summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/sub-attaq/submarine.cpp2
-rw-r--r--src/gui/animation/qguivariantanimation.cpp24
-rw-r--r--src/gui/graphicsview/qgraphicsitem_p.h11
-rw-r--r--src/gui/graphicsview/qgraphicstransform.cpp216
-rw-r--r--src/gui/graphicsview/qgraphicstransform.h26
-rw-r--r--src/gui/math3d/qmatrix4x4.cpp62
-rw-r--r--src/gui/math3d/qmatrix4x4.h5
-rw-r--r--src/gui/math3d/qquaternion.cpp9
-rw-r--r--src/gui/math3d/qquaternion.h3
-rw-r--r--src/gui/math3d/qvector2d.cpp9
-rw-r--r--src/gui/math3d/qvector2d.h3
-rw-r--r--src/gui/math3d/qvector3d.cpp9
-rw-r--r--src/gui/math3d/qvector3d.h2
-rw-r--r--src/gui/math3d/qvector4d.cpp9
-rw-r--r--src/gui/math3d/qvector4d.h2
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp7
-rw-r--r--src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp16
-rw-r--r--tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp141
-rw-r--r--tests/benchmarks/qmatrix4x4/tst_qmatrix4x4.cpp411
19 files changed, 783 insertions, 184 deletions
diff --git a/demos/sub-attaq/submarine.cpp b/demos/sub-attaq/submarine.cpp
index 383005d..42a681d 100644
--- a/demos/sub-attaq/submarine.cpp
+++ b/demos/sub-attaq/submarine.cpp
@@ -113,7 +113,7 @@ SubMarine::SubMarine(int type, const QString &name, int points, QGraphicsItem *
graphicsRotation = new QGraphicsRotation(this);
graphicsRotation->setAxis(QVector3D(0, 1, 0));
- graphicsRotation->setOrigin(QPointF(size().width()/2, size().height()/2));
+ graphicsRotation->setOrigin(QVector3D(size().width()/2, size().height()/2, 0));
QList<QGraphicsTransform *> r;
r.append(graphicsRotation);
setTransformations(r);
diff --git a/src/gui/animation/qguivariantanimation.cpp b/src/gui/animation/qguivariantanimation.cpp
index 9badc82..de9363c 100644
--- a/src/gui/animation/qguivariantanimation.cpp
+++ b/src/gui/animation/qguivariantanimation.cpp
@@ -45,6 +45,10 @@
#include <private/qvariantanimation_p.h>
#include <QtGui/qcolor.h>
+#include <QtGui/qvector2d.h>
+#include <QtGui/qvector3d.h>
+#include <QtGui/qvector4d.h>
+#include <QtGui/qquaternion.h>
QT_BEGIN_NAMESPACE
@@ -56,17 +60,35 @@ template<> Q_INLINE_TEMPLATE QColor _q_interpolate(const QColor &f,const QColor
_q_interpolate(f.alpha(), t.alpha(), progress));
}
+template<> Q_INLINE_TEMPLATE QQuaternion _q_interpolate(const QQuaternion &f,const QQuaternion &t, qreal progress)
+{
+ return QQuaternion::slerp(f, t, progress);
+}
+
static int qRegisterGuiGetInterpolator()
{
qRegisterAnimationInterpolator<QColor>(_q_interpolateVariant<QColor>);
+ qRegisterAnimationInterpolator<QVector2D>(_q_interpolateVariant<QVector2D>);
+ qRegisterAnimationInterpolator<QVector3D>(_q_interpolateVariant<QVector3D>);
+ qRegisterAnimationInterpolator<QVector4D>(_q_interpolateVariant<QVector4D>);
+ qRegisterAnimationInterpolator<QQuaternion>(_q_interpolateVariant<QQuaternion>);
return 1;
}
Q_CONSTRUCTOR_FUNCTION(qRegisterGuiGetInterpolator)
static int qUnregisterGuiGetInterpolator()
{
+ // casts required by Sun CC 5.5
qRegisterAnimationInterpolator<QColor>(
- (QVariant (*)(const QColor &, const QColor &, qreal))0); // cast required by Sun CC 5.5
+ (QVariant (*)(const QColor &, const QColor &, qreal))0);
+ qRegisterAnimationInterpolator<QVector2D>(
+ (QVariant (*)(const QVector2D &, const QVector2D &, qreal))0);
+ qRegisterAnimationInterpolator<QVector3D>(
+ (QVariant (*)(const QVector3D &, const QVector3D &, qreal))0);
+ qRegisterAnimationInterpolator<QVector4D>(
+ (QVariant (*)(const QVector4D &, const QVector4D &, qreal))0);
+ qRegisterAnimationInterpolator<QQuaternion>(
+ (QVariant (*)(const QQuaternion &, const QQuaternion &, qreal))0);
return 1;
}
diff --git a/src/gui/graphicsview/qgraphicsitem_p.h b/src/gui/graphicsview/qgraphicsitem_p.h
index ae7feb2..a41cab5 100644
--- a/src/gui/graphicsview/qgraphicsitem_p.h
+++ b/src/gui/graphicsview/qgraphicsitem_p.h
@@ -502,16 +502,17 @@ struct QGraphicsItemPrivate::TransformData
return transform * *postmultiplyTransform;
}
- QTransform x(transform);
+ QMatrix4x4 x(transform);
for (int i = 0; i < graphicsTransforms.size(); ++i)
graphicsTransforms.at(i)->applyTo(&x);
x.translate(xOrigin, yOrigin);
- x.rotate(rotation, Qt::ZAxis);
- x.scale(scale, scale);
+ x.rotate(rotation, 0, 0, 1);
+ x.scale(scale);
x.translate(-xOrigin, -yOrigin);
+ QTransform t = x.toTransform(); // project the 3D matrix back to 2D.
if (postmultiplyTransform)
- x *= *postmultiplyTransform;
- return x;
+ t *= *postmultiplyTransform;
+ return t;
}
};
diff --git a/src/gui/graphicsview/qgraphicstransform.cpp b/src/gui/graphicsview/qgraphicstransform.cpp
index 86f5b08..585e0f9 100644
--- a/src/gui/graphicsview/qgraphicstransform.cpp
+++ b/src/gui/graphicsview/qgraphicstransform.cpp
@@ -63,10 +63,17 @@
independent transformation. The resulting operation is then combined into a
single transform which is applied to QGraphicsItem.
+ Transformations are computed in true 3D space using QMatrix4x4.
+ When the transformation is applied to a QGraphicsItem, it will be
+ projected back to a 2D QTransform. When multiple QGraphicsTransform
+ objects are applied to a QGraphicsItem, all of the transformations
+ are computed in true 3D space, with the projection back to 2D
+ only occurring after the last QGraphicsTransform is applied.
+
If you want to create your own configurable transformation, you can create
a subclass of QGraphicsTransform (or any or the existing subclasses), and
reimplement the pure virtual applyTo() function, which takes a pointer to a
- QTransform. Each operation you would like to apply should be exposed as
+ QMatrix4x4. Each operation you would like to apply should be exposed as
properties (e.g., customTransform->setVerticalShear(2.5)). Inside you
reimplementation of applyTo(), you can modify the provided transform
respectively.
@@ -136,28 +143,13 @@ QGraphicsTransform::QGraphicsTransform(QGraphicsTransformPrivate &p, QObject *pa
}
/*!
- Applies this transformation to an identity transform, and returns the
- resulting transform.
-
- This is equivalent to passing an identity transform to applyTo().
-
- \sa applyTo()
-*/
-QTransform QGraphicsTransform::transform() const
-{
- QTransform t;
- applyTo(&t);
- return t;
-}
-
-/*!
- \fn void QGraphicsTransform::applyTo(QTransform *transform) const
+ \fn void QGraphicsTransform::applyTo(QMatrix4x4 *matrix) const
This pure virtual method has to be reimplemented in derived classes.
- It applies this transformation to \a transform.
+ It applies this transformation to \a matrix.
- \sa QGraphicsItem::transform()
+ \sa QGraphicsItem::transform(), QMatrix4x4::toTransform()
*/
/*!
@@ -189,11 +181,12 @@ void QGraphicsTransform::update()
relative to the parent as the rest of the item grows). By default the
origin is QPointF(0, 0).
- The two parameters xScale and yScale describe the scale factors to apply in
- horizontal and vertical direction. They can take on any value, including 0
- (to collapse the item to a point) or negativate value. A negative xScale
- value will mirror the item horizontally. A negative yScale value will flip
- the item vertically.
+ The parameters xScale, yScale, and zScale describe the scale factors to
+ apply in horizontal, vertical, and depth directions. They can take on any
+ value, including 0 (to collapse the item to a point) or negative value.
+ A negative xScale value will mirror the item horizontally. A negative yScale
+ value will flip the item vertically. A negative zScale will flip the
+ item end for end.
\sa QGraphicsTransform, QGraphicsItem::setScale(), QTransform::scale()
*/
@@ -202,10 +195,11 @@ class QGraphicsScalePrivate : public QGraphicsTransformPrivate
{
public:
QGraphicsScalePrivate()
- : xScale(1), yScale(1) {}
- QPointF origin;
+ : xScale(1), yScale(1), zScale(1) {}
+ QVector3D origin;
qreal xScale;
qreal yScale;
+ qreal zScale;
};
/*!
@@ -225,21 +219,23 @@ QGraphicsScale::~QGraphicsScale()
/*!
\property QGraphicsScale::origin
- \brief The QGraphicsScene class provides the origin of the scale.
+ \brief the origin of the scale in 3D space.
All scaling will be done relative to this point (i.e., this point
will stay fixed, relative to the parent, when the item is scaled).
- \sa xScale, yScale
+ \sa xScale, yScale, zScale
*/
-QPointF QGraphicsScale::origin() const
+QVector3D QGraphicsScale::origin() const
{
Q_D(const QGraphicsScale);
return d->origin;
}
-void QGraphicsScale::setOrigin(const QPointF &point)
+void QGraphicsScale::setOrigin(const QVector3D &point)
{
Q_D(QGraphicsScale);
+ if (d->origin == point)
+ return;
d->origin = point;
update();
emit originChanged();
@@ -254,7 +250,7 @@ void QGraphicsScale::setOrigin(const QPointF &point)
provide a negative value, the item will be mirrored horizontally around its
origin.
- \sa yScale, origin
+ \sa yScale, zScale, origin
*/
qreal QGraphicsScale::xScale() const
{
@@ -280,7 +276,7 @@ void QGraphicsScale::setXScale(qreal scale)
provide a negative value, the item will be flipped vertically around its
origin.
- \sa xScale, origin
+ \sa xScale, zScale, origin
*/
qreal QGraphicsScale::yScale() const
{
@@ -298,14 +294,40 @@ void QGraphicsScale::setYScale(qreal scale)
}
/*!
+ \property QGraphicsScale::zScale
+ \brief the depth scale factor.
+
+ The scale factor can be any real number; the default value is 1.0. If you
+ set the factor to 0.0, the item will be collapsed to a single point. If you
+ provide a negative value, the item will be flipped end for end around its
+ origin.
+
+ \sa xScale, yScale, origin
+*/
+qreal QGraphicsScale::zScale() const
+{
+ Q_D(const QGraphicsScale);
+ return d->zScale;
+}
+void QGraphicsScale::setZScale(qreal scale)
+{
+ Q_D(QGraphicsScale);
+ if (d->zScale == scale)
+ return;
+ d->zScale = scale;
+ update();
+ emit scaleChanged();
+}
+
+/*!
\reimp
*/
-void QGraphicsScale::applyTo(QTransform *transform) const
+void QGraphicsScale::applyTo(QMatrix4x4 *matrix) const
{
Q_D(const QGraphicsScale);
- transform->translate(d->origin.x(), d->origin.y());
- transform->scale(d->xScale, d->yScale);
- transform->translate(-d->origin.x(), -d->origin.y());
+ matrix->translate(d->origin);
+ matrix->scale(d->xScale, d->yScale, d->zScale);
+ matrix->translate(-d->origin);
}
/*!
@@ -319,10 +341,11 @@ void QGraphicsScale::applyTo(QTransform *transform) const
/*!
\fn QGraphicsScale::scaleChanged()
- This signal is emitted whenever the xScale or yScale of the object
- changes.
+ This signal is emitted whenever the xScale, yScale, or zScale
+ of the object changes.
\sa QGraphicsScale::xScale, QGraphicsScale::yScale
+ \sa QGraphicsScale::zScale
*/
/*!
@@ -359,20 +382,14 @@ void QGraphicsScale::applyTo(QTransform *transform) const
\sa QGraphicsTransform, QGraphicsItem::setRotation(), QTransform::rotate()
*/
-#define VECTOR_FOR_AXIS_X QVector3D(1, 0, 0)
-#define VECTOR_FOR_AXIS_Y QVector3D(0, 1, 0)
-#define VECTOR_FOR_AXIS_Z QVector3D(0, 0, 1)
-
-
class QGraphicsRotationPrivate : public QGraphicsTransformPrivate
{
public:
QGraphicsRotationPrivate()
- : angle(0), axis(VECTOR_FOR_AXIS_Z), simpleAxis(Qt::ZAxis) {}
- QPointF origin;
+ : angle(0), axis(0, 0, 1) {}
+ QVector3D origin;
qreal angle;
QVector3D axis;
- int simpleAxis;
};
/*!
@@ -392,21 +409,23 @@ QGraphicsRotation::~QGraphicsRotation()
/*!
\property QGraphicsRotation::origin
- \brief the origin of the rotation.
+ \brief the origin of the rotation in 3D space.
All rotations will be done relative to this point (i.e., this point
will stay fixed, relative to the parent, when the item is rotated).
\sa angle
*/
-QPointF QGraphicsRotation::origin() const
+QVector3D QGraphicsRotation::origin() const
{
Q_D(const QGraphicsRotation);
return d->origin;
}
-void QGraphicsRotation::setOrigin(const QPointF &point)
+void QGraphicsRotation::setOrigin(const QVector3D &point)
{
Q_D(QGraphicsRotation);
+ if (d->origin == point)
+ return;
d->origin = point;
update();
emit originChanged();
@@ -448,11 +467,11 @@ void QGraphicsRotation::setAngle(qreal angle)
*/
/*!
- \fn void QGraphicsRotation::angleChanged()
+ \fn void QGraphicsRotation::angleChanged()
- This signal is emitted whenever the angle has changed.
+ This signal is emitted whenever the angle has changed.
- \sa QGraphicsRotation::angle
+ \sa QGraphicsRotation::angle
*/
/*!
@@ -475,18 +494,9 @@ QVector3D QGraphicsRotation::axis() const
void QGraphicsRotation::setAxis(const QVector3D &axis)
{
Q_D(QGraphicsRotation);
- if (d->axis == axis)
+ if (d->axis == axis)
return;
- d->axis = axis;
- if (axis == VECTOR_FOR_AXIS_X) {
- d->simpleAxis = Qt::XAxis;
- } else if (axis == VECTOR_FOR_AXIS_Y) {
- d->simpleAxis = Qt::YAxis;
- } else if (axis == VECTOR_FOR_AXIS_Z) {
- d->simpleAxis = Qt::ZAxis;
- } else {
- d->simpleAxis = -1; // no predefined axis
- }
+ d->axis = axis;
update();
emit axisChanged();
}
@@ -495,90 +505,58 @@ void QGraphicsRotation::setAxis(const QVector3D &axis)
\fn void QGraphicsRotation::setAxis(Qt::Axis axis)
Convenience function to set the axis to \a axis.
-*/
+ Note: the Qt::YAxis rotation for QTransform is inverted from the
+ correct mathematical rotation in 3D space. The QGraphicsRotation
+ class implements a correct mathematical rotation. The following
+ two sequences of code will perform the same transformation:
+
+ \code
+ QTransform t;
+ t.rotate(45, Qt::YAxis);
+
+ QGraphicsRotation r;
+ r.setAxis(Qt::YAxis);
+ r.setAngle(-45);
+ \endcode
+*/
void QGraphicsRotation::setAxis(Qt::Axis axis)
{
switch (axis)
{
case Qt::XAxis:
- setAxis(VECTOR_FOR_AXIS_X);
+ setAxis(QVector3D(1, 0, 0));
break;
case Qt::YAxis:
- setAxis(VECTOR_FOR_AXIS_Y);
+ setAxis(QVector3D(0, 1, 0));
break;
case Qt::ZAxis:
- setAxis(VECTOR_FOR_AXIS_Z);
+ setAxis(QVector3D(0, 0, 1));
break;
}
}
-
-const qreal deg2rad = qreal(0.017453292519943295769); // pi/180
-static const qreal inv_dist_to_plane = 1. / 1024.;
-
/*!
\reimp
*/
-void QGraphicsRotation::applyTo(QTransform *t) const
+void QGraphicsRotation::applyTo(QMatrix4x4 *matrix) const
{
Q_D(const QGraphicsRotation);
- qreal a = d->angle;
-
- if (a == 0.)
- return;
-
- if (d->simpleAxis != -1) {
- //that's an optimization for simple axis
- t->translate(d->origin.x(), d->origin.y());
- t->rotate(a, Qt::Axis(d->simpleAxis));
- t->translate(-d->origin.x(), -d->origin.y());
- return;
- }
-
- qreal x = d->axis.x();
- qreal y = d->axis.y();
- qreal z = d->axis.z();
-
- if (x == 0. && y == 0 && z == 0)
+ if (d->angle == 0. || d->axis.isNull())
return;
- qreal c, s;
- if (a == 90. || a == -270.) {
- s = 1.;
- c = 0.;
- } else if (a == 270. || a == -90.) {
- s = -1.;
- c = 0.;
- } else if (a == 180.) {
- s = 0.;
- c = -1.;
- } else {
- qreal b = deg2rad*a;
- s = qSin(b);
- c = qCos(b);
- }
-
- qreal len = x * x + y * y + z * z;
- if (len != 1.) {
- len = 1. / qSqrt(len);
- x *= len;
- y *= len;
- z *= len;
- }
-
- t->translate(d->origin.x(), d->origin.y());
- *t = QTransform(x*x*(1-c)+c, x*y*(1-c)+z*s, x*z*(1-c)-y*s*inv_dist_to_plane,
- y*x*(1-c)-z*s, y*y*(1-c)+c, y*z*(1-c)-x*s*inv_dist_to_plane,
- 0, 0, 1) * *t;
- t->translate(-d->origin.x(), -d->origin.y());
+ matrix->translate(d->origin);
+ matrix->rotate(d->angle, d->axis.x(), d->axis.y(), d->axis.z());
+ matrix->translate(-d->origin);
}
/*!
\fn void QGraphicsRotation::axisChanged()
This signal is emitted whenever the axis of the object changes.
+
+ \sa QGraphicsRotation::axis
*/
#include "moc_qgraphicstransform.cpp"
diff --git a/src/gui/graphicsview/qgraphicstransform.h b/src/gui/graphicsview/qgraphicstransform.h
index 8ccc258..d6d5b79 100644
--- a/src/gui/graphicsview/qgraphicstransform.h
+++ b/src/gui/graphicsview/qgraphicstransform.h
@@ -43,8 +43,9 @@
#define QGRAPHICSTRANSFORM_H
#include <QtCore/QObject>
-#include <QtGui/QTransform>
#include <QtGui/QVector3D>
+#include <QtGui/QTransform>
+#include <QtGui/QMatrix4x4>
QT_BEGIN_HEADER
@@ -62,8 +63,7 @@ public:
QGraphicsTransform(QObject *parent = 0);
~QGraphicsTransform();
- QTransform transform() const;
- virtual void applyTo(QTransform *transform) const = 0;
+ virtual void applyTo(QMatrix4x4 *matrix) const = 0;
protected Q_SLOTS:
void update();
@@ -83,15 +83,16 @@ class Q_GUI_EXPORT QGraphicsScale : public QGraphicsTransform
{
Q_OBJECT
- Q_PROPERTY(QPointF origin READ origin WRITE setOrigin NOTIFY originChanged)
+ Q_PROPERTY(QVector3D origin READ origin WRITE setOrigin NOTIFY originChanged)
Q_PROPERTY(qreal xScale READ xScale WRITE setXScale NOTIFY scaleChanged)
Q_PROPERTY(qreal yScale READ yScale WRITE setYScale NOTIFY scaleChanged)
+ Q_PROPERTY(qreal zScale READ zScale WRITE setZScale NOTIFY scaleChanged)
public:
QGraphicsScale(QObject *parent = 0);
~QGraphicsScale();
- QPointF origin() const;
- void setOrigin(const QPointF &point);
+ QVector3D origin() const;
+ void setOrigin(const QVector3D &point);
qreal xScale() const;
void setXScale(qreal);
@@ -99,7 +100,10 @@ public:
qreal yScale() const;
void setYScale(qreal);
- void applyTo(QTransform *transform) const;
+ qreal zScale() const;
+ void setZScale(qreal);
+
+ void applyTo(QMatrix4x4 *matrix) const;
Q_SIGNALS:
void originChanged();
@@ -115,15 +119,15 @@ class Q_GUI_EXPORT QGraphicsRotation : public QGraphicsTransform
{
Q_OBJECT
- Q_PROPERTY(QPointF origin READ origin WRITE setOrigin NOTIFY originChanged)
+ Q_PROPERTY(QVector3D origin READ origin WRITE setOrigin NOTIFY originChanged)
Q_PROPERTY(qreal angle READ angle WRITE setAngle NOTIFY angleChanged)
Q_PROPERTY(QVector3D axis READ axis WRITE setAxis NOTIFY axisChanged)
public:
QGraphicsRotation(QObject *parent = 0);
~QGraphicsRotation();
- QPointF origin() const;
- void setOrigin(const QPointF &point);
+ QVector3D origin() const;
+ void setOrigin(const QVector3D &point);
qreal angle() const;
void setAngle(qreal);
@@ -132,7 +136,7 @@ public:
void setAxis(const QVector3D &axis);
void setAxis(Qt::Axis axis);
- void applyTo(QTransform *transform) const;
+ void applyTo(QMatrix4x4 *matrix) const;
Q_SIGNALS:
void originChanged();
diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp
index 8fc439b..36ffcbe 100644
--- a/src/gui/math3d/qmatrix4x4.cpp
+++ b/src/gui/math3d/qmatrix4x4.cpp
@@ -41,6 +41,7 @@
#include "qmatrix4x4.h"
#include <QtCore/qmath.h>
+#include <QtCore/qvariant.h>
#include <QtGui/qmatrix.h>
#include <QtGui/qtransform.h>
@@ -1438,18 +1439,59 @@ QMatrix QMatrix4x4::toAffine() const
qreal(m[3][0]), qreal(m[3][1]));
}
+static const qreal inv_dist_to_plane = 1. / 1024.;
+
/*!
Returns the conventional Qt 2D transformation matrix that
- corresponds to this matrix. It is assumed that this matrix
- only contains 2D transformation elements.
+ corresponds to this matrix.
+
+ If \a distanceToPlane is non-zero, it indicates a projection
+ factor to use to adjust for the z co-ordinate. The default
+ value of 1024 corresponds to the projection factor used
+ by QTransform::rotate() for the x and y axes.
+
+ If \a distToPlane is zero, then the returned QTransform
+ is formed by simply dropping the third row and third column
+ of the QMatrix4x4. This is suitable for implementing
+ orthographic projections where the z co-ordinate should
+ be dropped rather than projected.
\sa toAffine()
*/
-QTransform QMatrix4x4::toTransform() const
+QTransform QMatrix4x4::toTransform(qreal distanceToPlane) const
{
- return QTransform(qreal(m[0][0]), qreal(m[0][1]), qreal(m[0][3]),
- qreal(m[1][0]), qreal(m[1][1]), qreal(m[1][3]),
- qreal(m[3][0]), qreal(m[3][1]), qreal(m[3][3]));
+ if (distanceToPlane == 1024.0f) {
+ // Optimize the common case with constants.
+ return QTransform(qreal(m[0][0]), qreal(m[0][1]),
+ qreal(m[0][3]) - qreal(m[0][2]) *
+ inv_dist_to_plane,
+ qreal(m[1][0]), qreal(m[1][1]),
+ qreal(m[1][3]) - qreal(m[1][2]) *
+ inv_dist_to_plane,
+ qreal(m[3][0]), qreal(m[3][1]),
+ qreal(m[3][3]) - qreal(m[3][2]) *
+ inv_dist_to_plane);
+ } else if (distanceToPlane != 0.0f) {
+ // The following projection matrix is pre-multiplied with "matrix":
+ // | 1 0 0 0 |
+ // | 0 1 0 0 |
+ // | 0 0 1 0 |
+ // | 0 0 d 1 |
+ // where d = -1 / distanceToPlane. After projection, row 3 and
+ // column 3 are dropped to form the final QTransform.
+ qreal d = 1.0f / distanceToPlane;
+ return QTransform(qreal(m[0][0]), qreal(m[0][1]),
+ qreal(m[0][3]) - qreal(m[0][2]) * d,
+ qreal(m[1][0]), qreal(m[1][1]),
+ qreal(m[1][3]) - qreal(m[1][2]) * d,
+ qreal(m[3][0]), qreal(m[3][1]),
+ qreal(m[3][3]) - qreal(m[3][2]) * d);
+ } else {
+ // Orthographic projection: drop row 3 and column 3.
+ return QTransform(qreal(m[0][0]), qreal(m[0][1]), qreal(m[0][3]),
+ qreal(m[1][0]), qreal(m[1][1]), qreal(m[1][3]),
+ qreal(m[3][0]), qreal(m[3][1]), qreal(m[3][3]));
+ }
}
/*!
@@ -1776,6 +1818,14 @@ void QMatrix4x4::inferSpecialType()
flagBits = Scale;
}
+/*!
+ Returns the matrix as a QVariant.
+*/
+QMatrix4x4::operator QVariant() const
+{
+ return QVariant(QVariant::Matrix4x4, this);
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QMatrix4x4 &m)
diff --git a/src/gui/math3d/qmatrix4x4.h b/src/gui/math3d/qmatrix4x4.h
index b02608d..10e628b 100644
--- a/src/gui/math3d/qmatrix4x4.h
+++ b/src/gui/math3d/qmatrix4x4.h
@@ -58,6 +58,7 @@ QT_MODULE(Gui)
class QMatrix;
class QTransform;
+class QVariant;
class Q_GUI_EXPORT QMatrix4x4
{
@@ -158,7 +159,7 @@ public:
void toValueArray(qreal *values) const;
QMatrix toAffine() const;
- QTransform toTransform() const;
+ QTransform toTransform(qreal distanceToPlane = 1024.0f) const;
QPoint map(const QPoint& point) const;
QPointF map(const QPointF& point) const;
@@ -182,6 +183,8 @@ public:
void inferSpecialType();
+ operator QVariant() const;
+
#ifndef QT_NO_DEBUG_STREAM
friend Q_GUI_EXPORT QDebug operator<<(QDebug dbg, const QMatrix4x4 &m);
#endif
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
index b2c598f..f279388 100644
--- a/src/gui/math3d/qquaternion.cpp
+++ b/src/gui/math3d/qquaternion.cpp
@@ -41,6 +41,7 @@
#include "qquaternion.h"
#include <QtCore/qmath.h>
+#include <QtCore/qvariant.h>
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
@@ -560,6 +561,14 @@ QQuaternion QQuaternion::nlerp
return (q1 * (1.0f - t) + q2b * t).normalized();
}
+/*!
+ Returns the quaternion as a QVariant.
+*/
+QQuaternion::operator QVariant() const
+{
+ return QVariant(QVariant::Quaternion, this);
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QQuaternion &q)
diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h
index a2fb29f..af60b61 100644
--- a/src/gui/math3d/qquaternion.h
+++ b/src/gui/math3d/qquaternion.h
@@ -54,6 +54,7 @@ QT_MODULE(Gui)
#ifndef QT_NO_QUATERNION
class QMatrix4x4;
+class QVariant;
class Q_GUI_EXPORT QQuaternion
{
@@ -118,6 +119,8 @@ public:
QVector4D toVector4D() const;
#endif
+ operator QVariant() const;
+
#ifndef QT_NO_VECTOR3D
static QQuaternion fromAxisAndAngle(const QVector3D& axis, qreal angle);
#endif
diff --git a/src/gui/math3d/qvector2d.cpp b/src/gui/math3d/qvector2d.cpp
index 1662020..35c86a1 100644
--- a/src/gui/math3d/qvector2d.cpp
+++ b/src/gui/math3d/qvector2d.cpp
@@ -43,6 +43,7 @@
#include "qvector3d.h"
#include "qvector4d.h"
#include <QtCore/qdebug.h>
+#include <QtCore/qvariant.h>
#include <QtCore/qmath.h>
QT_BEGIN_NAMESPACE
@@ -402,6 +403,14 @@ QVector4D QVector2D::toVector4D() const
\sa toPoint(), toVector3D()
*/
+/*!
+ Returns the 2D vector as a QVariant.
+*/
+QVector2D::operator QVariant() const
+{
+ return QVariant(QVariant::Vector2D, this);
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QVector2D &vector)
diff --git a/src/gui/math3d/qvector2d.h b/src/gui/math3d/qvector2d.h
index 93052f6..d9727e2 100644
--- a/src/gui/math3d/qvector2d.h
+++ b/src/gui/math3d/qvector2d.h
@@ -53,6 +53,7 @@ QT_MODULE(Gui)
class QVector3D;
class QVector4D;
+class QVariant;
#ifndef QT_NO_VECTOR2D
@@ -114,6 +115,8 @@ public:
QPoint toPoint() const;
QPointF toPointF() const;
+ operator QVariant() const;
+
private:
float xp, yp;
diff --git a/src/gui/math3d/qvector3d.cpp b/src/gui/math3d/qvector3d.cpp
index 0e3f4e1..5c96979 100644
--- a/src/gui/math3d/qvector3d.cpp
+++ b/src/gui/math3d/qvector3d.cpp
@@ -43,6 +43,7 @@
#include "qvector2d.h"
#include "qvector4d.h"
#include <QtCore/qmath.h>
+#include <QtCore/qvariant.h>
#include <QtCore/qdebug.h>
QT_BEGIN_NAMESPACE
@@ -530,6 +531,14 @@ QVector4D QVector3D::toVector4D() const
*/
/*!
+ Returns the 3D vector as a QVariant.
+*/
+QVector3D::operator QVariant() const
+{
+ return QVariant(QVariant::Vector3D, this);
+}
+
+/*!
Returns the length of the vector from the origin.
\sa lengthSquared(), normalized()
diff --git a/src/gui/math3d/qvector3d.h b/src/gui/math3d/qvector3d.h
index 36292d2..d1370fb 100644
--- a/src/gui/math3d/qvector3d.h
+++ b/src/gui/math3d/qvector3d.h
@@ -127,6 +127,8 @@ public:
QPoint toPoint() const;
QPointF toPointF() const;
+ operator QVariant() const;
+
private:
float xp, yp, zp;
diff --git a/src/gui/math3d/qvector4d.cpp b/src/gui/math3d/qvector4d.cpp
index a2efff7..11eb4c4 100644
--- a/src/gui/math3d/qvector4d.cpp
+++ b/src/gui/math3d/qvector4d.cpp
@@ -43,6 +43,7 @@
#include "qvector3d.h"
#include "qvector2d.h"
#include <QtCore/qdebug.h>
+#include <QtCore/qvariant.h>
#include <QtCore/qmath.h>
QT_BEGIN_NAMESPACE
@@ -500,6 +501,14 @@ QVector3D QVector4D::toVector3DAffine() const
\sa toPoint(), toVector2D()
*/
+/*!
+ Returns the 4D vector as a QVariant.
+*/
+QVector4D::operator QVariant() const
+{
+ return QVariant(QVariant::Vector4D, this);
+}
+
#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug dbg, const QVector4D &vector)
diff --git a/src/gui/math3d/qvector4d.h b/src/gui/math3d/qvector4d.h
index 42db45b..69ccd30 100644
--- a/src/gui/math3d/qvector4d.h
+++ b/src/gui/math3d/qvector4d.h
@@ -124,6 +124,8 @@ public:
QPoint toPoint() const;
QPointF toPointF() const;
+ operator QVariant() const;
+
private:
float xp, yp, zp, wp;
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
index 26a2374..956189c 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbpaintengine.cpp
@@ -847,6 +847,13 @@ void QDirectFBPaintEnginePrivate::setCompositionMode(QPainter::CompositionMode m
{
if (!surface)
return;
+
+ static const bool forceRasterFallBack = qgetenv("QT_DIRECTFB_FORCE_RASTER").toInt() > 0;
+ if (forceRasterFallBack) {
+ compositionModeStatus = 0;
+ return;
+ }
+
compositionModeStatus = PorterDuff_SupportedBlits;
switch (mode) {
case QPainter::CompositionMode_Clear:
diff --git a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp
index dc53847..45de07a 100644
--- a/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp
+++ b/src/plugins/gfxdrivers/directfb/qdirectfbscreen.cpp
@@ -1029,10 +1029,10 @@ bool QDirectFBScreen::connect(const QString &displaySpec)
surface = createDFBSurface(description, DontTrackSurface);
#endif
// Work out what format we're going to use for surfaces with an alpha channel
- d_ptr->alphaPixmapFormat = QDirectFBScreen::getImageFormat(surface);
+ QImage::Format pixelFormat = QDirectFBScreen::getImageFormat(surface);
+ d_ptr->alphaPixmapFormat = pixelFormat;
- setPixelFormat(d_ptr->alphaPixmapFormat);
- switch (d_ptr->alphaPixmapFormat) {
+ switch (pixelFormat) {
case QImage::Format_RGB666:
d_ptr->alphaPixmapFormat = QImage::Format_ARGB6666_Premultiplied;
break;
@@ -1040,9 +1040,9 @@ bool QDirectFBScreen::connect(const QString &displaySpec)
d_ptr->alphaPixmapFormat = QImage::Format_ARGB4444_Premultiplied;
break;
case QImage::Format_RGB32:
- qWarning("QDirectFBScreen::connect(). Qt/DirectFB does not work with the RGB32 pixelformat. "
- "We recommmend using ARGB instead");
- return false;
+ pixelFormat = d_ptr->alphaPixmapFormat = QImage::Format_ARGB32_Premultiplied;
+ // ### Format_RGB32 doesn't work so well with Qt. Force ARGB32 for windows/pixmaps
+ break;
case QImage::Format_Indexed8:
qWarning("QDirectFBScreen::connect(). Qt/DirectFB does not work with the LUT8 pixelformat.");
return false;
@@ -1064,8 +1064,8 @@ bool QDirectFBScreen::connect(const QString &displaySpec)
// works already
break;
}
-
- QScreen::d = ::depth(pixelFormat());
+ setPixelFormat(pixelFormat);
+ QScreen::d = ::depth(pixelFormat);
data = 0;
lstep = 0;
size = 0;
diff --git a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp
index bfd346b..d3d511a 100644
--- a/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp
+++ b/tests/auto/qgraphicstransform/tst_qgraphicstransform.cpp
@@ -84,60 +84,131 @@ void tst_QGraphicsTransform::cleanup()
{
}
+static QTransform transform2D(const QGraphicsTransform& t)
+{
+ QMatrix4x4 m;
+ t.applyTo(&m);
+ return m.toTransform();
+}
void tst_QGraphicsTransform::scale()
{
QGraphicsScale scale;
- scale.setOrigin(QPointF(10, 10));
- QTransform t;
+ // check initial conditions
+ QCOMPARE(scale.xScale(), qreal(1));
+ QCOMPARE(scale.yScale(), qreal(1));
+ QCOMPARE(scale.zScale(), qreal(1));
+ QCOMPARE(scale.origin(), QVector3D(0, 0, 0));
+
+ scale.setOrigin(QVector3D(10, 10, 0));
+
+ QCOMPARE(scale.xScale(), qreal(1));
+ QCOMPARE(scale.yScale(), qreal(1));
+ QCOMPARE(scale.zScale(), qreal(1));
+ QCOMPARE(scale.origin(), QVector3D(10, 10, 0));
+
+ QMatrix4x4 t;
scale.applyTo(&t);
- QCOMPARE(t, QTransform());
- QCOMPARE(scale.transform(), QTransform());
+ QCOMPARE(t, QMatrix4x4());
+ QCOMPARE(transform2D(scale), QTransform());
scale.setXScale(10);
- scale.setOrigin(QPointF(0, 0));
+ scale.setOrigin(QVector3D(0, 0, 0));
+
+ QCOMPARE(scale.xScale(), qreal(10));
+ QCOMPARE(scale.yScale(), qreal(1));
+ QCOMPARE(scale.zScale(), qreal(1));
+ QCOMPARE(scale.origin(), QVector3D(0, 0, 0));
QTransform res;
res.scale(10, 1);
- QCOMPARE(scale.transform(), res);
- QCOMPARE(scale.transform().map(QPointF(10, 10)), QPointF(100, 10));
+ QCOMPARE(transform2D(scale), res);
+ QCOMPARE(transform2D(scale).map(QPointF(10, 10)), QPointF(100, 10));
+
+ scale.setOrigin(QVector3D(10, 10, 0));
+ QCOMPARE(transform2D(scale).map(QPointF(10, 10)), QPointF(10, 10));
+ QCOMPARE(transform2D(scale).map(QPointF(11, 10)), QPointF(20, 10));
+
+ scale.setYScale(2);
+ scale.setZScale(4.5);
+ scale.setOrigin(QVector3D(1, 2, 3));
+
+ QCOMPARE(scale.xScale(), qreal(10));
+ QCOMPARE(scale.yScale(), qreal(2));
+ QCOMPARE(scale.zScale(), qreal(4.5));
+ QCOMPARE(scale.origin(), QVector3D(1, 2, 3));
+
+ QMatrix4x4 t2;
+ scale.applyTo(&t2);
- scale.setOrigin(QPointF(10, 10));
- QCOMPARE(scale.transform().map(QPointF(10, 10)), QPointF(10, 10));
- QCOMPARE(scale.transform().map(QPointF(11, 10)), QPointF(20, 10));
+ QCOMPARE(t2.map(QVector3D(4, 5, 6)), QVector3D(31, 8, 16.5));
+
+ // Because the origin has a non-zero z, mapping (4, 5) in 2D
+ // will introduce a projective component into the result.
+ QTransform t3 = t2.toTransform();
+ QCOMPARE(t3.map(QPointF(4, 5)), QPointF(31 / t3.m33(), 8 / t3.m33()));
+}
+
+// QMatrix4x4 uses float internally, whereas QTransform uses qreal.
+// This can lead to issues with qFuzzyCompare() where it uses double
+// precision to compare values that have no more than float precision
+// after conversion from QMatrix4x4 to QTransform. The following
+// definitions correct for the difference.
+static inline bool fuzzyCompare(qreal p1, qreal p2)
+{
+ return (qAbs(p1 - p2) <= 0.00001f * qMin(qAbs(p1), qAbs(p2)));
+}
+static bool fuzzyCompare(const QTransform& t1, const QTransform& t2)
+{
+ return fuzzyCompare(t1.m11(), t2.m11()) &&
+ fuzzyCompare(t1.m12(), t2.m12()) &&
+ fuzzyCompare(t1.m13(), t2.m13()) &&
+ fuzzyCompare(t1.m21(), t2.m21()) &&
+ fuzzyCompare(t1.m22(), t2.m22()) &&
+ fuzzyCompare(t1.m23(), t2.m23()) &&
+ fuzzyCompare(t1.m31(), t2.m31()) &&
+ fuzzyCompare(t1.m32(), t2.m32()) &&
+ fuzzyCompare(t1.m33(), t2.m33());
}
void tst_QGraphicsTransform::rotation()
{
QGraphicsRotation rotation;
- QCOMPARE(rotation.axis().x(), (qreal)0);
- QCOMPARE(rotation.axis().y(), (qreal)0);
- QCOMPARE(rotation.axis().z(), (qreal)1);
+ QCOMPARE(rotation.axis(), QVector3D(0, 0, 1));
+ QCOMPARE(rotation.origin(), QVector3D(0, 0, 0));
QCOMPARE(rotation.angle(), (qreal)0);
- rotation.setOrigin(QPointF(10, 10));
+ rotation.setOrigin(QVector3D(10, 10, 0));
+
+ QCOMPARE(rotation.axis(), QVector3D(0, 0, 1));
+ QCOMPARE(rotation.origin(), QVector3D(10, 10, 0));
+ QCOMPARE(rotation.angle(), (qreal)0);
- QTransform t;
+ QMatrix4x4 t;
rotation.applyTo(&t);
- QCOMPARE(t, QTransform());
- QCOMPARE(rotation.transform(), QTransform());
+ QCOMPARE(t, QMatrix4x4());
+ QCOMPARE(transform2D(rotation), QTransform());
rotation.setAngle(40);
- rotation.setOrigin(QPointF(0, 0));
+ rotation.setOrigin(QVector3D(0, 0, 0));
+
+ QCOMPARE(rotation.axis(), QVector3D(0, 0, 1));
+ QCOMPARE(rotation.origin(), QVector3D(0, 0, 0));
+ QCOMPARE(rotation.angle(), (qreal)40);
QTransform res;
res.rotate(40);
- QCOMPARE(rotation.transform(), res);
+ QVERIFY(fuzzyCompare(transform2D(rotation), res));
- rotation.setOrigin(QPointF(10, 10));
+ rotation.setOrigin(QVector3D(10, 10, 0));
rotation.setAngle(90);
- QCOMPARE(rotation.transform().map(QPointF(10, 10)), QPointF(10, 10));
- QCOMPARE(rotation.transform().map(QPointF(20, 10)), QPointF(10, 20));
+ QCOMPARE(transform2D(rotation).map(QPointF(10, 10)), QPointF(10, 10));
+ QCOMPARE(transform2D(rotation).map(QPointF(20, 10)), QPointF(10, 20));
}
Q_DECLARE_METATYPE(Qt::Axis);
@@ -161,38 +232,44 @@ void tst_QGraphicsTransform::rotation3d()
QGraphicsRotation rotation;
rotation.setAxis(axis);
- QTransform t;
+ QMatrix4x4 t;
rotation.applyTo(&t);
QVERIFY(t.isIdentity());
- QVERIFY(rotation.transform().isIdentity());
+ QVERIFY(transform2D(rotation).isIdentity());
rotation.setAngle(angle);
+ // QGraphicsRotation uses a correct mathematical rotation in 3D.
+ // QTransform's Qt::YAxis rotation is inverted from the mathematical
+ // version of rotation. We correct for that here.
QTransform expected;
- expected.rotate(angle, axis);
+ if (axis == Qt::YAxis && angle != 180.)
+ expected.rotate(-angle, axis);
+ else
+ expected.rotate(angle, axis);
- QVERIFY(qFuzzyCompare(rotation.transform(), expected));
+ QVERIFY(fuzzyCompare(transform2D(rotation), expected));
//now let's check that a null vector will not change the transform
rotation.setAxis(QVector3D(0, 0, 0));
- rotation.setOrigin(QPointF(10, 10));
+ rotation.setOrigin(QVector3D(10, 10, 0));
- t.reset();
+ t.setIdentity();
rotation.applyTo(&t);
QVERIFY(t.isIdentity());
- QVERIFY(rotation.transform().isIdentity());
+ QVERIFY(transform2D(rotation).isIdentity());
rotation.setAngle(angle);
QVERIFY(t.isIdentity());
- QVERIFY(rotation.transform().isIdentity());
+ QVERIFY(transform2D(rotation).isIdentity());
- rotation.setOrigin(QPointF(0, 0));
+ rotation.setOrigin(QVector3D(0, 0, 0));
QVERIFY(t.isIdentity());
- QVERIFY(rotation.transform().isIdentity());
+ QVERIFY(transform2D(rotation).isIdentity());
}
diff --git a/tests/benchmarks/qmatrix4x4/tst_qmatrix4x4.cpp b/tests/benchmarks/qmatrix4x4/tst_qmatrix4x4.cpp
index aeefd20..f80a142 100644
--- a/tests/benchmarks/qmatrix4x4/tst_qmatrix4x4.cpp
+++ b/tests/benchmarks/qmatrix4x4/tst_qmatrix4x4.cpp
@@ -67,6 +67,33 @@ private slots:
void mapVectorDirect_data();
void mapVectorDirect();
+
+ void compareTranslate_data();
+ void compareTranslate();
+
+ void compareTranslateAfterScale_data();
+ void compareTranslateAfterScale();
+
+ void compareTranslateAfterRotate_data();
+ void compareTranslateAfterRotate();
+
+ void compareScale_data();
+ void compareScale();
+
+ void compareScaleAfterTranslate_data();
+ void compareScaleAfterTranslate();
+
+ void compareScaleAfterRotate_data();
+ void compareScaleAfterRotate();
+
+ void compareRotate_data();
+ void compareRotate();
+
+ void compareRotateAfterTranslate_data();
+ void compareRotateAfterTranslate();
+
+ void compareRotateAfterScale_data();
+ void compareRotateAfterScale();
};
static qreal const generalValues[16] =
@@ -256,6 +283,390 @@ void tst_QMatrix4x4::mapVectorDirect()
}
}
+// Compare the performance of QTransform::translate() to
+// QMatrix4x4::translate().
+void tst_QMatrix4x4::compareTranslate_data()
+{
+ QTest::addColumn<bool>("useQTransform");
+ QTest::addColumn<QVector3D>("translation");
+
+ QTest::newRow("QTransform::translate(0, 0, 0)")
+ << true << QVector3D(0, 0, 0);
+ QTest::newRow("QMatrix4x4::translate(0, 0, 0)")
+ << false << QVector3D(0, 0, 0);
+
+ QTest::newRow("QTransform::translate(1, 2, 0)")
+ << true << QVector3D(1, 2, 0);
+ QTest::newRow("QMatrix4x4::translate(1, 2, 0)")
+ << false << QVector3D(1, 2, 0);
+
+ QTest::newRow("QTransform::translate(1, 2, 4)")
+ << true << QVector3D(1, 2, 4);
+ QTest::newRow("QMatrix4x4::translate(1, 2, 4)")
+ << false << QVector3D(1, 2, 4);
+}
+void tst_QMatrix4x4::compareTranslate()
+{
+ QFETCH(bool, useQTransform);
+ QFETCH(QVector3D, translation);
+
+ qreal x = translation.x();
+ qreal y = translation.y();
+ qreal z = translation.z();
+
+ if (useQTransform) {
+ QTransform t;
+ QBENCHMARK {
+ t.translate(x, y);
+ }
+ } else if (z == 0.0f) {
+ QMatrix4x4 m;
+ QBENCHMARK {
+ m.translate(x, y);
+ }
+ } else {
+ QMatrix4x4 m;
+ QBENCHMARK {
+ m.translate(x, y, z);
+ }
+ }
+}
+
+// Compare the performance of QTransform::translate() to
+// QMatrix4x4::translate() after priming the matrix with a scale().
+void tst_QMatrix4x4::compareTranslateAfterScale_data()
+{
+ compareTranslate_data();
+}
+void tst_QMatrix4x4::compareTranslateAfterScale()
+{
+ QFETCH(bool, useQTransform);
+ QFETCH(QVector3D, translation);
+
+ qreal x = translation.x();
+ qreal y = translation.y();
+ qreal z = translation.z();
+
+ if (useQTransform) {
+ QTransform t;
+ t.scale(3, 4);
+ QBENCHMARK {
+ t.translate(x, y);
+ }
+ } else if (z == 0.0f) {
+ QMatrix4x4 m;
+ m.scale(3, 4);
+ QBENCHMARK {
+ m.translate(x, y);
+ }
+ } else {
+ QMatrix4x4 m;
+ m.scale(3, 4, 5);
+ QBENCHMARK {
+ m.translate(x, y, z);
+ }
+ }
+}
+
+// Compare the performance of QTransform::translate() to
+// QMatrix4x4::translate() after priming the matrix with a rotate().
+void tst_QMatrix4x4::compareTranslateAfterRotate_data()
+{
+ compareTranslate_data();
+}
+void tst_QMatrix4x4::compareTranslateAfterRotate()
+{
+ QFETCH(bool, useQTransform);
+ QFETCH(QVector3D, translation);
+
+ qreal x = translation.x();
+ qreal y = translation.y();
+ qreal z = translation.z();
+
+ if (useQTransform) {
+ QTransform t;
+ t.rotate(45.0f);
+ QBENCHMARK {
+ t.translate(x, y);
+ }
+ } else if (z == 0.0f) {
+ QMatrix4x4 m;
+ m.rotate(45.0f, 0, 0, 1);
+ QBENCHMARK {
+ m.translate(x, y);
+ }
+ } else {
+ QMatrix4x4 m;
+ m.rotate(45.0f, 0, 0, 1);
+ QBENCHMARK {
+ m.translate(x, y, z);
+ }
+ }
+}
+
+// Compare the performance of QTransform::scale() to
+// QMatrix4x4::scale().
+void tst_QMatrix4x4::compareScale_data()
+{
+ QTest::addColumn<bool>("useQTransform");
+ QTest::addColumn<QVector3D>("scale");
+
+ QTest::newRow("QTransform::scale(1, 1, 1)")
+ << true << QVector3D(1, 1, 1);
+ QTest::newRow("QMatrix4x4::scale(1, 1, 1)")
+ << false << QVector3D(1, 1, 1);
+
+ QTest::newRow("QTransform::scale(3, 6, 1)")
+ << true << QVector3D(3, 6, 1);
+ QTest::newRow("QMatrix4x4::scale(3, 6, 1)")
+ << false << QVector3D(3, 6, 1);
+
+ QTest::newRow("QTransform::scale(3, 6, 4)")
+ << true << QVector3D(3, 6, 4);
+ QTest::newRow("QMatrix4x4::scale(3, 6, 4)")
+ << false << QVector3D(3, 6, 4);
+}
+void tst_QMatrix4x4::compareScale()
+{
+ QFETCH(bool, useQTransform);
+ QFETCH(QVector3D, scale);
+
+ qreal x = scale.x();
+ qreal y = scale.y();
+ qreal z = scale.z();
+
+ if (useQTransform) {
+ QTransform t;
+ QBENCHMARK {
+ t.scale(x, y);
+ }
+ } else if (z == 1.0f) {
+ QMatrix4x4 m;
+ QBENCHMARK {
+ m.scale(x, y);
+ }
+ } else {
+ QMatrix4x4 m;
+ QBENCHMARK {
+ m.scale(x, y, z);
+ }
+ }
+}
+
+// Compare the performance of QTransform::scale() to
+// QMatrix4x4::scale() after priming the matrix with a translate().
+void tst_QMatrix4x4::compareScaleAfterTranslate_data()
+{
+ compareScale_data();
+}
+void tst_QMatrix4x4::compareScaleAfterTranslate()
+{
+ QFETCH(bool, useQTransform);
+ QFETCH(QVector3D, scale);
+
+ qreal x = scale.x();
+ qreal y = scale.y();
+ qreal z = scale.z();
+
+ if (useQTransform) {
+ QTransform t;
+ t.translate(20, 34);
+ QBENCHMARK {
+ t.scale(x, y);
+ }
+ } else if (z == 1.0f) {
+ QMatrix4x4 m;
+ m.translate(20, 34);
+ QBENCHMARK {
+ m.scale(x, y);
+ }
+ } else {
+ QMatrix4x4 m;
+ m.translate(20, 34, 42);
+ QBENCHMARK {
+ m.scale(x, y, z);
+ }
+ }
+}
+
+// Compare the performance of QTransform::scale() to
+// QMatrix4x4::scale() after priming the matrix with a rotate().
+void tst_QMatrix4x4::compareScaleAfterRotate_data()
+{
+ compareScale_data();
+}
+void tst_QMatrix4x4::compareScaleAfterRotate()
+{
+ QFETCH(bool, useQTransform);
+ QFETCH(QVector3D, scale);
+
+ qreal x = scale.x();
+ qreal y = scale.y();
+ qreal z = scale.z();
+
+ if (useQTransform) {
+ QTransform t;
+ t.rotate(45.0f);
+ QBENCHMARK {
+ t.scale(x, y);
+ }
+ } else if (z == 1.0f) {
+ QMatrix4x4 m;
+ m.rotate(45.0f, 0, 0, 1);
+ QBENCHMARK {
+ m.scale(x, y);
+ }
+ } else {
+ QMatrix4x4 m;
+ m.rotate(45.0f, 0, 0, 1);
+ QBENCHMARK {
+ m.scale(x, y, z);
+ }
+ }
+}
+
+// Compare the performance of QTransform::rotate() to
+// QMatrix4x4::rotate().
+void tst_QMatrix4x4::compareRotate_data()
+{
+ QTest::addColumn<bool>("useQTransform");
+ QTest::addColumn<qreal>("angle");
+ QTest::addColumn<QVector3D>("rotation");
+ QTest::addColumn<int>("axis");
+
+ QTest::newRow("QTransform::rotate(0, ZAxis)")
+ << true << qreal(0.0f) << QVector3D(0, 0, 1) << int(Qt::ZAxis);
+ QTest::newRow("QMatrix4x4::rotate(0, ZAxis)")
+ << false << qreal(0.0f) << QVector3D(0, 0, 1) << int(Qt::ZAxis);
+
+ QTest::newRow("QTransform::rotate(45, ZAxis)")
+ << true << qreal(45.0f) << QVector3D(0, 0, 1) << int(Qt::ZAxis);
+ QTest::newRow("QMatrix4x4::rotate(45, ZAxis)")
+ << false << qreal(45.0f) << QVector3D(0, 0, 1) << int(Qt::ZAxis);
+
+ QTest::newRow("QTransform::rotate(90, ZAxis)")
+ << true << qreal(90.0f) << QVector3D(0, 0, 1) << int(Qt::ZAxis);
+ QTest::newRow("QMatrix4x4::rotate(90, ZAxis)")
+ << false << qreal(90.0f) << QVector3D(0, 0, 1) << int(Qt::ZAxis);
+
+ QTest::newRow("QTransform::rotate(0, YAxis)")
+ << true << qreal(0.0f) << QVector3D(0, 1, 0) << int(Qt::YAxis);
+ QTest::newRow("QMatrix4x4::rotate(0, YAxis)")
+ << false << qreal(0.0f) << QVector3D(0, 1, 0) << int(Qt::YAxis);
+
+ QTest::newRow("QTransform::rotate(45, YAxis)")
+ << true << qreal(45.0f) << QVector3D(0, 1, 0) << int(Qt::YAxis);
+ QTest::newRow("QMatrix4x4::rotate(45, YAxis)")
+ << false << qreal(45.0f) << QVector3D(0, 1, 0) << int(Qt::YAxis);
+
+ QTest::newRow("QTransform::rotate(90, YAxis)")
+ << true << qreal(90.0f) << QVector3D(0, 1, 0) << int(Qt::YAxis);
+ QTest::newRow("QMatrix4x4::rotate(90, YAxis)")
+ << false << qreal(90.0f) << QVector3D(0, 1, 0) << int(Qt::YAxis);
+
+ QTest::newRow("QTransform::rotate(0, XAxis)")
+ << true << qreal(0.0f) << QVector3D(0, 1, 0) << int(Qt::XAxis);
+ QTest::newRow("QMatrix4x4::rotate(0, XAxis)")
+ << false << qreal(0.0f) << QVector3D(0, 1, 0) << int(Qt::XAxis);
+
+ QTest::newRow("QTransform::rotate(45, XAxis)")
+ << true << qreal(45.0f) << QVector3D(1, 0, 0) << int(Qt::XAxis);
+ QTest::newRow("QMatrix4x4::rotate(45, XAxis)")
+ << false << qreal(45.0f) << QVector3D(1, 0, 0) << int(Qt::XAxis);
+
+ QTest::newRow("QTransform::rotate(90, XAxis)")
+ << true << qreal(90.0f) << QVector3D(1, 0, 0) << int(Qt::XAxis);
+ QTest::newRow("QMatrix4x4::rotate(90, XAxis)")
+ << false << qreal(90.0f) << QVector3D(1, 0, 0) << int(Qt::XAxis);
+}
+void tst_QMatrix4x4::compareRotate()
+{
+ QFETCH(bool, useQTransform);
+ QFETCH(qreal, angle);
+ QFETCH(QVector3D, rotation);
+ QFETCH(int, axis);
+
+ qreal x = rotation.x();
+ qreal y = rotation.y();
+ qreal z = rotation.z();
+
+ if (useQTransform) {
+ QTransform t;
+ QBENCHMARK {
+ t.rotate(angle, Qt::Axis(axis));
+ }
+ } else {
+ QMatrix4x4 m;
+ QBENCHMARK {
+ m.rotate(angle, x, y, z);
+ }
+ }
+}
+
+// Compare the performance of QTransform::rotate() to
+// QMatrix4x4::rotate() after priming the matrix with a translate().
+void tst_QMatrix4x4::compareRotateAfterTranslate_data()
+{
+ compareRotate_data();
+}
+void tst_QMatrix4x4::compareRotateAfterTranslate()
+{
+ QFETCH(bool, useQTransform);
+ QFETCH(qreal, angle);
+ QFETCH(QVector3D, rotation);
+ QFETCH(int, axis);
+
+ qreal x = rotation.x();
+ qreal y = rotation.y();
+ qreal z = rotation.z();
+
+ if (useQTransform) {
+ QTransform t;
+ t.translate(3, 4);
+ QBENCHMARK {
+ t.rotate(angle, Qt::Axis(axis));
+ }
+ } else {
+ QMatrix4x4 m;
+ m.translate(3, 4, 5);
+ QBENCHMARK {
+ m.rotate(angle, x, y, z);
+ }
+ }
+}
+
+// Compare the performance of QTransform::rotate() to
+// QMatrix4x4::rotate() after priming the matrix with a scale().
+void tst_QMatrix4x4::compareRotateAfterScale_data()
+{
+ compareRotate_data();
+}
+void tst_QMatrix4x4::compareRotateAfterScale()
+{
+ QFETCH(bool, useQTransform);
+ QFETCH(qreal, angle);
+ QFETCH(QVector3D, rotation);
+ QFETCH(int, axis);
+
+ qreal x = rotation.x();
+ qreal y = rotation.y();
+ qreal z = rotation.z();
+
+ if (useQTransform) {
+ QTransform t;
+ t.scale(3, 4);
+ QBENCHMARK {
+ t.rotate(angle, Qt::Axis(axis));
+ }
+ } else {
+ QMatrix4x4 m;
+ m.scale(3, 4, 5);
+ QBENCHMARK {
+ m.rotate(angle, x, y, z);
+ }
+ }
+}
+
QTEST_MAIN(tst_QMatrix4x4)
#include "tst_qmatrix4x4.moc"