diff --git a/src/gui/math3d/qvector2d.cpp b/src/gui/math3d/qvector2d.cpp index 7c02b5ad5d..c04f8b1cbf 100644 --- a/src/gui/math3d/qvector2d.cpp +++ b/src/gui/math3d/qvector2d.cpp @@ -49,6 +49,39 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_VECTOR2D +Q_STATIC_ASSERT_X(std::is_standard_layout::value, "QVector2D is supposed to be standard layout"); +Q_STATIC_ASSERT_X(sizeof(QVector2D) == sizeof(float) * 2, "QVector2D is not supposed to have padding at the end"); + +// QVector2D used to be defined as class QVector2D { float x, y; };, +// now instead it is defined as classs QVector2D { float v[2]; };. +// Check that binary compatibility is preserved. +// ### Qt 6: remove all of these checks. + +namespace { + +struct QVector2DOld +{ + float x, y; +}; + +struct QVector2DNew +{ + float v[2]; +}; + +Q_STATIC_ASSERT_X(std::is_standard_layout::value, "Binary compatibility break in QVector2D"); +Q_STATIC_ASSERT_X(std::is_standard_layout::value, "Binary compatibility break in QVector2D"); + +Q_STATIC_ASSERT_X(sizeof(QVector2DOld) == sizeof(QVector2DNew), "Binary compatibility break in QVector2D"); + +// requires a constexpr offsetof +#if !defined(Q_CC_MSVC) || (_MSC_VER >= 1910) +Q_STATIC_ASSERT_X(offsetof(QVector2DOld, x) == offsetof(QVector2DNew, v) + sizeof(QVector2DNew::v[0]) * 0, "Binary compatibility break in QVector2D"); +Q_STATIC_ASSERT_X(offsetof(QVector2DOld, y) == offsetof(QVector2DNew, v) + sizeof(QVector2DNew::v[0]) * 1, "Binary compatibility break in QVector2D"); +#endif + +} // anonymous namespace + /*! \class QVector2D \brief The QVector2D class represents a vector or vertex in 2D space. @@ -105,8 +138,8 @@ QT_BEGIN_NAMESPACE */ QVector2D::QVector2D(const QVector3D& vector) { - xp = vector.xp; - yp = vector.yp; + v[0] = vector.v[0]; + v[1] = vector.v[1]; } #endif @@ -121,8 +154,8 @@ QVector2D::QVector2D(const QVector3D& vector) */ QVector2D::QVector2D(const QVector4D& vector) { - xp = vector.xp; - yp = vector.yp; + v[0] = vector.v[0]; + v[1] = vector.v[1]; } #endif @@ -193,8 +226,8 @@ QVector2D::QVector2D(const QVector4D& vector) float QVector2D::length() const { // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp); + double len = double(v[0]) * double(v[0]) + + double(v[1]) * double(v[1]); return float(std::sqrt(len)); } @@ -206,7 +239,7 @@ float QVector2D::length() const */ float QVector2D::lengthSquared() const { - return xp * xp + yp * yp; + return v[0] * v[0] + v[1] * v[1]; } /*! @@ -221,13 +254,13 @@ float QVector2D::lengthSquared() const QVector2D QVector2D::normalized() const { // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp); + double len = double(v[0]) * double(v[0]) + + double(v[1]) * double(v[1]); if (qFuzzyIsNull(len - 1.0f)) { return *this; } else if (!qFuzzyIsNull(len)) { double sqrtLen = std::sqrt(len); - return QVector2D(float(double(xp) / sqrtLen), float(double(yp) / sqrtLen)); + return QVector2D(float(double(v[0]) / sqrtLen), float(double(v[1]) / sqrtLen)); } else { return QVector2D(); } @@ -242,15 +275,15 @@ QVector2D QVector2D::normalized() const void QVector2D::normalize() { // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp); + double len = double(v[0]) * double(v[0]) + + double(v[1]) * double(v[1]); if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len)) return; len = std::sqrt(len); - xp = float(double(xp) / len); - yp = float(double(yp) / len); + v[0] = float(double(v[0]) / len); + v[1] = float(double(v[1]) / len); } /*! @@ -344,7 +377,7 @@ float QVector2D::distanceToLine */ float QVector2D::dotProduct(const QVector2D& v1, const QVector2D& v2) { - return v1.xp * v2.xp + v1.yp * v2.yp; + return v1.v[0] * v2.v[0] + v1.v[1] * v2.v[1]; } /*! @@ -458,7 +491,7 @@ float QVector2D::dotProduct(const QVector2D& v1, const QVector2D& v2) */ QVector3D QVector2D::toVector3D() const { - return QVector3D(xp, yp, 0.0f); + return QVector3D(v[0], v[1], 0.0f); } #endif @@ -472,7 +505,7 @@ QVector3D QVector2D::toVector3D() const */ QVector4D QVector2D::toVector4D() const { - return QVector4D(xp, yp, 0.0f, 0.0f); + return QVector4D(v[0], v[1], 0.0f, 0.0f); } #endif diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h index 2af5132665..88d8bc199e 100644 --- a/src/gui/math3d/qvector2d.h +++ b/src/gui/math3d/qvector2d.h @@ -123,7 +123,7 @@ public: operator QVariant() const; private: - float xp, yp; + float v[2]; friend class QVector3D; friend class QVector4D; @@ -131,76 +131,76 @@ private: Q_DECLARE_TYPEINFO(QVector2D, Q_PRIMITIVE_TYPE); -Q_DECL_CONSTEXPR inline QVector2D::QVector2D() : xp(0.0f), yp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector2D::QVector2D() : v{0.0f, 0.0f} {} -Q_DECL_CONSTEXPR inline QVector2D::QVector2D(float xpos, float ypos) : xp(xpos), yp(ypos) {} +Q_DECL_CONSTEXPR inline QVector2D::QVector2D(float xpos, float ypos) : v{xpos, ypos} {} -Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPoint& point) : xp(point.x()), yp(point.y()) {} +Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPoint& point) : v{float(point.x()), float(point.y())} {} -Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPointF& point) : xp(float(point.x())), yp(float(point.y())) {} +Q_DECL_CONSTEXPR inline QVector2D::QVector2D(const QPointF& point) : v{float(point.x()), float(point.y())} {} inline bool QVector2D::isNull() const { - return qIsNull(xp) && qIsNull(yp); + return qIsNull(v[0]) && qIsNull(v[1]); } -Q_DECL_CONSTEXPR inline float QVector2D::x() const { return xp; } -Q_DECL_CONSTEXPR inline float QVector2D::y() const { return yp; } +Q_DECL_CONSTEXPR inline float QVector2D::x() const { return v[0]; } +Q_DECL_CONSTEXPR inline float QVector2D::y() const { return v[1]; } -inline void QVector2D::setX(float aX) { xp = aX; } -inline void QVector2D::setY(float aY) { yp = aY; } +inline void QVector2D::setX(float aX) { v[0] = aX; } +inline void QVector2D::setY(float aY) { v[1] = aY; } inline float &QVector2D::operator[](int i) { Q_ASSERT(uint(i) < 2u); - return *(&xp + i); + return v[i]; } inline float QVector2D::operator[](int i) const { Q_ASSERT(uint(i) < 2u); - return *(&xp + i); + return v[i]; } inline QVector2D &QVector2D::operator+=(const QVector2D &vector) { - xp += vector.xp; - yp += vector.yp; + v[0] += vector.v[0]; + v[1] += vector.v[1]; return *this; } inline QVector2D &QVector2D::operator-=(const QVector2D &vector) { - xp -= vector.xp; - yp -= vector.yp; + v[0] -= vector.v[0]; + v[1] -= vector.v[1]; return *this; } inline QVector2D &QVector2D::operator*=(float factor) { - xp *= factor; - yp *= factor; + v[0] *= factor; + v[1] *= factor; return *this; } inline QVector2D &QVector2D::operator*=(const QVector2D &vector) { - xp *= vector.xp; - yp *= vector.yp; + v[0] *= vector.v[0]; + v[1] *= vector.v[1]; return *this; } inline QVector2D &QVector2D::operator/=(float divisor) { - xp /= divisor; - yp /= divisor; + v[0] /= divisor; + v[1] /= divisor; return *this; } inline QVector2D &QVector2D::operator/=(const QVector2D &vector) { - xp /= vector.xp; - yp /= vector.yp; + v[0] /= vector.v[0]; + v[1] /= vector.v[1]; return *this; } @@ -209,68 +209,68 @@ QT_WARNING_DISABLE_CLANG("-Wfloat-equal") QT_WARNING_DISABLE_GCC("-Wfloat-equal") Q_DECL_CONSTEXPR inline bool operator==(const QVector2D &v1, const QVector2D &v2) { - return v1.xp == v2.xp && v1.yp == v2.yp; + return v1.v[0] == v2.v[0] && v1.v[1] == v2.v[1]; } Q_DECL_CONSTEXPR inline bool operator!=(const QVector2D &v1, const QVector2D &v2) { - return v1.xp != v2.xp || v1.yp != v2.yp; + return v1.v[0] != v2.v[0] || v1.v[1] != v2.v[1]; } QT_WARNING_POP Q_DECL_CONSTEXPR inline const QVector2D operator+(const QVector2D &v1, const QVector2D &v2) { - return QVector2D(v1.xp + v2.xp, v1.yp + v2.yp); + return QVector2D(v1.v[0] + v2.v[0], v1.v[1] + v2.v[1]); } Q_DECL_CONSTEXPR inline const QVector2D operator-(const QVector2D &v1, const QVector2D &v2) { - return QVector2D(v1.xp - v2.xp, v1.yp - v2.yp); + return QVector2D(v1.v[0] - v2.v[0], v1.v[1] - v2.v[1]); } Q_DECL_CONSTEXPR inline const QVector2D operator*(float factor, const QVector2D &vector) { - return QVector2D(vector.xp * factor, vector.yp * factor); + return QVector2D(vector.v[0] * factor, vector.v[1] * factor); } Q_DECL_CONSTEXPR inline const QVector2D operator*(const QVector2D &vector, float factor) { - return QVector2D(vector.xp * factor, vector.yp * factor); + return QVector2D(vector.v[0] * factor, vector.v[1] * factor); } Q_DECL_CONSTEXPR inline const QVector2D operator*(const QVector2D &v1, const QVector2D &v2) { - return QVector2D(v1.xp * v2.xp, v1.yp * v2.yp); + return QVector2D(v1.v[0] * v2.v[0], v1.v[1] * v2.v[1]); } Q_DECL_CONSTEXPR inline const QVector2D operator-(const QVector2D &vector) { - return QVector2D(-vector.xp, -vector.yp); + return QVector2D(-vector.v[0], -vector.v[1]); } Q_DECL_CONSTEXPR inline const QVector2D operator/(const QVector2D &vector, float divisor) { - return QVector2D(vector.xp / divisor, vector.yp / divisor); + return QVector2D(vector.v[0] / divisor, vector.v[1] / divisor); } Q_DECL_CONSTEXPR inline const QVector2D operator/(const QVector2D &vector, const QVector2D &divisor) { - return QVector2D(vector.xp / divisor.xp, vector.yp / divisor.yp); + return QVector2D(vector.v[0] / divisor.v[0], vector.v[1] / divisor.v[1]); } Q_DECL_CONSTEXPR inline bool qFuzzyCompare(const QVector2D& v1, const QVector2D& v2) { - return qFuzzyCompare(v1.xp, v2.xp) && qFuzzyCompare(v1.yp, v2.yp); + return qFuzzyCompare(v1.v[0], v2.v[0]) && qFuzzyCompare(v1.v[1], v2.v[1]); } Q_DECL_CONSTEXPR inline QPoint QVector2D::toPoint() const { - return QPoint(qRound(xp), qRound(yp)); + return QPoint(qRound(v[0]), qRound(v[1])); } Q_DECL_CONSTEXPR inline QPointF QVector2D::toPointF() const { - return QPointF(qreal(xp), qreal(yp)); + return QPointF(qreal(v[0]), qreal(v[1])); } #ifndef QT_NO_DEBUG_STREAM diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp index 8aaf1b0eaa..12a7902272 100644 --- a/src/gui/math3d/qvector3d.cpp +++ b/src/gui/math3d/qvector3d.cpp @@ -51,6 +51,41 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_VECTOR3D +Q_STATIC_ASSERT_X(std::is_standard_layout::value, "QVector3D is supposed to be standard layout"); +Q_STATIC_ASSERT_X(sizeof(QVector3D) == sizeof(float) * 3, "QVector3D is not supposed to have padding at the end"); + +// QVector3D used to be defined as class QVector3D { float x, y, z; };, +// now instead it is defined as classs QVector3D { float v[3]; };. +// Check that binary compatibility is preserved. +// ### Qt 6: remove all of these checks. + +namespace { + +struct QVector3DOld +{ + float x, y, z; +}; + +struct QVector3DNew +{ + float v[3]; +}; + +Q_STATIC_ASSERT_X(std::is_standard_layout::value, "Binary compatibility break in QVector3D"); +Q_STATIC_ASSERT_X(std::is_standard_layout::value, "Binary compatibility break in QVector3D"); + +Q_STATIC_ASSERT_X(sizeof(QVector3DOld) == sizeof(QVector3DNew), "Binary compatibility break in QVector3D"); + +// requires a constexpr offsetof +#if !defined(Q_CC_MSVC) || (_MSC_VER >= 1910) +Q_STATIC_ASSERT_X(offsetof(QVector3DOld, x) == offsetof(QVector3DNew, v) + sizeof(QVector3DNew::v[0]) * 0, "Binary compatibility break in QVector3D"); +Q_STATIC_ASSERT_X(offsetof(QVector3DOld, y) == offsetof(QVector3DNew, v) + sizeof(QVector3DNew::v[0]) * 1, "Binary compatibility break in QVector3D"); +Q_STATIC_ASSERT_X(offsetof(QVector3DOld, z) == offsetof(QVector3DNew, v) + sizeof(QVector3DNew::v[0]) * 2, "Binary compatibility break in QVector3D"); +#endif + + +} // anonymous namespace + /*! \class QVector3D \brief The QVector3D class represents a vector or vertex in 3D space. @@ -112,9 +147,9 @@ QT_BEGIN_NAMESPACE */ QVector3D::QVector3D(const QVector2D& vector) { - xp = vector.xp; - yp = vector.yp; - zp = 0.0f; + v[0] = vector.v[0]; + v[1] = vector.v[1]; + v[2] = 0.0f; } /*! @@ -125,9 +160,9 @@ QVector3D::QVector3D(const QVector2D& vector) */ QVector3D::QVector3D(const QVector2D& vector, float zpos) { - xp = vector.xp; - yp = vector.yp; - zp = zpos; + v[0] = vector.v[0]; + v[1] = vector.v[1]; + v[2] = zpos; } #endif @@ -142,9 +177,9 @@ QVector3D::QVector3D(const QVector2D& vector, float zpos) */ QVector3D::QVector3D(const QVector4D& vector) { - xp = vector.xp; - yp = vector.yp; - zp = vector.zp; + v[0] = vector.v[0]; + v[1] = vector.v[1]; + v[2] = vector.v[2]; } #endif @@ -235,16 +270,16 @@ QVector3D::QVector3D(const QVector4D& vector) QVector3D QVector3D::normalized() const { // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp) + - double(zp) * double(zp); + double len = double(v[0]) * double(v[0]) + + double(v[1]) * double(v[1]) + + double(v[2]) * double(v[2]); if (qFuzzyIsNull(len - 1.0f)) { return *this; } else if (!qFuzzyIsNull(len)) { double sqrtLen = std::sqrt(len); - return QVector3D(float(double(xp) / sqrtLen), - float(double(yp) / sqrtLen), - float(double(zp) / sqrtLen)); + return QVector3D(float(double(v[0]) / sqrtLen), + float(double(v[1]) / sqrtLen), + float(double(v[2]) / sqrtLen)); } else { return QVector3D(); } @@ -259,17 +294,17 @@ QVector3D QVector3D::normalized() const void QVector3D::normalize() { // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp) + - double(zp) * double(zp); + double len = double(v[0]) * double(v[0]) + + double(v[1]) * double(v[1]) + + double(v[2]) * double(v[2]); if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len)) return; len = std::sqrt(len); - xp = float(double(xp) / len); - yp = float(double(yp) / len); - zp = float(double(zp) / len); + v[0] = float(double(v[0]) / len); + v[1] = float(double(v[1]) / len); + v[2] = float(double(v[2]) / len); } /*! @@ -336,7 +371,7 @@ void QVector3D::normalize() */ float QVector3D::dotProduct(const QVector3D& v1, const QVector3D& v2) { - return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp; + return v1.v[0] * v2.v[0] + v1.v[1] * v2.v[1] + v1.v[2] * v2.v[2]; } /*! @@ -347,9 +382,9 @@ float QVector3D::dotProduct(const QVector3D& v1, const QVector3D& v2) */ QVector3D QVector3D::crossProduct(const QVector3D& v1, const QVector3D& v2) { - return QVector3D(v1.yp * v2.zp - v1.zp * v2.yp, - v1.zp * v2.xp - v1.xp * v2.zp, - v1.xp * v2.yp - v1.yp * v2.xp); + return QVector3D(v1.v[1] * v2.v[2] - v1.v[2] * v2.v[1], + v1.v[2] * v2.v[0] - v1.v[0] * v2.v[2], + v1.v[0] * v2.v[1] - v1.v[1] * v2.v[0]); } /*! @@ -629,7 +664,7 @@ float QVector3D::distanceToLine */ QVector2D QVector3D::toVector2D() const { - return QVector2D(xp, yp); + return QVector2D(v[0], v[1]); } #endif @@ -643,7 +678,7 @@ QVector2D QVector3D::toVector2D() const */ QVector4D QVector3D::toVector4D() const { - return QVector4D(xp, yp, zp, 0.0f); + return QVector4D(v[0], v[1], v[2], 0.0f); } #endif @@ -682,9 +717,9 @@ QVector3D::operator QVariant() const float QVector3D::length() const { // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp) + - double(zp) * double(zp); + double len = double(v[0]) * double(v[0]) + + double(v[1]) * double(v[1]) + + double(v[2]) * double(v[2]); return float(std::sqrt(len)); } @@ -696,7 +731,7 @@ float QVector3D::length() const */ float QVector3D::lengthSquared() const { - return xp * xp + yp * yp + zp * zp; + return v[0] * v[0] + v[1] * v[1] + v[2] * v[2]; } #ifndef QT_NO_DEBUG_STREAM diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h index f3e8c976b7..1b49f3e7b9 100644 --- a/src/gui/math3d/qvector3d.h +++ b/src/gui/math3d/qvector3d.h @@ -59,7 +59,7 @@ class Q_GUI_EXPORT QVector3D public: Q_DECL_CONSTEXPR QVector3D(); explicit QVector3D(Qt::Initialization) {} - Q_DECL_CONSTEXPR QVector3D(float xpos, float ypos, float zpos) : xp(xpos), yp(ypos), zp(zpos) {} + Q_DECL_CONSTEXPR QVector3D(float xpos, float ypos, float zpos) : v{xpos, ypos, zpos} {} Q_DECL_CONSTEXPR explicit QVector3D(const QPoint& point); Q_DECL_CONSTEXPR explicit QVector3D(const QPointF& point); @@ -138,7 +138,7 @@ public: operator QVariant() const; private: - float xp, yp, zp; + float v[3]; friend class QVector2D; friend class QVector4D; @@ -150,82 +150,82 @@ private: Q_DECLARE_TYPEINFO(QVector3D, Q_PRIMITIVE_TYPE); -Q_DECL_CONSTEXPR inline QVector3D::QVector3D() : xp(0.0f), yp(0.0f), zp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector3D::QVector3D() : v{0.0f, 0.0f, 0.0f} {} -Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPoint& point) : v{float(point.x()), float(point.y()), float(0.0f)} {} -Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPointF& point) : xp(float(point.x())), yp(float(point.y())), zp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector3D::QVector3D(const QPointF& point) : v{float(point.x()), float(point.y()), 0.0f} {} inline bool QVector3D::isNull() const { - return qIsNull(xp) && qIsNull(yp) && qIsNull(zp); + return qIsNull(v[0]) && qIsNull(v[1]) && qIsNull(v[2]); } -Q_DECL_CONSTEXPR inline float QVector3D::x() const { return xp; } -Q_DECL_CONSTEXPR inline float QVector3D::y() const { return yp; } -Q_DECL_CONSTEXPR inline float QVector3D::z() const { return zp; } +Q_DECL_CONSTEXPR inline float QVector3D::x() const { return v[0]; } +Q_DECL_CONSTEXPR inline float QVector3D::y() const { return v[1]; } +Q_DECL_CONSTEXPR inline float QVector3D::z() const { return v[2]; } -inline void QVector3D::setX(float aX) { xp = aX; } -inline void QVector3D::setY(float aY) { yp = aY; } -inline void QVector3D::setZ(float aZ) { zp = aZ; } +inline void QVector3D::setX(float aX) { v[0] = aX; } +inline void QVector3D::setY(float aY) { v[1] = aY; } +inline void QVector3D::setZ(float aZ) { v[2] = aZ; } inline float &QVector3D::operator[](int i) { Q_ASSERT(uint(i) < 3u); - return *(&xp + i); + return v[i]; } inline float QVector3D::operator[](int i) const { Q_ASSERT(uint(i) < 3u); - return *(&xp + i); + return v[i]; } inline QVector3D &QVector3D::operator+=(const QVector3D &vector) { - xp += vector.xp; - yp += vector.yp; - zp += vector.zp; + v[0] += vector.v[0]; + v[1] += vector.v[1]; + v[2] += vector.v[2]; return *this; } inline QVector3D &QVector3D::operator-=(const QVector3D &vector) { - xp -= vector.xp; - yp -= vector.yp; - zp -= vector.zp; + v[0] -= vector.v[0]; + v[1] -= vector.v[1]; + v[2] -= vector.v[2]; return *this; } inline QVector3D &QVector3D::operator*=(float factor) { - xp *= factor; - yp *= factor; - zp *= factor; + v[0] *= factor; + v[1] *= factor; + v[2] *= factor; return *this; } inline QVector3D &QVector3D::operator*=(const QVector3D& vector) { - xp *= vector.xp; - yp *= vector.yp; - zp *= vector.zp; + v[0] *= vector.v[0]; + v[1] *= vector.v[1]; + v[2] *= vector.v[2]; return *this; } inline QVector3D &QVector3D::operator/=(float divisor) { - xp /= divisor; - yp /= divisor; - zp /= divisor; + v[0] /= divisor; + v[1] /= divisor; + v[2] /= divisor; return *this; } inline QVector3D &QVector3D::operator/=(const QVector3D &vector) { - xp /= vector.xp; - yp /= vector.yp; - zp /= vector.zp; + v[0] /= vector.v[0]; + v[1] /= vector.v[1]; + v[2] /= vector.v[2]; return *this; } @@ -234,70 +234,70 @@ QT_WARNING_DISABLE_CLANG("-Wfloat-equal") QT_WARNING_DISABLE_GCC("-Wfloat-equal") Q_DECL_CONSTEXPR inline bool operator==(const QVector3D &v1, const QVector3D &v2) { - return v1.xp == v2.xp && v1.yp == v2.yp && v1.zp == v2.zp; + return v1.v[0] == v2.v[0] && v1.v[1] == v2.v[1] && v1.v[2] == v2.v[2]; } Q_DECL_CONSTEXPR inline bool operator!=(const QVector3D &v1, const QVector3D &v2) { - return v1.xp != v2.xp || v1.yp != v2.yp || v1.zp != v2.zp; + return v1.v[0] != v2.v[0] || v1.v[1] != v2.v[1] || v1.v[2] != v2.v[2]; } QT_WARNING_POP Q_DECL_CONSTEXPR inline const QVector3D operator+(const QVector3D &v1, const QVector3D &v2) { - return QVector3D(v1.xp + v2.xp, v1.yp + v2.yp, v1.zp + v2.zp); + return QVector3D(v1.v[0] + v2.v[0], v1.v[1] + v2.v[1], v1.v[2] + v2.v[2]); } Q_DECL_CONSTEXPR inline const QVector3D operator-(const QVector3D &v1, const QVector3D &v2) { - return QVector3D(v1.xp - v2.xp, v1.yp - v2.yp, v1.zp - v2.zp); + return QVector3D(v1.v[0] - v2.v[0], v1.v[1] - v2.v[1], v1.v[2] - v2.v[2]); } Q_DECL_CONSTEXPR inline const QVector3D operator*(float factor, const QVector3D &vector) { - return QVector3D(vector.xp * factor, vector.yp * factor, vector.zp * factor); + return QVector3D(vector.v[0] * factor, vector.v[1] * factor, vector.v[2] * factor); } Q_DECL_CONSTEXPR inline const QVector3D operator*(const QVector3D &vector, float factor) { - return QVector3D(vector.xp * factor, vector.yp * factor, vector.zp * factor); + return QVector3D(vector.v[0] * factor, vector.v[1] * factor, vector.v[2] * factor); } Q_DECL_CONSTEXPR inline const QVector3D operator*(const QVector3D &v1, const QVector3D& v2) { - return QVector3D(v1.xp * v2.xp, v1.yp * v2.yp, v1.zp * v2.zp); + return QVector3D(v1.v[0] * v2.v[0], v1.v[1] * v2.v[1], v1.v[2] * v2.v[2]); } Q_DECL_CONSTEXPR inline const QVector3D operator-(const QVector3D &vector) { - return QVector3D(-vector.xp, -vector.yp, -vector.zp); + return QVector3D(-vector.v[0], -vector.v[1], -vector.v[2]); } Q_DECL_CONSTEXPR inline const QVector3D operator/(const QVector3D &vector, float divisor) { - return QVector3D(vector.xp / divisor, vector.yp / divisor, vector.zp / divisor); + return QVector3D(vector.v[0] / divisor, vector.v[1] / divisor, vector.v[2] / divisor); } Q_DECL_CONSTEXPR inline const QVector3D operator/(const QVector3D &vector, const QVector3D &divisor) { - return QVector3D(vector.xp / divisor.xp, vector.yp / divisor.yp, vector.zp / divisor.zp); + return QVector3D(vector.v[0] / divisor.v[0], vector.v[1] / divisor.v[1], vector.v[2] / divisor.v[2]); } Q_DECL_CONSTEXPR inline bool qFuzzyCompare(const QVector3D& v1, const QVector3D& v2) { - return qFuzzyCompare(v1.xp, v2.xp) && - qFuzzyCompare(v1.yp, v2.yp) && - qFuzzyCompare(v1.zp, v2.zp); + return qFuzzyCompare(v1.v[0], v2.v[0]) && + qFuzzyCompare(v1.v[1], v2.v[1]) && + qFuzzyCompare(v1.v[2], v2.v[2]); } Q_DECL_CONSTEXPR inline QPoint QVector3D::toPoint() const { - return QPoint(qRound(xp), qRound(yp)); + return QPoint(qRound(v[0]), qRound(v[1])); } Q_DECL_CONSTEXPR inline QPointF QVector3D::toPointF() const { - return QPointF(qreal(xp), qreal(yp)); + return QPointF(qreal(v[0]), qreal(v[1])); } #ifndef QT_NO_DEBUG_STREAM diff --git a/src/gui/math3d/qvector4d.cpp b/src/gui/math3d/qvector4d.cpp index 331144ba33..3a68bd6cb7 100644 --- a/src/gui/math3d/qvector4d.cpp +++ b/src/gui/math3d/qvector4d.cpp @@ -49,6 +49,42 @@ QT_BEGIN_NAMESPACE #ifndef QT_NO_VECTOR4D +Q_STATIC_ASSERT_X(std::is_standard_layout::value, "QVector4D is supposed to be standard layout"); +Q_STATIC_ASSERT_X(sizeof(QVector4D) == sizeof(float) * 4, "QVector4D is not supposed to have padding at the end"); + +// QVector4D used to be defined as class QVector4D { float x, y, z, w; };, +// now instead it is defined as classs QVector4D { float v[4]; };. +// Check that binary compatibility is preserved. +// ### Qt 6: remove all of these checks. + +namespace { + +struct QVector4DOld +{ + float x, y, z, w; +}; + +struct QVector4DNew +{ + float v[4]; +}; + +Q_STATIC_ASSERT_X(std::is_standard_layout::value, "Binary compatibility break in QVector4D"); +Q_STATIC_ASSERT_X(std::is_standard_layout::value, "Binary compatibility break in QVector4D"); + +Q_STATIC_ASSERT_X(sizeof(QVector4DOld) == sizeof(QVector4DNew), "Binary compatibility break in QVector4D"); + +// requires a constexpr offsetof +#if !defined(Q_CC_MSVC) || (_MSC_VER >= 1910) +Q_STATIC_ASSERT_X(offsetof(QVector4DOld, x) == offsetof(QVector4DNew, v) + sizeof(QVector4DNew::v[0]) * 0, "Binary compatibility break in QVector4D"); +Q_STATIC_ASSERT_X(offsetof(QVector4DOld, y) == offsetof(QVector4DNew, v) + sizeof(QVector4DNew::v[0]) * 1, "Binary compatibility break in QVector4D"); +Q_STATIC_ASSERT_X(offsetof(QVector4DOld, z) == offsetof(QVector4DNew, v) + sizeof(QVector4DNew::v[0]) * 2, "Binary compatibility break in QVector4D"); +Q_STATIC_ASSERT_X(offsetof(QVector4DOld, w) == offsetof(QVector4DNew, v) + sizeof(QVector4DNew::v[0]) * 3, "Binary compatibility break in QVector4D"); +#endif + + +} // anonymous namespace + /*! \class QVector4D \brief The QVector4D class represents a vector or vertex in 4D space. @@ -106,10 +142,10 @@ QT_BEGIN_NAMESPACE */ QVector4D::QVector4D(const QVector2D& vector) { - xp = vector.xp; - yp = vector.yp; - zp = 0.0f; - wp = 0.0f; + v[0] = vector.v[0]; + v[1] = vector.v[1]; + v[2] = 0.0f; + v[3] = 0.0f; } /*! @@ -120,10 +156,10 @@ QVector4D::QVector4D(const QVector2D& vector) */ QVector4D::QVector4D(const QVector2D& vector, float zpos, float wpos) { - xp = vector.xp; - yp = vector.yp; - zp = zpos; - wp = wpos; + v[0] = vector.v[0]; + v[1] = vector.v[1]; + v[2] = zpos; + v[3] = wpos; } #endif @@ -138,10 +174,10 @@ QVector4D::QVector4D(const QVector2D& vector, float zpos, float wpos) */ QVector4D::QVector4D(const QVector3D& vector) { - xp = vector.xp; - yp = vector.yp; - zp = vector.zp; - wp = 0.0f; + v[0] = vector.v[0]; + v[1] = vector.v[1]; + v[2] = vector.v[2]; + v[3] = 0.0f; } /*! @@ -152,10 +188,10 @@ QVector4D::QVector4D(const QVector3D& vector) */ QVector4D::QVector4D(const QVector3D& vector, float wpos) { - xp = vector.xp; - yp = vector.yp; - zp = vector.zp; - wp = wpos; + v[0] = vector.v[0]; + v[1] = vector.v[1]; + v[2] = vector.v[2]; + v[3] = wpos; } #endif @@ -258,10 +294,10 @@ QVector4D::QVector4D(const QVector3D& vector, float wpos) float QVector4D::length() const { // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp) + - double(zp) * double(zp) + - double(wp) * double(wp); + double len = double(v[0]) * double(v[0]) + + double(v[1]) * double(v[1]) + + double(v[2]) * double(v[2]) + + double(v[3]) * double(v[3]); return float(std::sqrt(len)); } @@ -273,7 +309,7 @@ float QVector4D::length() const */ float QVector4D::lengthSquared() const { - return xp * xp + yp * yp + zp * zp + wp * wp; + return v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]; } /*! @@ -288,18 +324,18 @@ float QVector4D::lengthSquared() const QVector4D QVector4D::normalized() const { // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp) + - double(zp) * double(zp) + - double(wp) * double(wp); + double len = double(v[0]) * double(v[0]) + + double(v[1]) * double(v[1]) + + double(v[2]) * double(v[2]) + + double(v[3]) * double(v[3]); if (qFuzzyIsNull(len - 1.0f)) { return *this; } else if (!qFuzzyIsNull(len)) { double sqrtLen = std::sqrt(len); - return QVector4D(float(double(xp) / sqrtLen), - float(double(yp) / sqrtLen), - float(double(zp) / sqrtLen), - float(double(wp) / sqrtLen)); + return QVector4D(float(double(v[0]) / sqrtLen), + float(double(v[1]) / sqrtLen), + float(double(v[2]) / sqrtLen), + float(double(v[3]) / sqrtLen)); } else { return QVector4D(); } @@ -314,19 +350,19 @@ QVector4D QVector4D::normalized() const void QVector4D::normalize() { // Need some extra precision if the length is very small. - double len = double(xp) * double(xp) + - double(yp) * double(yp) + - double(zp) * double(zp) + - double(wp) * double(wp); + double len = double(v[0]) * double(v[0]) + + double(v[1]) * double(v[1]) + + double(v[2]) * double(v[2]) + + double(v[3]) * double(v[3]); if (qFuzzyIsNull(len - 1.0f) || qFuzzyIsNull(len)) return; len = std::sqrt(len); - xp = float(double(xp) / len); - yp = float(double(yp) / len); - zp = float(double(zp) / len); - wp = float(double(wp) / len); + v[0] = float(double(v[0]) / len); + v[1] = float(double(v[1]) / len); + v[2] = float(double(v[2]) / len); + v[3] = float(double(v[3]) / len); } /*! @@ -387,7 +423,7 @@ void QVector4D::normalize() */ float QVector4D::dotProduct(const QVector4D& v1, const QVector4D& v2) { - return v1.xp * v2.xp + v1.yp * v2.yp + v1.zp * v2.zp + v1.wp * v2.wp; + return v1.v[0] * v2.v[0] + v1.v[1] * v2.v[1] + v1.v[2] * v2.v[2] + v1.v[3] * v2.v[3]; } /*! @@ -503,7 +539,7 @@ float QVector4D::dotProduct(const QVector4D& v1, const QVector4D& v2) */ QVector2D QVector4D::toVector2D() const { - return QVector2D(xp, yp); + return QVector2D(v[0], v[1]); } /*! @@ -515,9 +551,9 @@ QVector2D QVector4D::toVector2D() const */ QVector2D QVector4D::toVector2DAffine() const { - if (qIsNull(wp)) + if (qIsNull(v[3])) return QVector2D(); - return QVector2D(xp / wp, yp / wp); + return QVector2D(v[0] / v[3], v[1] / v[3]); } #endif @@ -531,7 +567,7 @@ QVector2D QVector4D::toVector2DAffine() const */ QVector3D QVector4D::toVector3D() const { - return QVector3D(xp, yp, zp); + return QVector3D(v[0], v[1], v[2]); } /*! @@ -542,9 +578,9 @@ QVector3D QVector4D::toVector3D() const */ QVector3D QVector4D::toVector3DAffine() const { - if (qIsNull(wp)) + if (qIsNull(v[3])) return QVector3D(); - return QVector3D(xp / wp, yp / wp, zp / wp); + return QVector3D(v[0] / v[3], v[1] / v[3], v[2] / v[3]); } #endif diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h index 3f14b41e8e..08cb423484 100644 --- a/src/gui/math3d/qvector4d.h +++ b/src/gui/math3d/qvector4d.h @@ -128,7 +128,7 @@ public: operator QVariant() const; private: - float xp, yp, zp, wp; + float v[4]; friend class QVector2D; friend class QVector3D; @@ -140,92 +140,92 @@ private: Q_DECLARE_TYPEINFO(QVector4D, Q_PRIMITIVE_TYPE); -Q_DECL_CONSTEXPR inline QVector4D::QVector4D() : xp(0.0f), yp(0.0f), zp(0.0f), wp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector4D::QVector4D() : v{0.0f, 0.0f, 0.0f, 0.0f} {} -Q_DECL_CONSTEXPR inline QVector4D::QVector4D(float xpos, float ypos, float zpos, float wpos) : xp(xpos), yp(ypos), zp(zpos), wp(wpos) {} +Q_DECL_CONSTEXPR inline QVector4D::QVector4D(float xpos, float ypos, float zpos, float wpos) : v{xpos, ypos, zpos, wpos} {} -Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPoint& point) : xp(point.x()), yp(point.y()), zp(0.0f), wp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPoint& point) : v{float(point.x()), float(point.y()), 0.0f, 0.0f} {} -Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPointF& point) : xp(float(point.x())), yp(float(point.y())), zp(0.0f), wp(0.0f) {} +Q_DECL_CONSTEXPR inline QVector4D::QVector4D(const QPointF& point) : v{float(point.x()), float(point.y()), 0.0f, 0.0f} {} inline bool QVector4D::isNull() const { - return qIsNull(xp) && qIsNull(yp) && qIsNull(zp) && qIsNull(wp); + return qIsNull(v[0]) && qIsNull(v[1]) && qIsNull(v[2]) && qIsNull(v[3]); } -Q_DECL_CONSTEXPR inline float QVector4D::x() const { return xp; } -Q_DECL_CONSTEXPR inline float QVector4D::y() const { return yp; } -Q_DECL_CONSTEXPR inline float QVector4D::z() const { return zp; } -Q_DECL_CONSTEXPR inline float QVector4D::w() const { return wp; } +Q_DECL_CONSTEXPR inline float QVector4D::x() const { return v[0]; } +Q_DECL_CONSTEXPR inline float QVector4D::y() const { return v[1]; } +Q_DECL_CONSTEXPR inline float QVector4D::z() const { return v[2]; } +Q_DECL_CONSTEXPR inline float QVector4D::w() const { return v[3]; } -inline void QVector4D::setX(float aX) { xp = aX; } -inline void QVector4D::setY(float aY) { yp = aY; } -inline void QVector4D::setZ(float aZ) { zp = aZ; } -inline void QVector4D::setW(float aW) { wp = aW; } +inline void QVector4D::setX(float aX) { v[0] = aX; } +inline void QVector4D::setY(float aY) { v[1] = aY; } +inline void QVector4D::setZ(float aZ) { v[2] = aZ; } +inline void QVector4D::setW(float aW) { v[3] = aW; } inline float &QVector4D::operator[](int i) { Q_ASSERT(uint(i) < 4u); - return *(&xp + i); + return v[i]; } inline float QVector4D::operator[](int i) const { Q_ASSERT(uint(i) < 4u); - return *(&xp + i); + return v[i]; } inline QVector4D &QVector4D::operator+=(const QVector4D &vector) { - xp += vector.xp; - yp += vector.yp; - zp += vector.zp; - wp += vector.wp; + v[0] += vector.v[0]; + v[1] += vector.v[1]; + v[2] += vector.v[2]; + v[3] += vector.v[3]; return *this; } inline QVector4D &QVector4D::operator-=(const QVector4D &vector) { - xp -= vector.xp; - yp -= vector.yp; - zp -= vector.zp; - wp -= vector.wp; + v[0] -= vector.v[0]; + v[1] -= vector.v[1]; + v[2] -= vector.v[2]; + v[3] -= vector.v[3]; return *this; } inline QVector4D &QVector4D::operator*=(float factor) { - xp *= factor; - yp *= factor; - zp *= factor; - wp *= factor; + v[0] *= factor; + v[1] *= factor; + v[2] *= factor; + v[3] *= factor; return *this; } inline QVector4D &QVector4D::operator*=(const QVector4D &vector) { - xp *= vector.xp; - yp *= vector.yp; - zp *= vector.zp; - wp *= vector.wp; + v[0] *= vector.v[0]; + v[1] *= vector.v[1]; + v[2] *= vector.v[2]; + v[3] *= vector.v[3]; return *this; } inline QVector4D &QVector4D::operator/=(float divisor) { - xp /= divisor; - yp /= divisor; - zp /= divisor; - wp /= divisor; + v[0] /= divisor; + v[1] /= divisor; + v[2] /= divisor; + v[3] /= divisor; return *this; } inline QVector4D &QVector4D::operator/=(const QVector4D &vector) { - xp /= vector.xp; - yp /= vector.yp; - zp /= vector.zp; - wp /= vector.wp; + v[0] /= vector.v[0]; + v[1] /= vector.v[1]; + v[2] /= vector.v[2]; + v[3] /= vector.v[3]; return *this; } @@ -234,71 +234,71 @@ QT_WARNING_DISABLE_CLANG("-Wfloat-equal") QT_WARNING_DISABLE_GCC("-Wfloat-equal") Q_DECL_CONSTEXPR inline bool operator==(const QVector4D &v1, const QVector4D &v2) { - return v1.xp == v2.xp && v1.yp == v2.yp && v1.zp == v2.zp && v1.wp == v2.wp; + return v1.v[0] == v2.v[0] && v1.v[1] == v2.v[1] && v1.v[2] == v2.v[2] && v1.v[3] == v2.v[3]; } Q_DECL_CONSTEXPR inline bool operator!=(const QVector4D &v1, const QVector4D &v2) { - return v1.xp != v2.xp || v1.yp != v2.yp || v1.zp != v2.zp || v1.wp != v2.wp; + return v1.v[0] != v2.v[0] || v1.v[1] != v2.v[1] || v1.v[2] != v2.v[2] || v1.v[3] != v2.v[3]; } QT_WARNING_POP Q_DECL_CONSTEXPR inline const QVector4D operator+(const QVector4D &v1, const QVector4D &v2) { - return QVector4D(v1.xp + v2.xp, v1.yp + v2.yp, v1.zp + v2.zp, v1.wp + v2.wp); + return QVector4D(v1.v[0] + v2.v[0], v1.v[1] + v2.v[1], v1.v[2] + v2.v[2], v1.v[3] + v2.v[3]); } Q_DECL_CONSTEXPR inline const QVector4D operator-(const QVector4D &v1, const QVector4D &v2) { - return QVector4D(v1.xp - v2.xp, v1.yp - v2.yp, v1.zp - v2.zp, v1.wp - v2.wp); + return QVector4D(v1.v[0] - v2.v[0], v1.v[1] - v2.v[1], v1.v[2] - v2.v[2], v1.v[3] - v2.v[3]); } Q_DECL_CONSTEXPR inline const QVector4D operator*(float factor, const QVector4D &vector) { - return QVector4D(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.wp * factor); + return QVector4D(vector.v[0] * factor, vector.v[1] * factor, vector.v[2] * factor, vector.v[3] * factor); } Q_DECL_CONSTEXPR inline const QVector4D operator*(const QVector4D &vector, float factor) { - return QVector4D(vector.xp * factor, vector.yp * factor, vector.zp * factor, vector.wp * factor); + return QVector4D(vector.v[0] * factor, vector.v[1] * factor, vector.v[2] * factor, vector.v[3] * factor); } Q_DECL_CONSTEXPR inline const QVector4D operator*(const QVector4D &v1, const QVector4D& v2) { - return QVector4D(v1.xp * v2.xp, v1.yp * v2.yp, v1.zp * v2.zp, v1.wp * v2.wp); + return QVector4D(v1.v[0] * v2.v[0], v1.v[1] * v2.v[1], v1.v[2] * v2.v[2], v1.v[3] * v2.v[3]); } Q_DECL_CONSTEXPR inline const QVector4D operator-(const QVector4D &vector) { - return QVector4D(-vector.xp, -vector.yp, -vector.zp, -vector.wp); + return QVector4D(-vector.v[0], -vector.v[1], -vector.v[2], -vector.v[3]); } Q_DECL_CONSTEXPR inline const QVector4D operator/(const QVector4D &vector, float divisor) { - return QVector4D(vector.xp / divisor, vector.yp / divisor, vector.zp / divisor, vector.wp / divisor); + return QVector4D(vector.v[0] / divisor, vector.v[1] / divisor, vector.v[2] / divisor, vector.v[3] / divisor); } Q_DECL_CONSTEXPR inline const QVector4D operator/(const QVector4D &vector, const QVector4D &divisor) { - return QVector4D(vector.xp / divisor.xp, vector.yp / divisor.yp, vector.zp / divisor.zp, vector.wp / divisor.wp); + return QVector4D(vector.v[0] / divisor.v[0], vector.v[1] / divisor.v[1], vector.v[2] / divisor.v[2], vector.v[3] / divisor.v[3]); } Q_DECL_CONSTEXPR inline bool qFuzzyCompare(const QVector4D& v1, const QVector4D& v2) { - return qFuzzyCompare(v1.xp, v2.xp) && - qFuzzyCompare(v1.yp, v2.yp) && - qFuzzyCompare(v1.zp, v2.zp) && - qFuzzyCompare(v1.wp, v2.wp); + return qFuzzyCompare(v1.v[0], v2.v[0]) && + qFuzzyCompare(v1.v[1], v2.v[1]) && + qFuzzyCompare(v1.v[2], v2.v[2]) && + qFuzzyCompare(v1.v[3], v2.v[3]); } Q_DECL_CONSTEXPR inline QPoint QVector4D::toPoint() const { - return QPoint(qRound(xp), qRound(yp)); + return QPoint(qRound(v[0]), qRound(v[1])); } Q_DECL_CONSTEXPR inline QPointF QVector4D::toPointF() const { - return QPointF(qreal(xp), qreal(yp)); + return QPointF(qreal(v[0]), qreal(v[1])); } #ifndef QT_NO_DEBUG_STREAM