/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** Contact: Qt Software Information (qt-info@nokia.com) ** ** This file is part of the QtDeclarative module of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** No Commercial Usage ** This file contains pre-release code and may not be distributed. ** You may use this file in accordance with the terms and conditions ** contained in the either Technology Preview License Agreement or the ** Beta Release License Agreement. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain ** additional rights. These rights are described in the Nokia Qt LGPL ** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this ** package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file. Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you are unsure which license is appropriate for your use, please ** contact the sales department at qt-sales@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ #include #include "private/qfxitem_p.h" #include "qfxtransform.h" #include #include #ifndef M_PI QT_BEGIN_NAMESPACE #define M_PI 3.14159265358979323846 #endif QML_DEFINE_NOCREATE_TYPE(QFxTransform); /*! \qmlclass Transform \brief A transformation. */ QFxTransform::QFxTransform(QObject *parent) : QObject(parent) { } QFxTransform::~QFxTransform() { } bool QFxTransform::isIdentity() const { return true; } QSimpleCanvas::Matrix QFxTransform::transform() const { return QSimpleCanvas::Matrix(); } void QFxTransform::update() { QFxItem *item = qobject_cast(parent()); if(item) item->updateTransform(); } /*! \qmlclass Axis \brief An axis that can be used for rotation or translation. */ QML_DEFINE_TYPE(QFxAxis, Axis); QFxAxis::QFxAxis(QObject *parent) : QObject(parent), _startX(0), _startY(0), _endX(0), _endY(0), _endZ(0) { } QFxAxis::~QFxAxis() { } qreal QFxAxis::startX() const { return _startX; } void QFxAxis::setStartX(qreal x) { _startX = x; emit updated(); } qreal QFxAxis::startY() const { return _startY; } void QFxAxis::setStartY(qreal y) { _startY = y; emit updated(); } qreal QFxAxis::endX() const { return _endX; } void QFxAxis::setEndX(qreal x) { _endX = x; emit updated(); } qreal QFxAxis::endY() const { return _endY; } void QFxAxis::setEndY(qreal y) { _endY = y; emit updated(); } qreal QFxAxis::endZ() const { return _endZ; } void QFxAxis::setEndZ(qreal z) { _endZ = z; emit updated(); } /*! \qmlclass AxisRotation \brief The AxisRotation element provides a way to rotate an Item around an axis. Here is an example of various rotations applied to an \l Image. \code \endcode \image axisrotation.png */ QML_DEFINE_TYPE(QFxRotation,AxisRotation); QFxRotation::QFxRotation(QObject *parent) : QFxTransform(parent), _angle(0), _distanceToPlane(1024.), _dirty(true) { connect(&_axis, SIGNAL(updated()), this, SLOT(update())); } QFxRotation::~QFxRotation() { } /*! \qmlproperty real AxisRotation::axis.startX \qmlproperty real AxisRotation::axis.startY \qmlproperty real AxisRotation::axis.endX \qmlproperty real AxisRotation::axis.endY \qmlproperty real AxisRotation::axis.endZ A rotation axis is specified by 2 points in 3D space: a start point and an end point. The z-position of the start point is assumed to be 0, and cannot be changed. */ QFxAxis *QFxRotation::axis() { return &_axis; } /*! \qmlproperty real AxisRotation::angle The angle, in degrees, to rotate around the specified axis. */ qreal QFxRotation::angle() const { return _angle; } void QFxRotation::setAngle(qreal angle) { _angle = angle; update(); } bool QFxRotation::isIdentity() const { return (_angle == 0.) || (_axis.endZ() == 0. && _axis.endY() == _axis.startY() && _axis.endX() == _axis.startX()); } #if defined(QFX_RENDER_QPAINTER) const qreal inv_dist_to_plane = 1. / 1024.; QTransform QFxRotation::transform() const { if(_dirty) { _transform = QTransform(); if(!isIdentity()) { if(angle() != 0.) { QTransform rotTrans; rotTrans.translate(-_axis.startX(), -_axis.startY()); QTransform rotTrans2; rotTrans2.translate(_axis.startX(), _axis.startY()); qreal rad = angle() * 2. * M_PI / 360.; qreal c = ::cos(rad); qreal s = ::sin(rad); qreal x = _axis.endX() - _axis.startX(); qreal y = _axis.endY() - _axis.startY(); qreal z = _axis.endZ(); qreal idtp = inv_dist_to_plane; if(distanceToPlane() != 1024.) idtp = 1. / distanceToPlane(); qreal len = x * x + y * y + z * z; if(len != 1.) { len = ::sqrt(len); x /= len; y /= len; z /= len; } QTransform rot(x*x*(1-c)+c, x*y*(1-c)-z*s, x*z*(1-c)+y*s*idtp, y*x*(1-c)+z*s, y*y*(1-c)+c, y*z*(1-c)-x*s*idtp, 0, 0, 1); _transform *= rotTrans; _transform *= rot; _transform *= rotTrans2; } } _dirty = false; } return _transform; } #elif defined(QFX_RENDER_OPENGL) QMatrix4x4 QFxRotation::transform() const { if(_dirty) { _dirty = false; _transform = QMatrix4x4(); if(!isIdentity()) { if(angle() != 0.) { qreal x = _axis.endX() - _axis.startX(); qreal y = _axis.endY() - _axis.startY(); qreal z = _axis.endZ(); _transform.translate(_axis.startX(), _axis.startY(), 0); _transform.rotate(angle(), x, y, z); _transform.translate(-_axis.startX(), -_axis.startY(), 0); } } } return _transform; } #endif /*! \qmlproperty real AxisRotation::distanceToPlane */ qreal QFxRotation::distanceToPlane() const { return _distanceToPlane; } void QFxRotation::setDistanceToPlane(qreal d) { _distanceToPlane = d; update(); } void QFxRotation::update() { _dirty = true; QFxItem *item = qobject_cast(parent()); if(item) item->updateTransform(); } /*! \qmlclass AxisTranslation \brief The AxisTranslation element provides a way to move an Item along an axis. The following example translates the image to 10, 3. \code \endcode */ QML_DEFINE_TYPE(QFxTranslation,AxisTranslation); QFxTranslation::QFxTranslation(QObject *parent) : QFxTransform(parent), _distance(0), _dirty(true) { connect(&_axis, SIGNAL(updated()), this, SLOT(update())); } QFxTranslation::~QFxTranslation() { } /*! \qmlproperty real AxisTranslation::axis.startX \qmlproperty real AxisTranslation::axis.startY \qmlproperty real AxisTranslation::axis.endX \qmlproperty real AxisTranslation::axis.endY \qmlproperty real AxisTranslation::axis.endZ A translation axis is specified by 2 points in 3D space: a start point and an end point. The z-position of the start point is assumed to be 0, and cannot be changed. Changing the z-position of the end point is only valid when running under OpenGL. */ QFxAxis *QFxTranslation::axis() { return &_axis; } /*! \qmlproperty real AxisTranslation::distance The distance to translate along the specified axis. distance is a multiplier; in the example below, a distance of 1 would translate to 100, 50, while a distance of 0.5 would translate to 50, 25. \code \endcode */ qreal QFxTranslation::distance() const { return _distance; } void QFxTranslation::setDistance(qreal distance) { _distance = distance; update(); } bool QFxTranslation::isIdentity() const { return (_distance == 0.) || (_axis.endZ() == 0. && _axis.endY() == _axis.startY() && _axis.endX() == _axis.startX()); } #if defined(QFX_RENDER_QPAINTER) QTransform QFxTranslation::transform() const { if(_dirty) { _transform = QTransform(); if(!isIdentity()) { if(distance() != 0.) { QTransform trans; trans.translate((_axis.endX() - _axis.startX()) * distance(), (_axis.endY() - _axis.startY()) * distance()); _transform *= trans; } } _dirty = false; } return _transform; } #elif defined(QFX_RENDER_OPENGL) QMatrix4x4 QFxRotation::transform() const { if(_dirty) { _dirty = false; _transform = QMatrix4x4(); if(!isIdentity()) { if(distance() != 0.) _transform.translate((_axis.endX() - _axis.startX()) * distance(), (_axis.endY() - _axis.startY()) * distance(), (_axis.endZ()) * distance()); } } return _transform; } #endif void QFxTranslation::update() { _dirty = true; #if !defined(QFX_RENDER_OPENGL) if(_axis.endZ() != 0. && distance() != 0.) { qmlInfo(this) << "QTransform cannot translate along Z-axis."; } #endif QFxItem *item = qobject_cast(parent()); if(item) item->updateTransform(); } /*! \qmlclass Perspective \brief The Perspective element specifies a perspective transformation. A Perspective transform only affects an item when running under OpenGL; when running under software rasterization it has no effect. */ QML_DEFINE_TYPE(QFxPerspective,Perspective); QFxPerspective::QFxPerspective(QObject *parent) : QFxTransform(parent) { } QFxPerspective::~QFxPerspective() { } #if defined(QFX_RENDER_OPENGL) bool QFxPerspective::isIdentity() const { return false; } QMatrix4x4 QFxPerspective::transform() const { QMatrix4x4 rv; rv.translate(_x, _y); rv.perspective(_angle, _aspect, 1, 1024 * 1024); rv.translate(-_x, -_y, -1); rv.scale(1, 1, 1. / _scale); return rv; } #endif /*! \qmlproperty real Perspective::angle */ /*! \qmlproperty real Perspective::aspect */ /*! \qmlproperty real Perspective::x */ /*! \qmlproperty real Perspective::y */ /*! \qmlproperty real Perspective::scale */ /*! \qmlclass Squish \brief The Squish element allows you to distort an items appearance by 'squishing' it. A Squish transform only affects an item when running under OpenGL; when running under software rasterization it has no effect. */ QML_DEFINE_TYPE(QFxSquish,Squish); QFxSquish::QFxSquish(QObject *parent) : QFxTransform(parent) { } QFxSquish::~QFxSquish() { } /*! \qmlproperty real Squish::x */ qreal QFxSquish::x() const { return p.x(); } void QFxSquish::setX(qreal v) { p.setX(v); update(); } /*! \qmlproperty real Squish::y */ qreal QFxSquish::y() const { return p.y(); } void QFxSquish::setY(qreal v) { p.setY(v); update(); } /*! \qmlproperty real Squish::width */ qreal QFxSquish::width() const { return s.width(); } void QFxSquish::setWidth(qreal v) { s.setWidth(v); update(); } /*! \qmlproperty real Squish::height */ qreal QFxSquish::height() const { return s.height(); } void QFxSquish::setHeight(qreal v) { s.setHeight(v); update(); } /*! \qmlproperty real Squish::topLeftX \qmlproperty real Squish::topLeftY */ qreal QFxSquish::topLeft_x() const { return p1.x(); } void QFxSquish::settopLeft_x(qreal v) { p1.setX(v); update(); } qreal QFxSquish::topLeft_y() const { return p1.y(); } void QFxSquish::settopLeft_y(qreal v) { p1.setY(v); update(); } /*! \qmlproperty real Squish::topRightX \qmlproperty real Squish::topRightY */ qreal QFxSquish::topRight_x() const { return p2.x(); } void QFxSquish::settopRight_x(qreal v) { p2.setX(v); update(); } qreal QFxSquish::topRight_y() const { return p2.y(); } void QFxSquish::settopRight_y(qreal v) { p2.setY(v); update(); } /*! \qmlproperty real Squish::bottomLeftX \qmlproperty real Squish::bottomLeftY */ qreal QFxSquish::bottomLeft_x() const { return p3.x(); } void QFxSquish::setbottomLeft_x(qreal v) { p3.setX(v); update(); } qreal QFxSquish::bottomLeft_y() const { return p3.y(); } void QFxSquish::setbottomLeft_y(qreal v) { p3.setY(v); update(); } /*! \qmlproperty real Squish::bottomRightX \qmlproperty real Squish::bottomRightY */ qreal QFxSquish::bottomRight_x() const { return p4.x(); } void QFxSquish::setbottomRight_x(qreal v) { p4.setX(v); update(); } qreal QFxSquish::bottomRight_y() const { return p4.y(); } void QFxSquish::setbottomRight_y(qreal v) { p4.setY(v); update(); } void QFxSquish::update() { QFxItem *item = qobject_cast(parent()); if(item) item->updateTransform(); } #if defined(QFX_RENDER_OPENGL) bool QFxSquish::isIdentity() const { return false; } QMatrix4x4 QFxSquish::transform() const { QPolygonF poly; poly << p << QPointF(p.x() + s.width(), p.y()) << QPointF(p.x() + s.width(), p.y() + s.height()) << QPointF(p.x(), p.y() + s.height()); QPolygonF poly2; poly2 << p1 << p2 << p4 << p3; QTransform t; QMatrix4x4 rv; if(QTransform::quadToQuad(poly, poly2, t)) rv = QMatrix4x4(t); return rv; } #endif QT_END_NAMESPACE