diff options
Diffstat (limited to 'src/threed/viewing')
-rw-r--r-- | src/threed/viewing/qglcamera.cpp | 1328 | ||||
-rw-r--r-- | src/threed/viewing/qglcamera.h | 184 | ||||
-rw-r--r-- | src/threed/viewing/qglcameraanimation.cpp | 543 | ||||
-rw-r--r-- | src/threed/viewing/qglcameraanimation.h | 116 | ||||
-rw-r--r-- | src/threed/viewing/qglview.cpp | 1496 | ||||
-rw-r--r-- | src/threed/viewing/qglview.h | 146 | ||||
-rw-r--r-- | src/threed/viewing/viewing.pri | 12 |
7 files changed, 0 insertions, 3825 deletions
diff --git a/src/threed/viewing/qglcamera.cpp b/src/threed/viewing/qglcamera.cpp deleted file mode 100644 index 4f236507..00000000 --- a/src/threed/viewing/qglcamera.cpp +++ /dev/null @@ -1,1328 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtQuick3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglcamera.h" -#include "qglpainter.h" -#include <QtGui/qquaternion.h> -#include <QtCore/qmath.h> - -QT_BEGIN_NAMESPACE - -/*! - \class QGLCamera - \brief The QGLCamera class defines the projection to apply to simulate a camera's position, orientation, and optics. - \since 4.8 - \ingroup qt3d - \ingroup qt3d::viewing - - \section1 Modelview and projection transformations - - A QGLCamera instance is applied to the scene in two phases: - modelview transformation and projection transformation. - - During the modelview transformation, the eye(), center(), and - upVector() are used to generate a 4x4 transformation matrix that - reflects the viewer's current position and orientation. - - During the projection transformation, the projectionType(), - nearPlane(), farPlane(), fieldOfView(), and viewSize() are used - to define a viewing volume as a 4x4 transformation matrix. - - The modelview transformation matrix is returned by modelViewMatrix(). - The projection transformation matrix is returned by projectionMatrix(). - - \section1 Positioning and orienting the view - - The viewer position and orientation are defined by eye(), center(), - and upVector(). The location of the viewer in world co-ordinates is - given by eye(), the viewer is looking at the object of interest located - at center(), and the upVector() specifies the direction that should - be considered "up" with respect to the viewer. - - The vector from the eye() to the center() is called the "view vector", - and the cross-product of the view vector and upVector() is called - the "side vector". The view vector specifies the direction the - viewer is looking, and the side vector points off to the right of - the viewer. - - It is recommended that the view vector and upVector() be at right angles - to each other, but this is not required as long as the angle between - them is close to 90 degrees. - - The most common use of view and up vectors that are not at right angles - is to simulate a human eye at a specific height above the ground looking - down at a lower object or up at a higher object. In this case, the - the view vector will not be true horizontal, but the upVector() indicating - the human's upright stance will be true vertical. - - \section1 Zooming the camera image - - There are two ways to zoom the image seen through the camera: either - the camera eye() position can be moved closer to the object of interest, - or the field of view of the camera lens can be changed to make it appear - as though the object is moving closer. - - Changing the eye() position changes the lighting calculation in the - scene because the viewer is in a different position, changing the - angle of light reflection on the object's surface. - - The setFieldOfView() function can be used to simulate the effect of a - camera lens. The smaller the fieldOfView(), the closer the object - will appear. The lighting calculation will be the same as for the - unzoomed scene. - - If fieldOfView() is zero, then a standard perspective frustum of - viewSize() is used to define the viewing volume. The viewSize() - can be adjusted with setViewSize() to zoom the view. A smaller - viewSize() will make the the object appear closer. - - The fieldOfView() or viewSize() is applied as part of the - projectionMatrix(). - - \section1 Rotating the viewer or object of interest - - Rotating a viewer in 3D space is a very delicate process. It is very - easy to construct the rotation incorrectly and end up in a "gimbal lock" - state where further rotations are impossible in certain directions. - - To help alleviate this problem, QGLCamera uses a quaternion-based - approach to generate rotations. A quaternion is a compact representation - of a rotation in 3D space. Rotations can be combined through quaternion - multiplication. More information on quaternions can be found in the - documentation for QQuaternion. - - Before rotating the view, you should first decide the type - of rotation you want to perform: - - \list - \i Tilting or panning a fixed eye to reveal the scene in different - directions and orientations. This is equivalent to mounting a camera - on a fixed tripod and then adjusting the direction of view and - orientation with the tripod controls. - \i Rotating a moving viewer about the object of interest. This is - equivalent to moving the viewer around the object at a fixed distance, - but with the viewer always pointing at the object. - \endlist - - In the QGLCamera class, the first type of rotation is performed with - rotateEye() and the second with rotateCenter(). Each of these functions - take a quaternion argument that defines the type of rotation to perform. - - The tilt(), pan(), and roll() functions return values that can help with - constructing the rotation quaternions to pass to rotateEye() and - rotateCenter(). Tilt and pan are also known as "pitch" and "yaw" in - flight dynamics. - - Three axes of rotation are used to compute the quaternions. The tilt() - quaternion is computed with respect to the side vector, the pan() - quaterion is computed with respect to the upVector(), and the roll() - quaternion is computed with respect to the view vector. - - The following example tilts the direction the eye() is pointing - by 5 degrees, and then pans by 45 degrees: - - \code - camera.rotateEye(camera.tilt(5)); - camera.rotateEye(camera.pan(45)); - \endcode - - The next example performs the two rotations in a single fluid step - (note that the rotation to be performed first is multiplied last): - - \code - camera.rotateEye(camera.pan(45) * camera.tilt(5)); - \endcode - - These two examples will not produce the same visual result, even though - it looks like they might. In the first example, the upVector() is tilted - before the pan() quaternion is computed. In the second example, the pan() - quaternion is computed using the original upVector(). - - This difference in behavior is useful in different situations. Some - applications may wish to perform all rotations relative to the original - viewer orientation, and other applications may wish to perform rotations - relative to the current viewer orientation. These application types - correspond to the second and first examples above. - - \section1 Moving the viewer or object of interest - - The simplest way to move the viewer or object of interest is to call - setEye() or setCenter() respectively and supply a new position in - world co-ordinates. However, this can lead to non-intuitive movements - if the viewer orientation is not aligned with the world co-ordinate axes. - - For example, subtracting 3 from the eye() x co-ordinate will appear to - move the eye left 3 units if the viewer orientation is aligned with the - world co-ordinate axes. But it will not appear to move the eye left 3 - units in any other orientation. - - The translation() function can be used to construct a translation - vector that is aligned with the viewer's current orientation. - Movement in the x direction will move along the side vector, movement in - the y direction will move along upVector(), and movement in the z - direction will move along the view vector. - - The translation() function is useful when implementing operations such - as "step left", "jump up", and so on where the movement should be - interpreted relative to the viewer's current orientation, not the - world co-ordinate axes, - - In other words, the following two lines of code are not equivalent - unless the view is oriented with the world co-ordinate axes: - - \code - camera.translateEye(camera.translation(x, y, z)); - - camera.translateEye(QVector3D(x, y, z)); - \endcode - - The following example translates the eye() position while - keeping the object of interest at the original center(): - - \code - camera.translateEye(camera.translation(x, y, z)); - \endcode - - The following example translates the object of interest at - center() while keeping the eye() position fixed: - - \code - camera.translateCenter(camera.translation(x, y, z)); - \endcode - - The following example translates both the eye() and the center() - by the same amount, which will maintain the original view vector. - - \code - QVector3D vector = camera.translation(x, y, z); - camera.translateEye(vector); - camera.translateCenter(vector); - \endcode - - It is important that the translation vector for center() be computed - before eye() is translated if both eye() and center() must move by the - same amount. The following code translates center() in the viewer - orientation after the eye() is translated: - - \code - camera.translateEye(camera.translation(x, y, z)); - camera.translateCenter(camera.translation(x, y, z)); - \endcode - - Translating both eye() and center() by the same amount can be used - to simulate sliding a viewer past a scene while always looking in the - same direction (for example, filming a scene from a moving vehicle). - An alternative is to fix the viewer and move the scene itself: - the negation of the translation() vector can be applied to the - scene's modelview transformation. - - \section1 Motion tracking - - Viewing of 3D scenes can be enhanced if there is some way to track - the motion of the viewer or the orientation of the display device. - - Applications can use setMotionAdjustment() to alter the position - of the camera to account for the viewer's motion. This indicates - the viewer's position relative to the center of the screen. - The motionAdjustment() vector is used to determine by how much - the camera position should be adjusted. The distance of the viewer - from the screen is ignored. - - On handheld devices that use accelerometers to determine the - orientation of the device, the down vector due to gravity - can be adjusted to serve as a motion tracking vector. - - The output of motion tracking hardware can be very noisy, - with minor fluctuations due to viewer twitch movements or - environmental factors. The application is responsible for - cleaning up the signal and removing these fluctuations before - setMotionAdjustment() is called. - - \section1 Stereo projections - - QGLCamera can adjust the camera position for rendering separate left - and right eye images by setting eyeSeparation() to a non-zero value. - The eyeSeparation() is in world co-ordinates. - - Objects that are placed at center() will coincide in the left and - right eye images, establishing the logical center of the stereo - effect. Objects that are closer to the eye() will be rendered - to appear closer in the stereo effect, and objects that are further - away from eye() than center() will be rendered to appear further away. - - Perspective and Orthographic projections incorporate the - eyeSeparation() into the modelViewMatrix() by altering the - eye() position. - - \sa QGLView, QGLPainter -*/ - -/*! - \qmlclass Camera QGLCamera - \brief The Camera item defines the viewing position and projection for a 3D scene. - \since 4.8 - \ingroup qt3d::qml3d - - Camera instances are defined on a \l Viewport item using the - Viewport::camera property: - - \code - import QtQuick 1.0 - import Qt3D 1.0 - - Viewport { - width: 640; height: 480 - camera: Camera { - eye: Qt.vector3d(-1, 2, 10) - } - light: Light {} - Item3D { - mesh: Mesh { source: "meshes/teapot.bez" } - effect: Effect {} - } - } - \endcode - - \section1 Positioning and orienting the view - - The viewer position and orientation are defined by \l eye, \l center, - and \l upVector. The location of the viewer in world co-ordinates is - given by \l eye, the viewer is looking at the object of interest located - at \l center, and the \l upVector specifies the direction that should - be considered "up" with respect to the viewer. - - The vector from the \l eye to the \l center is called the "view vector", - and the cross-product of the view vector and \l upVector is called - the "side vector". The view vector specifies the direction the - viewer is looking, and the side vector points off to the right of - the viewer. - - It is recommended that the view vector and \l upVector be at right angles - to each other, but this is not required as long as the angle between - them is close to 90 degrees. - - The most common use of view and up vectors that are not at right angles - is to simulate a human eye at a specific height above the ground looking - down at a lower object or up at a higher object. In this case, the - the view vector will not be true horizontal, but the \l upVector - indicating the human's upright stance will be true vertical. - - \section1 Zooming the camera image - - There are two ways to zoom the image seen through the camera: either - the camera \l eye position can be moved closer to the object of interest, - or the field of view of the camera lens can be changed to make it appear - as though the object is moving closer. - - Changing the \l eye position changes the lighting calculation in the - scene because the viewer is in a different position, changing the - angle of light reflection on the object's surface. - - The \l fieldOfView property function can be used to simulate the effect - of a camera lens. The smaller the \l fieldOfView, the closer the object - will appear. The lighting calculation will be the same as for the - unzoomed scene. - - If \l fieldOfView is zero, then a standard perspective frustum of - is used to define the viewing volume based on the width and height - of the \l Viewport. - - \section1 Stereo projections - - Camera can adjust the camera position for rendering separate left - and right eye images by setting the \l eyeSeparation property - to a non-zero value. The \l eyeSeparation is in world co-ordinates. - - Objects that are placed at \l center will coincide in the left and - right eye images, establishing the logical center of the stereo - effect. Objects that are closer to the \l eye will be rendered - to appear closer in the stereo effect, and objects that are further - away from \l eye than \l center will be rendered to appear further away. - - \sa Viewport -*/ - -class QGLCameraPrivate -{ -public: - QGLCameraPrivate(); - - QGLCamera::ProjectionType projectionType; - qreal fieldOfView; - qreal nearPlane; - qreal farPlane; - QSizeF viewSize; - QSizeF minViewSize; - int screenRotation; - QVector3D eye; - QVector3D upVector; - QVector3D center; - QVector3D viewVector; - qreal eyeSeparation; - QVector3D motionAdjustment; - QQuaternion motionQuaternion; - bool adjustForAspectRatio; -}; - -QGLCameraPrivate::QGLCameraPrivate() - : projectionType(QGLCamera::Perspective), - fieldOfView(0.0f), - nearPlane(5.0f), - farPlane(1000.0f), - viewSize(2.0f, 2.0f), - minViewSize(0.0001f, 0.0001f), - screenRotation(0), - eye(0.0f, 0.0f, 10.0f), - upVector(0.0f, 1.0f, 0.0f), - center(0.0f, 0.0f, 0.0f), - viewVector(0.0f, 0.0f, -10.0f), - eyeSeparation(0.0f), - motionAdjustment(0.0f, 0.0f, 1.0f), - adjustForAspectRatio(true) -{ -} - -/*! - Constructs a QGLCamera with the default properties and - attaches it to \a parent. -*/ -QGLCamera::QGLCamera(QObject *parent) - : QObject(parent), d_ptr(new QGLCameraPrivate) -{ -} - -/*! - Destroys this QGLCamera object. -*/ -QGLCamera::~QGLCamera() -{ - delete d_ptr; -} - -/*! - \enum QGLCamera::ProjectionType - This enum defines the type of view projection to use for a QGLCamera. - - \value Perspective Use a perspective view. - \value Orthographic Use an orthographic view. -*/ - -/*! - \property QGLCamera::projectionType - \brief the projection type for this camera. The default is Perspective. -*/ - -/*! - \qmlproperty enumeration Camera::projectionType - - The projection type for this camera, which is one of: - - \list - \o Perspective Use a perspective view. This is the default. - \o Orthographic Use an orthographic view. - \endlist -*/ - -QGLCamera::ProjectionType QGLCamera::projectionType() const -{ - Q_D(const QGLCamera); - return d->projectionType; -} - -void QGLCamera::setProjectionType(QGLCamera::ProjectionType value) -{ - Q_D(QGLCamera); - if (d->projectionType != value) { - d->projectionType = value; - emit projectionChanged(); - } -} - -/*! - \property QGLCamera::fieldOfView - \brief the field of view in degrees for a perspective projection. - - The default value is zero, which indicates a standard perspective - frustum view volume of viewSize() in size. If the value is not - zero, then viewSize() is ignored. - - This value is ignored if projectionType() is not Perspective. - - \sa viewSize() -*/ - -/*! - \qmlproperty real Camera::fieldOfView - The field of view in degrees for a perspective projection. - - The default value is zero, which indicates a standard perspective - frustum view volume. - - This value is ignored if projectionType is not Perspective. - - \sa projectionType -*/ - -qreal QGLCamera::fieldOfView() const -{ - Q_D(const QGLCamera); - return d->fieldOfView; -} - -void QGLCamera::setFieldOfView(qreal angle) -{ - Q_D(QGLCamera); - if (d->fieldOfView != angle) { - d->fieldOfView = angle; - emit projectionChanged(); - } -} - -/*! - \property QGLCamera::nearPlane - \brief the distance from the eye to the near clipping plane. - The default value is 5. - - \sa farPlane() -*/ - -/*! - \qmlproperty real Camera::nearPlane - The distance from the eye to the near clipping plane. - The default value is 5. - - \sa farPlane -*/ - -qreal QGLCamera::nearPlane() const -{ - Q_D(const QGLCamera); - return d->nearPlane; -} - -void QGLCamera::setNearPlane(qreal value) -{ - Q_D(QGLCamera); - if (d->nearPlane != value) { - d->nearPlane = value; - emit projectionChanged(); - } -} - -/*! - \property QGLCamera::farPlane - \brief the distance from the eye to the far clipping plane. - The default value is 1000. - - \sa nearPlane() -*/ - -/*! - \qmlproperty real Camera::farPlane - The distance from the eye to the far clipping plane. - The default value is 1000. - - \sa nearPlane -*/ - -qreal QGLCamera::farPlane() const -{ - Q_D(const QGLCamera); - return d->farPlane; -} - -void QGLCamera::setFarPlane(qreal value) -{ - Q_D(QGLCamera); - if (d->farPlane != value) { - d->farPlane = value; - emit projectionChanged(); - } -} - -/*! - \property QGLCamera::viewSize - \brief the size of the front of the projection viewing volume. - The viewing volume is assumed to be centered on the origin. - - The default value is (2, 2), which indicates a viewing volume front - from (-1, -1) to (1, 1). - - If the width or height of the viewing volume is negative, then the - co-ordinates will be swapped. For example, a size of (2, -2) will - flip the vertical axis upside down for a viewing volume from - (-1, 1) to (1, -1). - - The view size will be further adjusted by the window's aspect ratio - when projectionMatrix() is called. For best results, the width and - height of the view size should be the same to define an ideal square - viewing volume, which is then extended to the final viewing volume - width and height based on the window's aspect ratio. - - \sa projectionMatrix(), minViewSize() -*/ -QSizeF QGLCamera::viewSize() const -{ - Q_D(const QGLCamera); - return d->viewSize; -} - -void QGLCamera::setViewSize(const QSizeF& size) -{ - Q_D(QGLCamera); - QSizeF sz(size); - if (qAbs(sz.width()) < d->minViewSize.width()) { - if (sz.width() >= 0.0f) - sz.setWidth(d->minViewSize.width()); - else - sz.setWidth(-d->minViewSize.width()); - } - if (qAbs(sz.height()) < d->minViewSize.height()) { - if (sz.height() >= 0.0f) - sz.setHeight(d->minViewSize.height()); - else - sz.setHeight(-d->minViewSize.height()); - } - if (d->viewSize != sz) { - d->viewSize = sz; - emit projectionChanged(); - } -} - -/*! - \property QGLCamera::minViewSize - \brief the minimum size of the front of the projection viewing volume. - - The minimum view size is used to clamp viewSize() when zooming - the camera closer to an object to prevent it "passing through" - the object and causing the scale factor to become infinite. - - The default value is (0.0001, 0.0001). - - \sa projectionMatrix(), viewSize() -*/ -QSizeF QGLCamera::minViewSize() const -{ - Q_D(const QGLCamera); - return d->minViewSize; -} - -void QGLCamera::setMinViewSize(const QSizeF& size) -{ - Q_D(QGLCamera); - if (d->minViewSize != size) { - d->minViewSize = size; - emit projectionChanged(); - } -} - -/*! - \property QGLCamera::screenRotation - \brief the screen rotation angle in degrees. The default - value is 0. If this value is 90 or 270, then the view - will be flipped width for height. The only supported values - are 0, 90, 180, and 270. The screen is rotated around the - positive z axis. - - This setting is intended for simple screen rotations on handheld - devices that can be held in either portrait or landscape orientations. - The entire screen image is rotated so that it can be viewed in a - different device orientation. - - Use rotateEye() or rotateCenter() for more complex rotations - that are not aligned with 0, 90, 180, or 270 degrees. -*/ - -int QGLCamera::screenRotation() const -{ - Q_D(const QGLCamera); - return d->screenRotation; -} - -void QGLCamera::setScreenRotation(int angle) -{ - Q_D(QGLCamera); - if (d->screenRotation != angle) { - d->screenRotation = angle; - emit projectionChanged(); - } -} - -/*! - \property QGLCamera::eye - \brief the position of the viewer's eye. The default value is (0, 0, 10). - - \sa translateEye(), upVector(), center(), eyeSeparation() - \sa motionAdjustment() -*/ - -/*! - \qmlproperty vector3D Camera::eye - The position of the viewer's eye. The default value is (0, 0, 10). - - \sa upVector, center, eyeSeparation -*/ -QVector3D QGLCamera::eye() const -{ - Q_D(const QGLCamera); - return d->eye; -} - -void QGLCamera::setEye(const QVector3D& vertex) -{ - Q_D(QGLCamera); - if (d->eye != vertex) { - d->eye = vertex; - d->viewVector = d->center - d->eye; - emit viewChanged(); - } -} - -/*! - Adjusts the position of the viewer's eye by the components - (\a x, \a y, \a z), where the components are interpreted relative - to the viewer's current orientation. See translation() for more - information. - - This function is accessible to QML on the Camera item. - - \sa eye(), setEye(), translateCenter() -*/ -void QGLCamera::translateEye(qreal x, qreal y, qreal z) -{ - Q_D(QGLCamera); - d->eye += translation(x, y, z); - d->viewVector = d->center - d->eye; - emit viewChanged(); -} - -/*! - \property QGLCamera::upVector - \brief the up vector for the viewer. The default value is (0, 1, 0). - - \sa eye(), center() -*/ - -/*! - \qmlproperty vector3D Camera::upVector - The up vector for the viewer. The default value is (0, 1, 0). - - \sa eye, center -*/ - -QVector3D QGLCamera::upVector() const -{ - Q_D(const QGLCamera); - return d->upVector; -} - -void QGLCamera::setUpVector(const QVector3D& vector) -{ - Q_D(QGLCamera); - if (d->upVector != vector) { - d->upVector = vector; - emit viewChanged(); - } -} - -/*! - \property QGLCamera::center - \brief the center of the view visible from the viewer's position. - The default value is (0, 0, 0). - - \sa translateCenter(), eye(), upVector() -*/ - -/*! - \qmlproperty vector3D Camera::center - The center of the view visible from the viewer's position. - The default value is (0, 0, 0). - - \sa eye, upVector -*/ - -QVector3D QGLCamera::center() const -{ - Q_D(const QGLCamera); - return d->center; -} - -void QGLCamera::setCenter(const QVector3D& vertex) -{ - Q_D(QGLCamera); - if (d->center != vertex) { - d->center = vertex; - d->viewVector = d->center - d->eye; - emit viewChanged(); - } -} - -/*! - Adjusts the center of the view by the components (\a x, \a y, \a z), - where the components are interpreted relative to the viewer's current - orientation. See translation() for more information. - - This function is accessible to QML on the Camera item. - - \sa center(), setCenter(), translateEye() -*/ -void QGLCamera::translateCenter(qreal x, qreal y, qreal z) -{ - Q_D(QGLCamera); - d->center += translation(x, y, z); - d->viewVector = d->center - d->eye; - emit viewChanged(); -} - -/*! - \property QGLCamera::eyeSeparation - \brief the separation between the eyes when stereo viewing is in use, - with eye() specifying the mid-point between the eyes. The default - value is 0. - - \sa eye() -*/ - -/*! - \qmlproperty real Camera::eyeSeparation - The separation between the eyes when stereo viewing is in use, - with \l eye property specifying the mid-point between the eyes. - The default value is 0. - - \sa eye -*/ - -qreal QGLCamera::eyeSeparation() const -{ - Q_D(const QGLCamera); - return d->eyeSeparation; -} - -void QGLCamera::setEyeSeparation(qreal value) -{ - Q_D(QGLCamera); - if (d->eyeSeparation != value) { - d->eyeSeparation = value; - emit viewChanged(); - } -} - -/*! - \property QGLCamera::motionAdjustment - \brief the adjustment vector to apply to the eye() for user motion. - - This property is typically used to implement motion tracking. - It is interpreted as a vector from the center of the screen to the - current position of the viewer. The angle between the motion - adjustment vector and the screen center is used to adjust the - position of the eye() when modelViewMatrix() is called. - - The default value is (0, 0, 1), which indicates a viewer - directly in front of the center of the screen. - - The units for the vector are unspecified. They could be - meters, centimeters, or the force due to gravity in various - directions from an accelerometer. The angle defined - by the vector is used to perform the adjustment, not its - magnitude. - - The output of motion tracking hardware can be very noisy, - with minor fluctuations due to viewer twitch movements or - environmental factors. The application is responsible for - cleaning up the signal and removing these fluctuations before - altering this property. - - \sa eye(), modelViewMatrix() -*/ - -QVector3D QGLCamera::motionAdjustment() const -{ - Q_D(const QGLCamera); - return d->motionAdjustment; -} - -void QGLCamera::setMotionAdjustment(const QVector3D& vector) -{ - Q_D(QGLCamera); - if (d->motionAdjustment != vector) { - d->motionAdjustment = vector; - if (vector.x() == 0.0f && vector.y() == 0.0f) { - // If the vector is centered, then don't perform any rotations. - d->motionQuaternion = QQuaternion(); - } else { - // Determine the pan and tilt angles from the vector. - QVector3D view = -vector.normalized(); - if (view.z() < 0.0f) - view = -view; - qreal xangle = asin(view.x()) * 180.0f / M_PI; - qreal yangle = asin(-view.y()) * 180.0f / M_PI; - - // Construct the pan and tilt quaternions. - if (qFuzzyIsNull(xangle)) - d->motionQuaternion = tilt(yangle); - else if (qFuzzyIsNull(yangle)) - d->motionQuaternion = pan(xangle); - else - d->motionQuaternion = tilt(yangle) * pan(xangle); - } - emit viewChanged(); - } -} - -/*! - \property QGLCamera::adjustForAspectRatio - \brief the adjustment state of the aspect ratio in the viewing volume. - - By default, QGLCamera adjusts the viewing volume for the aspect - ratio of the window so that pixels appear square without the - application needing to adjust viewSize() manually. - - If this property is false, then the aspect ratio adjustment is - not performed. -*/ - -/*! - \qmlproperty bool Camera::adjustForAspectRatio - The adjustment state of the aspect ratio in the viewing volume. - - By default, the camera adjusts the viewing volume for the aspect - ratio of the window so that pixels appear square without the - application needing to adjust the view size manually. - - If this property is false, then the aspect ratio adjustment is - not performed. - - \sa projectionType -*/ - -bool QGLCamera::adjustForAspectRatio() const -{ - Q_D(const QGLCamera); - return d->adjustForAspectRatio; -} - -void QGLCamera::setAdjustForAspectRatio(bool value) -{ - Q_D(QGLCamera); - if (d->adjustForAspectRatio != value) { - d->adjustForAspectRatio = value; - emit viewChanged(); - } -} - -/*! - Returns the quaternion corresponding to tilting the view up or - down by \a angle degrees. The returned quaternion can be applied to - the eye() position with rotateEye() or to the center() position with - rotateCenter(). - - \sa pan(), roll(), rotateEye(), rotateCenter() -*/ -QQuaternion QGLCamera::tilt(qreal angle) const -{ - Q_D(const QGLCamera); - QVector3D side = QVector3D::crossProduct(d->viewVector, d->upVector); - return QQuaternion::fromAxisAndAngle(side, angle); -} - -/*! - Returns the quaternion corresponding to panning the view left or - right by \a angle degrees. The returned quaternion can be applied to - the eye() position with rotateEye() or to the center() position with - rotateCenter(). - - \sa tilt(), roll(), rotateEye(), rotateCenter() -*/ -QQuaternion QGLCamera::pan(qreal angle) const -{ - Q_D(const QGLCamera); - return QQuaternion::fromAxisAndAngle(d->upVector, angle); -} - -/*! - Returns the quaternion corresponding to rolling the view left or - right by \a angle degrees. The returned quaternion can be applied to - the eye() position with rotateEye() or to the center() position with - rotateCenter(). - - \sa tilt(), pan(), rotateEye(), rotateCenter() -*/ -QQuaternion QGLCamera::roll(qreal angle) const -{ - Q_D(const QGLCamera); - return QQuaternion::fromAxisAndAngle(d->viewVector, angle); -} - -/*! - Rotates the orientation of the eye() according to the quaternion \a q. - The eye() will remain in the same position, but the upVector() and - center() may be altered by the rotation. - - \sa rotateCenter(), tilt(), pan(), roll() -*/ -void QGLCamera::rotateEye(const QQuaternion& q) -{ - Q_D(QGLCamera); - d->upVector = q.rotatedVector(d->upVector); - d->viewVector = q.rotatedVector(d->viewVector); - d->center = d->eye + d->viewVector; - emit viewChanged(); -} - -/*! - Rotates the position and orientation of the eye() around center() - according to the quaternion \a q. The center() will remain in the - same position, but the upVector() and eye() may be altered by - the rotation. - - \sa rotateEye(), tilt(), pan(), roll() -*/ -void QGLCamera::rotateCenter(const QQuaternion& q) -{ - Q_D(QGLCamera); - d->upVector = q.rotatedVector(d->upVector); - d->viewVector = q.rotatedVector(d->viewVector); - d->eye = d->center - d->viewVector; - emit viewChanged(); -} - -/*! - Returns a translation vector that can be used to adjust the eye() - or center() by \a x units side-ways, \a y units up, - and \a z units forwards. - - This function is useful when implementing operations such as - "step left", "jump up", and so on where the movement should be - interpreted relative to the viewer's current orientation, not the - world co-ordinate axes. - - The following example moves the eye() 2 units to the right of the - current eye position while keeping the same center() of interest: - - \code - camera.setEye(camera.eye() + camera.translation(2, 0, 0)); - \endcode - - \sa translateEye(), translateCenter() -*/ -QVector3D QGLCamera::translation(qreal x, qreal y, qreal z) const -{ - Q_D(const QGLCamera); - QVector3D vector(0.0f, 0.0f, 0.0f); - if (x != 0.0f) - vector += QVector3D::normal(d->viewVector, d->upVector) * x; - if (y != 0.0f) - vector += d->upVector.normalized() * y; - if (z != 0.0f) - vector += d->viewVector.normalized() * z; - return vector; -} - -/*! - Returns the transformation matrix to apply to the projection matrix - to present the scene as viewed from the camera position. - - The \a aspectRatio specifies the aspect ratio of the window the - camera view is being displayed in. An \a aspectRatio of 1 indicates that - the window is square. An \a aspectRatio greater than 1 indicates that - the window is wider than it is high. An \a aspectRatio less than 1 - indicates that the window is higher than it is wide. - - \sa modelViewMatrix() -*/ -QMatrix4x4 QGLCamera::projectionMatrix(qreal aspectRatio) const -{ - Q_D(const QGLCamera); - QMatrix4x4 m; - if (!d->adjustForAspectRatio) - aspectRatio = 1.0f; - if (d->screenRotation != 0) { - m.rotate((qreal)(d->screenRotation), 0.0f, 0.0f, 1.0f); - if (d->screenRotation == 90 || d->screenRotation == 270) { - if (aspectRatio != 0.0f) - aspectRatio = 1.0f / aspectRatio; - } - } - if (d->projectionType == Perspective && d->fieldOfView != 0.0f) { - m.perspective(d->fieldOfView, aspectRatio, - d->nearPlane, d->farPlane); - } else { - qreal halfWidth = d->viewSize.width() / 2.0f; - qreal halfHeight = d->viewSize.height() / 2.0f; - if (aspectRatio > 1.0f) { - halfWidth *= aspectRatio; - } else if (aspectRatio > 0.0f && aspectRatio < 1.0f) { - halfHeight /= aspectRatio; - } - if (d->projectionType == Perspective) { - m.frustum(-halfWidth, halfWidth, -halfHeight, halfHeight, - d->nearPlane, d->farPlane); - } else { - m.ortho(-halfWidth, halfWidth, -halfHeight, halfHeight, - d->nearPlane, d->farPlane); - } - } - return m; -} - -/*! - Returns the transformation to apply to the modelview matrix - to present the scene as viewed from the eye position. - - The \a eye parameter is used to adjust the camera's position - horizontally by half of eyeSeparation() if \a eye is QGL::LeftEye - or QGL::RightEye. - - \sa projectionMatrix() -*/ -QMatrix4x4 QGLCamera::modelViewMatrix(QGL::Eye eye) const -{ - Q_D(const QGLCamera); - QMatrix4x4 m; - QVector3D adjust; - if (eye == QGL::LeftEye) - adjust = translation(-d->eyeSeparation / 2.0f, 0.0f, 0.0f); - else if (eye == QGL::RightEye) - adjust = translation(d->eyeSeparation / 2.0f, 0.0f, 0.0f); - if (d->motionQuaternion.isIdentity()) { - m.lookAt(d->eye + adjust, d->center, d->upVector); - } else { - QVector3D up = d->motionQuaternion.rotatedVector(d->upVector); - QVector3D view = d->motionQuaternion.rotatedVector(d->viewVector); - m.lookAt(d->center - view + adjust, d->center, up); - } - return m; -} - -/*! - Maps \a point from viewport co-ordinates to eye co-ordinates. - The size of the viewport is given by \a viewportSize, and its - aspect ratio by \a aspectRatio. - - The returned vector will have its x and y components set to the - position of the point on the near plane, and the z component - set to -nearPlane(). - - This function is used for converting a mouse event's position - into eye co-ordinates within the current camera view. -*/ -QVector3D QGLCamera::mapPoint - (const QPoint& point, qreal aspectRatio, const QSize& viewportSize) const -{ - Q_D(const QGLCamera); - - // Rotate the co-ordinate system to account for the screen rotation. - int x = point.x(); - int y = point.y(); - int width = viewportSize.width(); - int height = viewportSize.height(); - if (!d->adjustForAspectRatio) - aspectRatio = 1.0f; - if (d->screenRotation == 90) { - if (aspectRatio != 0.0f) - aspectRatio = 1.0f / aspectRatio; - qSwap(x, y); - qSwap(width, height); - y = height - 1 - y; - } else if (d->screenRotation == 180) { - x = width - 1 - x; - y = height - 1 - y; - } else if (d->screenRotation == 270) { - if (aspectRatio != 0.0f) - aspectRatio = 1.0f / aspectRatio; - qSwap(x, y); - qSwap(width, height); - } - - // Determine the relative distance from the middle of the screen. - // After this xrel and yrel are typically between -1.0 and +1.0 - // (unless the point was outside the viewport). The yrel is - // flipped upside down to account for the incoming co-ordinate - // being left-handed, but the world being right-handed. - qreal xrel, yrel; - if (width) - xrel = (((qreal)(x * 2)) - (qreal)width) / (qreal)width; - else - xrel = 0.0f; - if (height) - yrel = -(((qreal)(y * 2)) - (qreal)height) / (qreal)height; - else - yrel = 0.0f; - - // Reverse the projection and return the point in world co-ordinates. - QMatrix4x4 m = projectionMatrix(aspectRatio); - QMatrix4x4 invm = m.inverted(); - return invm.map(QVector3D(xrel, yrel, -1.0f)); -} - -/*! - \fn void QGLCamera::projectionChanged() - - This signal is emitted when one of projectionType(), fieldOfView(), - nearPlane(), farPlane(), viewSize(), or screenRotation() changes, - indicating a modification to the optical properties of the camera - looking at the scene. - - \sa viewChanged() -*/ - -/*! - \fn void QGLCamera::viewChanged() - - This signal is emitted when one of eye(), upVector(), or center() - changes, indicating a modification to the viewer's position or - orientation. - - \sa projectionChanged() -*/ - -/*! - \enum QGLCamera::RotateOrder - This enum defines the order to perform a tilt, pan, and roll - of a QGLCamera eye or center. - - \value TiltPanRoll Tilt, then pan, then roll. - \value TiltRollPan Tilt, then roll, then pan. - \value PanTiltRoll Pan, then tilt, then roll. - \value PanRollTilt Pan, then roll, then tilt. - \value RollTiltPan Roll, then tilt, then pan. - \value RollPanTilt Roll, then pan, then tilt. -*/ - -/*! - Tilts the center() up or down by \a tiltAngle degrees, - pans the center() left or right by \a panAngle degrees, - and rolls the center() left or right by \a rollAngle degrees, - all in a single fluid movement. The \a order parameter - indicates the order in which to perform the rotations. - - This function is accessible to QML on the Camera item. - It is provided as a convenience for navigation items that - rotate the center in multiple directions at the same time - based on mouse movements. - - \sa tiltPanRollEye() -*/ -void QGLCamera::tiltPanRollCenter - (qreal tiltAngle, qreal panAngle, qreal rollAngle, - QGLCamera::RotateOrder order) -{ - switch (order) { - case QGLCamera::TiltPanRoll: - rotateCenter(roll(rollAngle) * pan(panAngle) * tilt(tiltAngle)); - break; - case QGLCamera::TiltRollPan: - rotateCenter(pan(panAngle) * roll(rollAngle) * tilt(tiltAngle)); - break; - case QGLCamera::PanTiltRoll: - rotateCenter(roll(rollAngle) * tilt(tiltAngle) * pan(panAngle)); - break; - case QGLCamera::PanRollTilt: - rotateCenter(tilt(tiltAngle) * roll(rollAngle) * pan(panAngle)); - break; - case QGLCamera::RollTiltPan: - rotateCenter(pan(panAngle) * tilt(tiltAngle) * roll(rollAngle)); - break; - case QGLCamera::RollPanTilt: - rotateCenter(tilt(tiltAngle) * pan(panAngle) * roll(rollAngle)); - break; - } -} - -/*! - Tilts the eye() up or down by \a tiltAngle degrees, - pans the eye() left or right by \a panAngle degrees, - and rolls the eye() left or right by \a rollAngle degrees, - all in a single fluid movement. The \a order parameter - indicates the order in which to perform the rotations. - - This function is accessible to QML on the Camera item. - It is provided as a convenience for navigation items that - rotate the eye in multiple directions at the same time - based on mouse movements. - - \sa tiltPanRollCenter() -*/ -void QGLCamera::tiltPanRollEye - (qreal tiltAngle, qreal panAngle, qreal rollAngle, - QGLCamera::RotateOrder order) -{ - switch (order) { - case QGLCamera::TiltPanRoll: - rotateEye(roll(rollAngle) * pan(panAngle) * tilt(tiltAngle)); - break; - case QGLCamera::TiltRollPan: - rotateEye(pan(panAngle) * roll(rollAngle) * tilt(tiltAngle)); - break; - case QGLCamera::PanTiltRoll: - rotateEye(roll(rollAngle) * tilt(tiltAngle) * pan(panAngle)); - break; - case QGLCamera::PanRollTilt: - rotateEye(tilt(tiltAngle) * roll(rollAngle) * pan(panAngle)); - break; - case QGLCamera::RollTiltPan: - rotateEye(pan(panAngle) * tilt(tiltAngle) * roll(rollAngle)); - break; - case QGLCamera::RollPanTilt: - rotateEye(tilt(tiltAngle) * pan(panAngle) * roll(rollAngle)); - break; - } -} - -QDebug operator<<(QDebug dbg, const QGLCamera &cam) -{ - dbg << "QGLCamera"; - if (!cam.objectName().isEmpty()) - dbg << cam.objectName(); - dbg << "\n"; - dbg << " projection:" << ( cam.projectionType() == QGLCamera::Perspective ? - "Perspective" : "Orthographic" ); - dbg << "-- viewsize:" << cam.viewSize().width() << "x" << cam.viewSize().height() << "\n"; - dbg << " near-plane:" << cam.nearPlane() << "-- far-plane:" << cam.farPlane(); - dbg << "-- field-of-view:" << cam.fieldOfView() << "\n"; - dbg << " rotation:" << cam.screenRotation() << " -- motion adjust:" << - cam.motionAdjustment() << " -- aspect adjust:" << cam.adjustForAspectRatio() << "\n"; - dbg << " eye:" << cam.eye() << "-- center:" << cam.center(); - dbg << "-- up:" << cam.upVector() << "\n"; - return dbg; -} - -QT_END_NAMESPACE diff --git a/src/threed/viewing/qglcamera.h b/src/threed/viewing/qglcamera.h deleted file mode 100644 index d943d283..00000000 --- a/src/threed/viewing/qglcamera.h +++ /dev/null @@ -1,184 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtQuick3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGLCAMERA_H -#define QGLCAMERA_H - -#include "qt3dglobal.h" -#include "qglnamespace.h" -#include <QtCore/qobject.h> -#include <QtCore/qsize.h> -#include <QtGui/qvector3d.h> -#include <QtGui/qmatrix4x4.h> -#include <QtGui/qquaternion.h> - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Qt3D) - -class QGLCameraPrivate; -class QGLPainter; - -class Q_QT3D_EXPORT QGLCamera : public QObject -{ - Q_OBJECT - Q_ENUMS(ProjectionType RotateOrder) - Q_PROPERTY(ProjectionType projectionType READ projectionType WRITE setProjectionType NOTIFY projectionChanged) - Q_PROPERTY(qreal fieldOfView READ fieldOfView WRITE setFieldOfView NOTIFY projectionChanged) - Q_PROPERTY(qreal nearPlane READ nearPlane WRITE setNearPlane NOTIFY projectionChanged) - Q_PROPERTY(qreal farPlane READ farPlane WRITE setFarPlane NOTIFY projectionChanged) - Q_PROPERTY(QSizeF viewSize READ viewSize WRITE setViewSize NOTIFY projectionChanged) - Q_PROPERTY(QSizeF minViewSize READ minViewSize WRITE setMinViewSize NOTIFY projectionChanged SCRIPTABLE false) - Q_PROPERTY(int screenRotation READ screenRotation WRITE setScreenRotation NOTIFY projectionChanged SCRIPTABLE false) - Q_PROPERTY(QVector3D eye READ eye WRITE setEye NOTIFY viewChanged) - Q_PROPERTY(QVector3D upVector READ upVector WRITE setUpVector NOTIFY viewChanged) - Q_PROPERTY(QVector3D center READ center WRITE setCenter NOTIFY viewChanged) - Q_PROPERTY(qreal eyeSeparation READ eyeSeparation WRITE setEyeSeparation NOTIFY viewChanged) - Q_PROPERTY(QVector3D motionAdjustment READ motionAdjustment WRITE setMotionAdjustment DESIGNABLE false NOTIFY viewChanged SCRIPTABLE false) - Q_PROPERTY(bool adjustForAspectRatio READ adjustForAspectRatio WRITE setAdjustForAspectRatio NOTIFY viewChanged) -public: - explicit QGLCamera(QObject *parent = 0); - ~QGLCamera(); - - enum ProjectionType - { - Perspective, - Orthographic - }; - - QGLCamera::ProjectionType projectionType() const; - void setProjectionType(QGLCamera::ProjectionType value); - - qreal fieldOfView() const; - void setFieldOfView(qreal angle); - - qreal nearPlane() const; - void setNearPlane(qreal value); - - qreal farPlane() const; - void setFarPlane(qreal value); - - QSizeF viewSize() const; - void setViewSize(const QSizeF& size); - - QSizeF minViewSize() const; - void setMinViewSize(const QSizeF& size); - - int screenRotation() const; - void setScreenRotation(int angle); - - QVector3D eye() const; - void setEye(const QVector3D& vertex); - - QVector3D upVector() const; - void setUpVector(const QVector3D& vector); - - QVector3D center() const; - void setCenter(const QVector3D& vertex); - - qreal eyeSeparation() const; - void setEyeSeparation(qreal value); - - QVector3D motionAdjustment() const; - void setMotionAdjustment(const QVector3D& vector); - - bool adjustForAspectRatio() const; - void setAdjustForAspectRatio(bool value); - - QQuaternion tilt(qreal angle) const; - QQuaternion pan(qreal angle) const; - QQuaternion roll(qreal angle) const; - - void rotateEye(const QQuaternion& q); - void rotateCenter(const QQuaternion& q); - - QVector3D translation(qreal x, qreal y, qreal z) const; - - QMatrix4x4 projectionMatrix(qreal aspectRatio) const; - QMatrix4x4 modelViewMatrix(QGL::Eye eye = QGL::NoEye) const; - - QVector3D mapPoint - (const QPoint& point, qreal aspectRatio, - const QSize& viewportSize) const; - - enum RotateOrder - { - TiltPanRoll, - TiltRollPan, - PanTiltRoll, - PanRollTilt, - RollTiltPan, - RollPanTilt - }; - -public Q_SLOTS: - void translateEye(qreal x, qreal y, qreal z); - void translateCenter(qreal x, qreal y, qreal z); - - void tiltPanRollCenter(qreal tiltAngle, qreal panAngle, qreal rollAngle, - QGLCamera::RotateOrder order = TiltPanRoll); - void tiltPanRollEye(qreal tiltAngle, qreal panAngle, qreal rollAngle, - QGLCamera::RotateOrder order = TiltPanRoll); - -Q_SIGNALS: - void projectionChanged(); - void viewChanged(); - -private: - QGLCameraPrivate *d_ptr; - - QGLCameraPrivate *d_func() const { return d_ptr; } - - Q_DISABLE_COPY(QGLCamera) -}; - -#ifndef QT_NO_DEBUG_STREAM -#include <QtCore/qdebug.h> -Q_QT3D_EXPORT QDebug operator<<(QDebug dbg, const QGLCamera &order); -#endif - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif diff --git a/src/threed/viewing/qglcameraanimation.cpp b/src/threed/viewing/qglcameraanimation.cpp deleted file mode 100644 index 7c19e96e..00000000 --- a/src/threed/viewing/qglcameraanimation.cpp +++ /dev/null @@ -1,543 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtQuick3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglcameraanimation.h" -#include "qglcamera.h" -#include <QtCore/qmath.h> - -QT_BEGIN_NAMESPACE - -/*! - \class QGLCameraAnimation - \brief The QGLCameraAnimation class implements smooth animations between two camera positions. - \since 4.8 - \ingroup qt3d - \ingroup qt3d::viewing - - QGLCameraAnimation modifies the camera() object to fall on a smooth - path between startEye(), startUpVector(), startCenter() and - endEye(), endUpVector(), endCenter. The animation will attempt to - keep the eye and center at the same relative distance from each other - throughout the animation, as though one object is flying around another. - - \sa QGLCamera -*/ - -class QGLCameraAnimationPrivate -{ -public: - enum PointOfRotation - { - Center, - CenterDual, - Eye, - EyeDual, - Both - }; - - QGLCameraAnimationPrivate() - : camera(0) - , startEye(0.0f, 0.0f, 10.f) - , startUpVector(0.0f, 1.0f, 0.0f) - , startCenter(0.0f, 0.0f, 0.0f) - , endEye(0.0f, 0.0f, 10.f) - , endUpVector(0.0f, 1.0f, 0.0f) - , endCenter(0.0f, 0.0f, 0.0f) - , duration(250) - , dirty(true) - , pointOfRotation(Both) - , lengthStart(1.0f) - , lengthEnd(1.0f) - { - } - - QGLCamera *camera; - QVector3D startEye; - QVector3D startUpVector; - QVector3D startCenter; - QVector3D endEye; - QVector3D endUpVector; - QVector3D endCenter; - int duration; - bool dirty; - QEasingCurve easingCurve; - - // Derived values for use during the animation. - PointOfRotation pointOfRotation; - QVector3D upVectorAxis; - qreal upVectorAngle; - QVector3D pointAxis; - qreal pointAngle; - QVector3D centerTranslate; - QVector3D eyeTranslate; - qreal lengthStart; - qreal lengthEnd; - - static void rotateBetween(const QVector3D &start, const QVector3D &end, - const QVector3D &defaultAxis, - QVector3D *rotationAxis, qreal *rotationAngle); - void deriveRotations(); -}; - -static inline bool fuzzyCompareVectors(const QVector3D &v1, const QVector3D &v2) -{ - return qAbs(v1.x() - v2.x()) <= 0.00001 && - qAbs(v1.y() - v2.y()) <= 0.00001 && - qAbs(v1.z() - v2.z()) <= 0.00001; -} - -// Determine how to rotate between the "start" and "end" vectors. -// We use the cross-product of the two vectors as the axis of rotation -// or "defaultAxis" if the cross-product is zero (180 degree rotation). -void QGLCameraAnimationPrivate::rotateBetween - (const QVector3D &start, const QVector3D &end, const QVector3D &defaultAxis, - QVector3D *rotationAxis, qreal *rotationAngle) -{ - QVector3D nstart = start.normalized(); - QVector3D nend = end.normalized(); - if (qFuzzyCompare(nstart, nend)) { - // Vectors are the same, so no rotation to perform. - *rotationAxis = QVector3D(0, 1, 0); - *rotationAngle = 0.0f; - } else { - QVector3D axis = QVector3D::crossProduct(nstart, nend); - if (qFuzzyIsNull(axis.x()) && qFuzzyIsNull(axis.y()) && - qFuzzyIsNull(axis.z())) { - // Vectors are probably at 180 degrees to each other. - // We can pick either direction; arbitrarily pick anti-clockwise. - *rotationAxis = defaultAxis; - *rotationAngle = 180.0f; - } else { - // Compute the smallest angle between the two vectors - // from the cosine of the angle (i.e. the dot product). - *rotationAxis = axis; - *rotationAngle = - qAcos(QVector3D::dotProduct(nstart, nend)) * 180.0f / M_PI; - } - } -} - -void QGLCameraAnimationPrivate::deriveRotations() -{ - // If the center points are the same, rotate the eye around the center. - // If the eye points are the same, rotate the center around the eye. - // If both are different, then interpolate along linear vectors. - if (qFuzzyCompare(startCenter, endCenter)) { - if (qFuzzyCompare(startEye, endEye)) { - // Center and eye both stay the same: nothing to do. - pointOfRotation = Both; - centerTranslate = QVector3D(); - eyeTranslate = QVector3D(); - } else { - // Centers are the same, rotate the eye position. - pointOfRotation = Center; - rotateBetween(startEye - startCenter, endEye - startCenter, - startUpVector, &pointAxis, &pointAngle); - lengthStart = (startEye - startCenter).length(); - lengthEnd = (endEye - startCenter).length(); - - // Rotate the start up vector to the final position. If it is - // different than the end up vector, we need to perform the - // animation in two steps: rotate eye, then rotate up. - QQuaternion q = - QQuaternion::fromAxisAndAngle(pointAxis, pointAngle); - QVector3D up = q.rotatedVector(startUpVector); - if (!fuzzyCompareVectors(startUpVector, endUpVector) && - !fuzzyCompareVectors(up, endUpVector)) { - pointOfRotation = CenterDual; - rotateBetween(up, endUpVector, endEye - endCenter, - &upVectorAxis, &upVectorAngle); - } - } - } else if (qFuzzyCompare(startEye, endEye)) { - // Eyes are the same, rotate the center position. - pointOfRotation = Eye; - rotateBetween(startCenter - startEye, endCenter - startEye, - startUpVector, &pointAxis, &pointAngle); - lengthStart = (startCenter - startEye).length(); - lengthEnd = (startCenter - endEye).length(); - - // Rotate the start up vector to the final position. If it is - // different than the end up vector, we need to perform the - // animation in two steps: rotate eye, then rotate up. - QQuaternion q = - QQuaternion::fromAxisAndAngle(pointAxis, pointAngle); - QVector3D up = q.rotatedVector(startUpVector); - if (!fuzzyCompareVectors(startUpVector, endUpVector) && - !fuzzyCompareVectors(up, endUpVector)) { - pointOfRotation = EyeDual; - rotateBetween(up, endUpVector, endCenter - endEye, - &upVectorAxis, &upVectorAngle); - } - } else { - // Both center and eye are changing, so perform a linear translation. - pointOfRotation = Both; - centerTranslate = endCenter - startCenter; - eyeTranslate = endEye - startEye; - } - - // If we are doing a single movement, then determine how to - // rotate the up vector during the movement. - if (pointOfRotation != CenterDual) { - rotateBetween(startUpVector, endUpVector, startCenter - startEye, - &upVectorAxis, &upVectorAngle); - } -} - -/*! - Constructs a new camera animation object and attaches it to \a parent. -*/ -QGLCameraAnimation::QGLCameraAnimation(QObject *parent) - : QAbstractAnimation(parent) - , d_ptr(new QGLCameraAnimationPrivate) -{ -} - -/*! - Destroys this camera animation object. -*/ -QGLCameraAnimation::~QGLCameraAnimation() -{ -} - -/*! - \property QGLCameraAnimation::camera - \brief the camera that will be animated by this animation object; - null if the camera has not yet been set. -*/ - -QGLCamera *QGLCameraAnimation::camera() const -{ - Q_D(const QGLCameraAnimation); - return d->camera; -} - -void QGLCameraAnimation::setCamera(QGLCamera *camera) -{ - Q_D(QGLCameraAnimation); - d->camera = camera; -} - -/*! - \property QGLCameraAnimation::startEye - \brief the position of the viewer's eye at the start of the animation. - The default value is (0, 0, 10). - - \sa startUpVector(), startCenter(), endEye() -*/ - -QVector3D QGLCameraAnimation::startEye() const -{ - Q_D(const QGLCameraAnimation); - return d->startEye; -} - -void QGLCameraAnimation::setStartEye(const QVector3D &eye) -{ - Q_D(QGLCameraAnimation); - d->startEye = eye; - d->dirty = true; -} - -/*! - \property QGLCameraAnimation::startUpVector - \brief the up vector for the viewer at the start of the animation. - The default value is (0, 1, 0). - - \sa startEye(), startCenter(), endUpVector() -*/ - -QVector3D QGLCameraAnimation::startUpVector() const -{ - Q_D(const QGLCameraAnimation); - return d->startUpVector; -} - -void QGLCameraAnimation::setStartUpVector(const QVector3D &upVector) -{ - Q_D(QGLCameraAnimation); - d->startUpVector = upVector; - d->dirty = true; -} - -/*! - \property QGLCameraAnimation::startCenter - \brief the center of the view visible from the viewer's position - at the start of the animation. The default value is (0, 0, 0). - - \sa startEye(), startUpVector(), endCenter() -*/ - -QVector3D QGLCameraAnimation::startCenter() const -{ - Q_D(const QGLCameraAnimation); - return d->startCenter; -} - -void QGLCameraAnimation::setStartCenter(const QVector3D ¢er) -{ - Q_D(QGLCameraAnimation); - d->startCenter = center; - d->dirty = true; -} - -/*! - \property QGLCameraAnimation::endEye - \brief the position of the viewer's eye at the end of the animation. - The default value is (0, 0, 10). - - \sa endUpVector(), endCenter(), startEye() -*/ - -QVector3D QGLCameraAnimation::endEye() const -{ - Q_D(const QGLCameraAnimation); - return d->endEye; -} - -void QGLCameraAnimation::setEndEye(const QVector3D &eye) -{ - Q_D(QGLCameraAnimation); - d->endEye = eye; - d->dirty = true; -} - -/*! - \property QGLCameraAnimation::endUpVector - \brief the up vector for the viewer at the end of the animation. - The default value is (0, 1, 0). - - \sa endEye(), endCenter(), startUpVector() -*/ - -QVector3D QGLCameraAnimation::endUpVector() const -{ - Q_D(const QGLCameraAnimation); - return d->endUpVector; -} - -void QGLCameraAnimation::setEndUpVector(const QVector3D &upVector) -{ - Q_D(QGLCameraAnimation); - d->endUpVector = upVector; - d->dirty = true; -} - -/*! - \property QGLCameraAnimation::endCenter - \brief the center of the view visible from the viewer's position - at the end of the animation. The default value is (0, 0, 0). - - \sa endEye(), endUpVector(), startCenter() -*/ - -QVector3D QGLCameraAnimation::endCenter() const -{ - Q_D(const QGLCameraAnimation); - return d->endCenter; -} - -void QGLCameraAnimation::setEndCenter(const QVector3D ¢er) -{ - Q_D(QGLCameraAnimation); - d->endCenter = center; - d->dirty = true; -} - -/*! - \property QGLCameraAnimation::duration - \brief the duration of the animation in milliseconds. The default - value is 250 milliseconds. - - \sa easingCurve() -*/ - -int QGLCameraAnimation::duration() const -{ - Q_D(const QGLCameraAnimation); - return d->duration; -} - -void QGLCameraAnimation::setDuration(int duration) -{ - Q_D(QGLCameraAnimation); - d->duration = duration; -} - -/*! - \property QGLCameraAnimation::easingCurve - \brief the easing curve to use for the animation. The default - value is a linear easing curve. - - \sa duration() -*/ - -QEasingCurve QGLCameraAnimation::easingCurve() const -{ - Q_D(const QGLCameraAnimation); - return d->easingCurve; -} - -void QGLCameraAnimation::setEasingCurve(const QEasingCurve &easing) -{ - Q_D(QGLCameraAnimation); - d->easingCurve = easing; -} - -/*! - \internal -*/ -void QGLCameraAnimation::updateCurrentTime(int currentTime) -{ - Q_D(QGLCameraAnimation); - if (!d->camera) - return; // Nothing to do if no camera to modify. - if (currentTime >= d->duration) { - d->camera->setEye(d->endEye); - d->camera->setUpVector(d->endUpVector); - d->camera->setCenter(d->endCenter); - } else if (currentTime <= 0) { - d->camera->setEye(d->startEye); - d->camera->setUpVector(d->startUpVector); - d->camera->setCenter(d->startCenter); - } else { - // Derive the rotation parameters we need if arguments have changed. - if (d->dirty) { - d->dirty = false; - d->deriveRotations(); - } - - // Calculate the progress and modify it with the easing curve. - qreal progress = d->easingCurve.valueForProgress - (qreal(currentTime) / qreal(d->duration)); - - // Calculate the new eye and center locations. - QVector3D eye = d->startEye; - QVector3D center = d->startCenter; - QVector3D upVector = d->startUpVector; - if (d->pointOfRotation == QGLCameraAnimationPrivate::Center) { - QQuaternion q = QQuaternion::fromAxisAndAngle - (d->pointAxis, d->pointAngle * progress); - eye = q.rotatedVector(eye - d->startCenter); - if (d->lengthStart != d->lengthEnd) { - qreal length = (1.0f - progress) * d->lengthStart + - progress * d->lengthEnd; - eye = eye.normalized() * length; - } - eye += d->startCenter; - } else if (d->pointOfRotation == QGLCameraAnimationPrivate::CenterDual) { - if (progress < 0.5f) { - // First half of the animation - rotate the eye position. - QQuaternion q = QQuaternion::fromAxisAndAngle - (d->pointAxis, d->pointAngle * progress * 2.0f); - eye = q.rotatedVector(eye - d->startCenter); - if (d->lengthStart != d->lengthEnd) { - qreal length = (1.0f - progress) * d->lengthStart + - progress * d->lengthEnd; - eye = eye.normalized() * length; - } - eye += d->startCenter; - upVector = q.rotatedVector(upVector); - } else { - // Second half of the animation - rotate the up vector. - QQuaternion q = QQuaternion::fromAxisAndAngle - (d->upVectorAxis, - d->upVectorAngle * (progress - 0.5f) * 2.0f) * - QQuaternion::fromAxisAndAngle - (d->pointAxis, d->pointAngle); - eye = d->endEye; - upVector = q.rotatedVector(upVector); - } - } else if (d->pointOfRotation == QGLCameraAnimationPrivate::Eye) { - QQuaternion q = QQuaternion::fromAxisAndAngle - (d->pointAxis, d->pointAngle * progress); - center = q.rotatedVector(center - d->startEye); - if (d->lengthStart != d->lengthEnd) { - qreal length = (1.0f - progress) * d->lengthStart + - progress * d->lengthEnd; - center = center.normalized() * length; - } - center += d->startEye; - } else if (d->pointOfRotation == QGLCameraAnimationPrivate::EyeDual) { - if (progress < 0.5f) { - // First half of the animation - rotate the center position. - QQuaternion q = QQuaternion::fromAxisAndAngle - (d->pointAxis, d->pointAngle * progress * 2.0f); - center = q.rotatedVector(center - d->startEye); - if (d->lengthStart != d->lengthEnd) { - qreal length = (1.0f - progress) * d->lengthStart + - progress * d->lengthEnd; - center = center.normalized() * length; - } - center += d->startEye; - upVector = q.rotatedVector(upVector); - } else { - // Second half of the animation - rotate the up vector. - QQuaternion q = QQuaternion::fromAxisAndAngle - (d->upVectorAxis, - d->upVectorAngle * (progress - 0.5f) * 2.0f) * - QQuaternion::fromAxisAndAngle - (d->pointAxis, d->pointAngle); - center = d->endCenter; - upVector = q.rotatedVector(upVector); - } - } else { - eye += d->eyeTranslate * progress; - center += d->centerTranslate * progress; - } - - // Calculate the new up vector for single-step animations. - if (d->pointOfRotation != QGLCameraAnimationPrivate::CenterDual && - d->pointOfRotation != QGLCameraAnimationPrivate::EyeDual) { - if (d->upVectorAngle != 0.0f) { - QQuaternion q = QQuaternion::fromAxisAndAngle - (d->upVectorAxis, d->upVectorAngle * progress); - upVector = q.rotatedVector(upVector); - } - } - - d->camera->setEye(eye); - d->camera->setUpVector(upVector); - d->camera->setCenter(center); - } -} - -QT_END_NAMESPACE diff --git a/src/threed/viewing/qglcameraanimation.h b/src/threed/viewing/qglcameraanimation.h deleted file mode 100644 index e77e6a61..00000000 --- a/src/threed/viewing/qglcameraanimation.h +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtQuick3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGLCAMERAANIMATION_H -#define QGLCAMERAANIMATION_H - -#include <QtCore/qabstractanimation.h> -#include <QtCore/qeasingcurve.h> -#include <QtGui/qvector3d.h> -#include "qt3dglobal.h" - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Qt3D) - -class QGLCamera; -class QGLCameraAnimationPrivate; - -class Q_QT3D_EXPORT QGLCameraAnimation : public QAbstractAnimation -{ - Q_OBJECT - Q_PROPERTY(QGLCamera *camera READ camera WRITE setCamera) - Q_PROPERTY(QVector3D startEye READ startEye WRITE setStartEye) - Q_PROPERTY(QVector3D startUpVector READ startUpVector WRITE setStartUpVector) - Q_PROPERTY(QVector3D startCenter READ startCenter WRITE setStartCenter) - Q_PROPERTY(QVector3D endEye READ endEye WRITE setEndEye) - Q_PROPERTY(QVector3D endUpVector READ endUpVector WRITE setEndUpVector) - Q_PROPERTY(QVector3D endCenter READ endCenter WRITE setEndCenter) - Q_PROPERTY(int duration READ duration WRITE setDuration) - Q_PROPERTY(QEasingCurve easingCurve READ easingCurve WRITE setEasingCurve) -public: - explicit QGLCameraAnimation(QObject *parent = 0); - ~QGLCameraAnimation(); - - QGLCamera *camera() const; - void setCamera(QGLCamera *camera); - - QVector3D startEye() const; - void setStartEye(const QVector3D &eye); - - QVector3D startUpVector() const; - void setStartUpVector(const QVector3D &upVector); - - QVector3D startCenter() const; - void setStartCenter(const QVector3D ¢er); - - QVector3D endEye() const; - void setEndEye(const QVector3D &eye); - - QVector3D endUpVector() const; - void setEndUpVector(const QVector3D &upVector); - - QVector3D endCenter() const; - void setEndCenter(const QVector3D ¢er); - - int duration() const; - void setDuration(int duration); - - QEasingCurve easingCurve() const; - void setEasingCurve(const QEasingCurve &easing); - -protected: - void updateCurrentTime(int currentTime); - -private: - QScopedPointer<QGLCameraAnimationPrivate> d_ptr; - - Q_DISABLE_COPY(QGLCameraAnimation) - Q_DECLARE_PRIVATE(QGLCameraAnimation) -}; - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif diff --git a/src/threed/viewing/qglview.cpp b/src/threed/viewing/qglview.cpp deleted file mode 100644 index f22314f1..00000000 --- a/src/threed/viewing/qglview.cpp +++ /dev/null @@ -1,1496 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtQuick3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qglview.h" -#include "qglframebufferobject.h" -#include "qglsubsurface.h" -#include "qglmaskedsurface_p.h" -#include "qglwidgetsurface.h" -#include "qgldrawbuffersurface_p.h" -#include "qray3d.h" -#include <QtGui/qevent.h> -#include <QtCore/qmap.h> -#include <QtGui/qapplication.h> -#include <QtCore/qtimer.h> -#include <QtCore/qdatetime.h> -#include <QtCore/qdebug.h> - -QT_BEGIN_NAMESPACE - -/*! - \class QGLView - \brief The QGLView class extends QGLWidget with support for 3D viewing. - \since 4.8 - \ingroup qt3d - \ingroup qt3d::viewing - - \section1 Navigating - - Navigation in 3D space is possible under keyboard and mouse control. - - Holding down the left mouse button and dragging it will rotate the - camera() position around the object being viewed. Holding down the - left mouse button and the Shift key pans the view in a plane without - rotating the viewed object. - - Using the mouse wheel, the view can be zoomed in or out. If the - system does not have a mouse wheel, then holding down the left mouse - button and the Control key and moving the mouse up and down will - also zoom in and out. - - On the keyboard, the left, right, up, and down keys can also be used - to shift the camera() position around the object being viewed. Shift - and Control modify keys the same way they modify the left mouse - button above. Hitting the Home key will cause the camera position - to be reset to its original position. - - \section1 Stereo viewing support - - Note - Stereo viewing is experimental and unsupported. - - If the hardware supports stereo buffers, then each time the scene needs - to be painted, QGLView renders it twice: first from the perspective of - the left eye, and then from the perspective of the right eye. - The separation between the eye positions is specified by - QGLCamera::eyeSeparation(). If the eye separation is zero, - then stereo viewing is disabled and only a single image will - be rendered per frame. - - Three kinds of stereo viewing are possible: hardware stereo, - anaglyph stereo, and double image stereo. - - Hardware stereo relies upon specialized hardware that can render - the left and right eye images into separate buffers and then show - them independently to each eye through the use of polarized glasses - or similar technology. Hardware stereo is used if the \c{-stereo-hw} - command-line option is supplied or if the user explicitly requests - stereo buffers when the QGLView is constructed: - - \code - QGLFormat format(QGLFormat::defaultFormat()); - format.setOption(QGL::StereoBuffers); - QGLView view(format); - \endcode - - Anaglyph stereo is used when the hardware doesn't have specialized - stereo buffer support. The left eye image is masked by a red - filter and the right eye image is masked by a cyan filter. This makes - the resulting images suitable for viewing with standard red-cyan - anaglyph glasses. - - When using red-cyan anaglyphs, it is recommended that the - scene use non-primary object colors. Pure primary colors such - as red, green, and blue will only appear to one of the viewer's - eyes and will inhibit the 3D effect. Non-primary colors or - grayscale should be used to get the best effects. - - Red-cyan anaglyphs can be disorienting to some viewers. If hardware - stereo is not available and stereo viewing is not critical to - the application, then stereo can be disabled by setting - QGLCamera::eyeSeparation() to zero. - - Double image stereo involves drawing the left and right eye - images in a double-wide or double-high window, with the hardware - combining the images. Four different configurations are available: - LeftRight, RightLeft, TopBottom, - and BottomTop, according to the layout of the eye images. - Double image stereo is selected by calling setStereoType(). It is - the responsibility of the application to resize the window to - twice its normal size to accommodate the images. - - Ctrl-Left and Ctrl-Right can be used to make the eye separation - smaller or larger under keyboard control. - - A number of command-line options are available to select the - stereo mode of the QGLView so that the application does not - need to select the mode itself: - - \table - \row \o \c{-stereo-hw} \o \l Hardware. - \row \o \c{-stereo-lr} \o LeftRight. - \row \o \c{-stereo-rl} \o RightLeft. - \row \o \c{-stereo-tb} \o TopBottom. - \row \o \c{-stereo-bt} \o BottomTop. - \row \o \c{-stereo-stretched-lr} \o StretchedLeftRight. - \row \o \c{-stereo-stretched-rl} \o StretchedRightLeft. - \row \o \c{-stereo-stretched-tb} \o StretchedTopBottom. - \row \o \c{-stereo-stretched-bt} \o StretchedBottomTop. - \endtable - - The option can also be supplied in the \c{Quick3D_OPTIONS} environment - variable: - - \code - $ Quick3D_OPTIONS="-stereo-lr" ./cubehouse - \endcode - - If the application sets the stereo type with setStereoType(), - that will be used. Next is the command-line setting, and finally - the contents of the environment variable. -*/ - -/*! - \enum QGLView::Option - This enum defines an option for QGLView. - - \value ObjectPicking Object picking is enabled. Disabled by default. - \value ShowPicking Objects are rendered with their pick colors instead - of their normal colors and materials. This can help debug - problems with object picking. Disabled by default. - \value CameraNavigation Camera navigation using the keyboard and mouse - is enabled. Enabled by default. - \omitvalue PaintingLog - \value FOVZoom Enables zooming by changing field of view instead of - physically moving the camera. -*/ - -/*! - \enum QGLView::StereoType - This enum defines the type of stereo viewing technology being used by QGLView. - - \value Hardware Specialized stereo hardware is being used. - \value RedCyanAnaglyph Stereo is being simulated for viewing by - red-cyan anaglyph classes. - \value LeftRight The view is double-wide with the left eye - image on the left of the window. - \value RightLeft The view is double-wide with the left eye - image on the right of the window. - \value TopBottom The view is double-high with the left eye - image on the top of the window. - \value BottomTop The view is double-high with the left eye - image on the bottom of the window. - \value StretchedLeftRight Same as LeftRight, but with the - left and right eye images stretched to double their width. - \value StretchedRightLeft Same as RightLeft, but with the - left and right eye images stretched to double their width. - \value StretchedTopBottom Same as TopBottom, but with the - left and right eye images stretched to double their height. - \value StretchedBottomTop Same as BottomTop, but with the - left and right eye images stretched to double their height. -*/ - -class QGLViewPrivate -{ -public: - QGLViewPrivate(QGLView *parent) - : view(parent), mainSurface(parent) - { - options = QGLView::CameraNavigation; - fbo = 0; - leftSurface = 0; - rightSurface = 0; - - if (parent->format().stereo()) - stereoType = QGLView::Hardware; - else - stereoType = QGLView::RedCyanAnaglyph; - - pickBufferForceUpdate = true; - pickBufferMaybeInvalid = true; - updateQueued = false; - - pressedObject = 0; - pressedButton = Qt::NoButton; - enteredObject = 0; - - defaultCamera = new QGLCamera(parent); - camera = defaultCamera; - - panning = false; - startPan = QPoint(-1, -1); - lastPan = QPoint(-1, -1); - panModifiers = Qt::NoModifier; - QObject::connect(defaultCamera, SIGNAL(projectionChanged()), - parent, SLOT(cameraChanged())); - QObject::connect(defaultCamera, SIGNAL(viewChanged()), - parent, SLOT(cameraChanged())); - - logTime.start(); - lastFrameTime.start(); - QByteArray env = qgetenv("Quick3D_LOG_EVENTS"); - if (env == "1") - options |= QGLView::PaintingLog; - } - ~QGLViewPrivate() - { - delete fbo; - delete leftSurface; - delete rightSurface; - } - - QGLView *view; - QGLView::Options options; - QGLView::StereoType stereoType; - QGLFramebufferObject *fbo; - QGLWidgetSurface mainSurface; - QGLAbstractSurface *leftSurface; - QGLAbstractSurface *rightSurface; - bool pickBufferForceUpdate; - bool pickBufferMaybeInvalid; - bool updateQueued; - QMap<int, QObject *> objects; - QObject *pressedObject; - Qt::MouseButton pressedButton; - QObject *enteredObject; - QGLCamera *defaultCamera; - QGLCamera *camera; - bool panning; - QPoint startPan; - QPoint lastPan; - QVector3D startEye; - QVector3D startCenter; - QVector3D startUpVector; - Qt::KeyboardModifiers panModifiers; - QTime logTime; - QTime enterTime; - QTime lastFrameTime; - - inline void logEnter(const char *message); - inline void logLeave(const char *message); - - void processStereoOptions(QGLView *view); - void processStereoOptions(QGLView *view, const QString &arg); - - QGLAbstractSurface *leftEyeSurface(const QSize &size); - QGLAbstractSurface *rightEyeSurface(const QSize &size); - QGLAbstractSurface *bothEyesSurface(); -}; - -inline void QGLViewPrivate::logEnter(const char *message) -{ - if ((options & QGLView::PaintingLog) == 0) - return; - int ms = logTime.elapsed(); - enterTime.start(); - int sinceLast = lastFrameTime.restart(); - qDebug("LOG[%d:%02d:%02d.%03d]: ENTER: %s (%d ms since last enter)", - ms / 3600000, (ms / 60000) % 60, - (ms / 1000) % 60, ms % 1000, message, sinceLast); -} - -inline void QGLViewPrivate::logLeave(const char *message) -{ - if ((options & QGLView::PaintingLog) == 0) - return; - int ms = logTime.elapsed(); - int duration = enterTime.elapsed(); - qDebug("LOG[%d:%02d:%02d.%03d]: LEAVE: %s (%d ms elapsed)", - ms / 3600000, (ms / 60000) % 60, - (ms / 1000) % 60, ms % 1000, message, duration); -} - -static QString qt_gl_stereo_arg() -{ - QStringList args = QApplication::arguments(); - foreach (QString arg, args) { - if (arg.startsWith(QLatin1String("-stereo-"))) - return arg; - } - QByteArray options(qgetenv("Quick3D_OPTIONS")); - args = QString::fromLocal8Bit - (options.constData(), options.size()).split(QLatin1Char(' ')); - foreach (QString arg, args) { - if (arg.startsWith(QLatin1String("-stereo-"))) - return arg; - } - return QString(); -} - -void QGLViewPrivate::processStereoOptions(QGLView *view) -{ - if (stereoType == QGLView::Hardware) - return; - QString arg = qt_gl_stereo_arg(); - if (!arg.isEmpty()) - processStereoOptions(view, arg); -} - -void QGLViewPrivate::processStereoOptions(QGLView *view, const QString &arg) -{ - // If the command-line contains an option that starts with "-stereo-", - // then convert it into options that define the size and type of - // stereo window to use for a top-level QGLView. Possible options: - // - // hw - use hardware stereo - // lr, rl, tb, bt - specify the eye order (default is left-right) - // stretched - used stretched versions of double wide/high modes. - // - QStringList opts = arg.mid(8).split(QLatin1Char('-')); - QGLView::StereoType stereoType; - bool stretched = opts.contains(QLatin1String("stretched")); - if (opts.contains(QLatin1String("rl"))) { - stereoType = stretched ? QGLView::StretchedRightLeft : QGLView::RightLeft; - } else if (opts.contains(QLatin1String("tb"))) { - stereoType = stretched ? QGLView::StretchedTopBottom : QGLView::TopBottom; - } else if (opts.contains(QLatin1String("bt"))) { - stereoType = stretched ? QGLView::StretchedBottomTop : QGLView::BottomTop; - } else { - stereoType = stretched ? QGLView::StretchedLeftRight : QGLView::LeftRight; - } - view->setStereoType(stereoType); -} - -class QGLViewSubsurface : public QGLSubsurface -{ -public: - QGLViewSubsurface(QGLAbstractSurface *surface, const QRect ®ion, - qreal adjust) - : QGLSubsurface(surface, region), m_adjust(adjust) {} - - qreal aspectRatio() const; - -private: - qreal m_adjust; -}; - -qreal QGLViewSubsurface::aspectRatio() const -{ - return QGLSubsurface::aspectRatio() * m_adjust; -} - -// Returns the surface to use to render the left eye image. -QGLAbstractSurface *QGLViewPrivate::leftEyeSurface(const QSize &size) -{ - QRect viewport; - qreal adjust = 1.0f; - switch (stereoType) { - case QGLView::Hardware: -#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT) - if (!leftSurface) { - leftSurface = new QGLDrawBufferSurface - (&mainSurface, - view->doubleBuffer() ? GL_BACK_LEFT : GL_FRONT_LEFT); - } - return leftSurface; -#endif - case QGLView::RedCyanAnaglyph: - if (!leftSurface) { - leftSurface = new QGLMaskedSurface - (&mainSurface, - QGLMaskedSurface::RedMask | QGLMaskedSurface::AlphaMask); - } - return leftSurface; - case QGLView::LeftRight: - viewport = QRect(0, 0, size.width() / 2, size.height()); - break; - case QGLView::RightLeft: - viewport = QRect(size.width() / 2, 0, size.width() / 2, size.height()); - break; - case QGLView::TopBottom: - viewport = QRect(0, 0, size.width(), size.height() / 2); - break; - case QGLView::BottomTop: - viewport = QRect(0, size.height() / 2, size.width(), size.height() / 2); - break; - case QGLView::StretchedLeftRight: - viewport = QRect(0, 0, size.width() / 2, size.height()); - adjust = 2.0f; - break; - case QGLView::StretchedRightLeft: - viewport = QRect(size.width() / 2, 0, size.width() / 2, size.height()); - adjust = 2.0f; - break; - case QGLView::StretchedTopBottom: - viewport = QRect(0, 0, size.width(), size.height() / 2); - adjust = 0.5f; - break; - case QGLView::StretchedBottomTop: - viewport = QRect(0, size.height() / 2, size.width(), size.height() / 2); - adjust = 0.5f; - break; - } - if (!leftSurface) { - if (adjust == 1.0f) - leftSurface = new QGLSubsurface(&mainSurface, viewport); - else - leftSurface = new QGLViewSubsurface(&mainSurface, viewport, adjust); - } else { - static_cast<QGLSubsurface *>(leftSurface)->setRegion(viewport); - } - return leftSurface; -} - -// Returns the surface to use to render the right eye image. -QGLAbstractSurface *QGLViewPrivate::rightEyeSurface(const QSize &size) -{ - QRect viewport; - qreal adjust = 1.0f; - switch (stereoType) { - case QGLView::Hardware: -#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT) - if (!rightSurface) { - rightSurface = new QGLDrawBufferSurface - (&mainSurface, - view->doubleBuffer() ? GL_BACK_RIGHT : GL_FRONT_RIGHT); - } - return rightSurface; -#endif - case QGLView::RedCyanAnaglyph: - if (!rightSurface) { - rightSurface = new QGLMaskedSurface - (&mainSurface, - QGLMaskedSurface::GreenMask | QGLMaskedSurface::BlueMask); - } - return rightSurface; - case QGLView::LeftRight: - viewport = QRect(size.width() / 2, 0, size.width() / 2, size.height()); - break; - case QGLView::RightLeft: - viewport = QRect(0, 0, size.width() / 2, size.height()); - break; - case QGLView::TopBottom: - viewport = QRect(0, size.height() / 2, size.width(), size.height() / 2); - break; - case QGLView::BottomTop: - viewport = QRect(0, 0, size.width(), size.height() / 2); - break; - case QGLView::StretchedLeftRight: - viewport = QRect(size.width() / 2, 0, size.width() / 2, size.height()); - adjust = 2.0f; - break; - case QGLView::StretchedRightLeft: - viewport = QRect(0, 0, size.width() / 2, size.height()); - adjust = 2.0f; - break; - case QGLView::StretchedTopBottom: - viewport = QRect(0, size.height() / 2, size.width(), size.height() / 2); - adjust = 0.5f; - break; - case QGLView::StretchedBottomTop: - viewport = QRect(0, 0, size.width(), size.height() / 2); - adjust = 0.5f; - break; - } - if (!rightSurface) { - if (adjust == 1.0f) - rightSurface = new QGLSubsurface(&mainSurface, viewport); - else - rightSurface = new QGLViewSubsurface(&mainSurface, viewport, adjust); - } else { - static_cast<QGLSubsurface *>(rightSurface)->setRegion(viewport); - } - return rightSurface; -} - -// Returns a surface that can be used to render a non-stereoscopic -// image into both eyes at the same time. Returns null if the eyes -// must be rendered one at a time. -QGLAbstractSurface *QGLViewPrivate::bothEyesSurface() -{ - switch (stereoType) { - case QGLView::Hardware: -#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT) - return 0; -#endif - case QGLView::RedCyanAnaglyph: - return &mainSurface; - default: - return 0; - } -} - -static QGLFormat makeStereoGLFormat(const QGLFormat& format) -{ -#if defined(GL_BACK_LEFT) && defined(GL_BACK_RIGHT) - QGLFormat fmt(format); - if (qt_gl_stereo_arg() == QLatin1String("-stereo-hw")) - fmt.setOption(QGL::StereoBuffers); - return fmt; -#else - QGLFormat fmt(format); - fmt.setOption(QGL::NoStereoBuffers); - return fmt; -#endif -} - -/*! - Constructs a new view widget and attaches it to \a parent. - - This constructor will request a stereo rendering context if - the hardware supports it. -*/ -QGLView::QGLView(QWidget *parent) - : QGLWidget(makeStereoGLFormat(QGLFormat::defaultFormat()), parent) -{ - d = new QGLViewPrivate(this); - setMouseTracking(true); - if (!parent) - d->processStereoOptions(this); -} - -/*! - Constructs a new view widget and attaches it to \a parent. - The \a format argument specifies the desired QGLFormat - rendering options. - - If \a format does not include the stereo option, then a stereo - viewing context will not be requested. -*/ -QGLView::QGLView(const QGLFormat& format, QWidget *parent) - : QGLWidget(format, parent) -{ - d = new QGLViewPrivate(this); - setMouseTracking(true); - if (!parent) - d->processStereoOptions(this); -} - -/*! - Destroys this view widget. -*/ -QGLView::~QGLView() -{ - delete d; -} - -/*! - Returns the options for this view. The default value is - CameraNavigation. - - \sa setOptions(), setOption() -*/ -QGLView::Options QGLView::options() const -{ - return d->options; -} - -/*! - Sets the options for this view to \a value. - - \sa options(), setOption() -*/ -void QGLView::setOptions(QGLView::Options value) -{ - d->options = value; -} - -/*! - Enables or disables \a option according to \a value. - - \sa options(), setOptions() -*/ -void QGLView::setOption(QGLView::Option option, bool value) -{ - if (value) - d->options |= option; - else - d->options &= ~option; -} - -/*! - Returns the type of stereo viewing technology that is in use. - - \sa setStereoType() -*/ -QGLView::StereoType QGLView::stereoType() const -{ - return d->stereoType; -} - -/*! - Sets the \a type of stereo viewing technology that is in use. - The request takes effect at the next repaint. - - The request is ignored stereoType() or \a type is Hardware, - because hardware stereo can only be enabled if the hardware - supports it, and then it can never be disabled. - - \sa stereoType() -*/ -void QGLView::setStereoType(QGLView::StereoType type) -{ - if (d->stereoType == Hardware || type == Hardware) - return; - if (d->stereoType == type) - return; - d->stereoType = type; - - // Destroy the current surface objects so that they will - // be re-generated the next time we paint the widget. - delete d->leftSurface; - delete d->rightSurface; - d->leftSurface = 0; - d->rightSurface = 0; -} - -/*! - Registers an \a object with this view to be notified when - \a objectId is selected with the mouse. The \a object must - persist for the lifetime of the QGLView, or until - deregisterObject() is called for \a objectId. - - \sa deregisterObject(), objectForPoint() -*/ -void QGLView::registerObject(int objectId, QObject *object) -{ - d->objects[objectId] = object; -} - -/*! - Deregisters the object associated with \a objectId. - - \sa registerObject() -*/ -void QGLView::deregisterObject(int objectId) -{ - d->objects.remove(objectId); -} - -/*! - Returns the camera parameters. The camera defines the projection - to apply to convert eye co-ordinates into window co-ordinates, - and the position and orientation of the viewer's eye. - - \sa setCamera() -*/ -QGLCamera *QGLView::camera() const -{ - return d->camera; -} - -/*! - Sets the camera parameters to \a value. The camera defines the - projection to apply to convert eye co-ordinates into window - co-ordinates, and the position and orientation of the viewer's eye. - - If \a value is null, then the default camera object will be used. - - This function will call update() to force the view to - update with the new camera parameters upon the next event loop. - - \sa camera() -*/ -void QGLView::setCamera(QGLCamera *value) -{ - if (!value) - value = d->defaultCamera; - - if (d->camera == value) - return; - - disconnect(d->camera, SIGNAL(projectionChanged()), - this, SLOT(cameraChanged())); - disconnect(d->camera, SIGNAL(viewChanged()), - this, SLOT(cameraChanged())); - - d->camera = value; - - connect(d->camera, SIGNAL(projectionChanged()), - this, SLOT(cameraChanged())); - connect(d->camera, SIGNAL(viewChanged()), - this, SLOT(cameraChanged())); - - cameraChanged(); -} - -/*! - Maps \a point from viewport co-ordinates to eye co-ordinates. - - The returned vector will have its x and y components set to the - position of the point on the near plane, and the z component - set to the inverse of the camera's near plane. - - This function is used for converting a mouse event's position - into eye co-ordinates within the current camera view. - - \sa QGLCamera::mapPoint() -*/ -QVector3D QGLView::mapPoint(const QPoint &point) const -{ - QSize viewportSize(size()); - qreal aspectRatio; - - // Get the size of the underlying paint device. - int width = viewportSize.width(); - int height = viewportSize.height(); - - // Use the device's DPI setting to determine the pixel aspect ratio. - int dpiX = logicalDpiX(); - int dpiY = logicalDpiY(); - if (dpiX <= 0 || dpiY <= 0) - dpiX = dpiY = 1; - - // Derive the aspect ratio based on window and pixel size. - if (width <= 0 || height <= 0) - aspectRatio = 1.0f; - else - aspectRatio = ((qreal)(width * dpiY)) / ((qreal)(height * dpiX)); - - // Map the point into eye co-ordinates. - return d->camera->mapPoint(point, aspectRatio, viewportSize); -} - -void QGLView::cameraChanged() -{ - // The pick buffer will need to be refreshed at the new camera position. - d->pickBufferForceUpdate = true; - - // Queue an update for the next event loop. - update(); -} - -/*! - \internal -*/ -void QGLView::initializeGL() -{ - d->logEnter("QGLView::initializeGL"); - QGLPainter painter; - painter.begin(); - - // Set the default depth buffer options. - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - glDepthMask(GL_TRUE); -#if defined(QT_OPENGL_ES) - glDepthRangef(0.0f, 1.0f); -#else - glDepthRange(0.0f, 1.0f); -#endif - - // Set the default blend options. - if (painter.hasOpenGLFeature(QOpenGLFunctions::BlendColor)) - painter.glBlendColor(0, 0, 0, 0); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - if (painter.hasOpenGLFeature(QOpenGLFunctions::BlendEquation)) - painter.glBlendEquation(GL_FUNC_ADD); - else if (painter.hasOpenGLFeature(QOpenGLFunctions::BlendEquationSeparate)) - painter.glBlendEquationSeparate(GL_FUNC_ADD, GL_FUNC_ADD); - - glDisable(GL_CULL_FACE); - initializeGL(&painter); - d->logLeave("QGLView::initializeGL"); -} - -/*! - \internal -*/ -void QGLView::resizeGL(int w, int h) -{ - // Set up the standard viewport for the new window size. - glViewport(0, 0, w, h); - - // We will need to regenerate the pick buffer. - d->pickBufferForceUpdate = true; -} - -/*! - \internal -*/ -void QGLView::paintGL() -{ - d->logEnter("QGLView::paintGL"); - // We may need to regenerate the pick buffer on the next mouse event. - d->pickBufferMaybeInvalid = true; - - // Paint the scene contents. - QGLPainter painter; - QGLAbstractSurface *surface; - painter.begin(); - if (d->options & QGLView::ShowPicking && - d->stereoType == QGLView::RedCyanAnaglyph) { - // If showing picking, then render normally. This really - // only works if we aren't using hardware or double stereo. - painter.setPicking(true); - painter.clearPickObjects(); - painter.setEye(QGL::NoEye); - earlyPaintGL(&painter); - painter.setCamera(d->camera); - paintGL(&painter); - painter.setPicking(false); - } else if (d->camera->eyeSeparation() == 0.0f && - (surface = d->bothEyesSurface()) != 0) { - // No camera separation, so render the same image into both buffers. - painter.pushSurface(surface); - painter.setEye(QGL::NoEye); - earlyPaintGL(&painter); - painter.setCamera(d->camera); - paintGL(&painter); - painter.popSurface(); - } else { - // Paint the scene twice, from the perspective of each camera. - QSize size(this->size()); - painter.setEye(QGL::LeftEye); - if (d->stereoType != QGLView::Hardware) - earlyPaintGL(&painter); // Clear both eyes at the same time. - painter.pushSurface(d->leftEyeSurface(size)); - if (d->stereoType == QGLView::Hardware) - earlyPaintGL(&painter); // Clear the left eye only. - earlyPaintGL(&painter); - painter.setCamera(d->camera); - paintGL(&painter); - if (d->stereoType == QGLView::RedCyanAnaglyph) - glClear(GL_DEPTH_BUFFER_BIT); - painter.setEye(QGL::RightEye); - painter.setSurface(d->rightEyeSurface(size)); - if (d->stereoType == QGLView::Hardware) - earlyPaintGL(&painter); // Clear the right eye only. - painter.setCamera(d->camera); - paintGL(&painter); - painter.popSurface(); - } - d->logLeave("QGLView::paintGL"); -} - -/*! - Initializes the current GL context represented by \a painter. - - \sa paintGL() -*/ -void QGLView::initializeGL(QGLPainter *painter) -{ - Q_UNUSED(painter); -} - -/*! - Performs early painting operations just after \a painter - is initialized but before the camera is set up. The default - implementation clears the color buffer and depth buffer. - - This function is typically overridden to draw scene backdrops - on the color buffer before the rest of the scene is drawn - by paintGL(). - - \sa paintGL() -*/ -void QGLView::earlyPaintGL(QGLPainter *painter) -{ - Q_UNUSED(painter); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); -} - -/*! - \fn void QGLView::paintGL(QGLPainter *painter) - - Paints the scene onto \a painter. The color and depth buffers - will have already been cleared, and the camera() position set. - - If QGLPainter::isPicking() is set for \a painter, then the - function should paint the scene onto \a painter in - "object picking mode". The scene will be rendered into a - background buffer using flat colors so that mouse events - can determine which object lies under the mouse pointer. - - The default implementation of picking will typically just - render the scene normally. However, some applications - may wish to render a simpler scene that omits unselectable - objects and uses simpler meshes for the selectable objects. - - \sa earlyPaintGL() -*/ - -/*! - Processes the mouse press event \a e. -*/ -void QGLView::mousePressEvent(QMouseEvent *e) -{ - QObject *object; - if (!d->panning && (d->options & QGLView::ObjectPicking) != 0) - object = objectForPoint(e->pos()); - else - object = 0; - if (d->pressedObject) { - // Send the press event to the pressed object. Use a position - // of (0, 0) if the mouse is still within the pressed object, - // or (-1, -1) if the mouse is no longer within the pressed object. - QMouseEvent event - (QEvent::MouseButtonPress, - (d->pressedObject == object) ? QPoint(0, 0) : QPoint(-1, -1), - e->globalPos(), e->button(), e->buttons(), e->modifiers()); - QCoreApplication::sendEvent(d->pressedObject, &event); - } else if (object) { - // Record the object that was pressed and forward the event. - d->pressedObject = object; - d->enteredObject = 0; - d->pressedButton = e->button(); - - // Send a mouse press event for (0, 0). - QMouseEvent event(QEvent::MouseButtonPress, QPoint(0, 0), - e->globalPos(), e->button(), e->buttons(), - e->modifiers()); - QCoreApplication::sendEvent(object, &event); - } else if ((d->options & QGLView::CameraNavigation) != 0 && - e->button() == Qt::LeftButton) { - d->panning = true; - d->lastPan = d->startPan = e->pos(); - d->startEye = d->camera->eye(); - d->startCenter = d->camera->center(); - d->startUpVector = d->camera->upVector(); - d->panModifiers = e->modifiers(); -#ifndef QT_NO_CURSOR - setCursor(Qt::ClosedHandCursor); -#endif - } - QGLWidget::mousePressEvent(e); -} - -/*! - Processes the mouse release event \a e. -*/ -void QGLView::mouseReleaseEvent(QMouseEvent *e) -{ - if (d->panning && e->button() == Qt::LeftButton) { - d->panning = false; -#ifndef QT_NO_CURSOR - unsetCursor(); -#endif - } - if (d->pressedObject) { - // Notify the previously pressed object about the release. - QObject *object = objectForPoint(e->pos()); - QObject *pressed = d->pressedObject; - if (e->button() == d->pressedButton) { - d->pressedObject = 0; - d->pressedButton = Qt::NoButton; - d->enteredObject = object; - - // Send the release event to the pressed object. Use a position - // of (0, 0) if the mouse is still within the pressed object, - // or (-1, -1) if the mouse is no longer within the pressed object. - QMouseEvent event - (QEvent::MouseButtonRelease, - (pressed == object) ? QPoint(0, 0) : QPoint(-1, -1), - e->globalPos(), e->button(), e->buttons(), e->modifiers()); - QCoreApplication::sendEvent(pressed, &event); - - // Send leave and enter events if necessary. - if (object != pressed) { - sendLeaveEvent(pressed); - if (object) - sendEnterEvent(object); - } - } else { - // Some other button than the original was released. - // Forward the event to the pressed object. - QMouseEvent event - (QEvent::MouseButtonRelease, - (pressed == object) ? QPoint(0, 0) : QPoint(-1, -1), - e->globalPos(), e->button(), e->buttons(), e->modifiers()); - QCoreApplication::sendEvent(pressed, &event); - } - } - QGLWidget::mouseReleaseEvent(e); -} - -/*! - Processes the mouse double click event \a e. -*/ -void QGLView::mouseDoubleClickEvent(QMouseEvent *e) -{ - if ((d->options & QGLView::ObjectPicking) != 0) { - QObject *object = objectForPoint(e->pos()); - if (object) { - // Simulate a double click event for (0, 0). - QMouseEvent event - (QEvent::MouseButtonDblClick, QPoint(0, 0), - e->globalPos(), e->button(), e->buttons(), e->modifiers()); - QCoreApplication::sendEvent(object, &event); - } - } - QGLWidget::mouseDoubleClickEvent(e); -} - -/*! - Processes the mouse move event \a e. -*/ -void QGLView::mouseMoveEvent(QMouseEvent *e) -{ - if (d->panning) { - QPoint delta = e->pos() - d->startPan; - if (e->modifiers() == d->panModifiers) { - d->camera->setEye(d->startEye); - d->camera->setCenter(d->startCenter); - d->camera->setUpVector(d->startUpVector); - } else { - d->startPan = d->lastPan; - delta = e->pos() - d->startPan; - d->startEye = d->camera->eye(); - d->startCenter = d->camera->center(); - d->startUpVector = d->camera->upVector(); - d->panModifiers = e->modifiers(); - } - d->lastPan = e->pos(); - if ((e->modifiers() & Qt::ControlModifier) != 0) - wheel(delta.y() * -60); - else if ((e->modifiers() & Qt::ShiftModifier) != 0) - pan(delta.x(), delta.y()); - else - rotate(delta.x(), delta.y()); - } else if ((d->options & QGLView::ObjectPicking) != 0) { - QObject *object = objectForPoint(e->pos()); - if (d->pressedObject) { - // Send the move event to the pressed object. Use a position - // of (0, 0) if the mouse is still within the pressed object, - // or (-1, -1) if the mouse is no longer within the pressed object. - QMouseEvent event - (QEvent::MouseMove, - (d->pressedObject == object) ? QPoint(0, 0) : QPoint(-1, -1), - e->globalPos(), e->button(), e->buttons(), e->modifiers()); - QCoreApplication::sendEvent(d->pressedObject, &event); - } else if (object) { - if (object != d->enteredObject) { - if (d->enteredObject) - sendLeaveEvent(d->enteredObject); - d->enteredObject = object; - sendEnterEvent(d->enteredObject); - } - QMouseEvent event - (QEvent::MouseMove, QPoint(0, 0), - e->globalPos(), e->button(), e->buttons(), e->modifiers()); - QCoreApplication::sendEvent(object, &event); - } else if (d->enteredObject) { - sendLeaveEvent(d->enteredObject); - d->enteredObject = 0; - } - } - QGLWidget::mouseMoveEvent(e); -} - -/*! - Processes the leave event \a e. -*/ -void QGLView::leaveEvent(QEvent *e) -{ - if (!d->pressedObject && d->enteredObject) { - sendLeaveEvent(d->enteredObject); - d->enteredObject = 0; - } - QGLWidget::leaveEvent(e); -} - -#ifndef QT_NO_WHEELEVENT - -/*! - Processes the wheel event \a e. -*/ -void QGLView::wheelEvent(QWheelEvent *e) -{ - if ((d->options & QGLView::CameraNavigation) != 0) - wheel(e->delta()); - QGLWidget::wheelEvent(e); -} - -#endif - -/*! - Processes the key press event \a e. -*/ -void QGLView::keyPressEvent(QKeyEvent *e) -{ - QGLCamera *camera; - qreal sep; - - if ((d->options & QGLView::CameraNavigation) == 0) { - QGLWidget::keyPressEvent(e); - return; - } - switch (e->key()) { - - case Qt::Key_Escape: - case Qt::Key_Q: - { - if (parentWidget() == 0) - close(); - } - - case Qt::Key_Left: - { - if ((e->modifiers() & Qt::ShiftModifier) != 0) { - pan(-10, 0); - } else if ((e->modifiers() & Qt::ControlModifier) != 0) { - camera = this->camera(); - sep = camera->eyeSeparation(); - sep -= (sep / 10.0f); - if (sep < 0.0f) - sep = 0.0f; - camera->setEyeSeparation(sep); - e->accept(); - return; - } else { - rotate(-10, 0); - } - } - break; - - case Qt::Key_Right: - { - if ((e->modifiers() & Qt::ShiftModifier) != 0) { - pan(10, 0); - } else if ((e->modifiers() & Qt::ControlModifier) != 0) { - camera = this->camera(); - sep = camera->eyeSeparation(); - sep += (sep / 10.0f); - camera->setEyeSeparation(sep); - e->accept(); - return; - } else { - rotate(10, 0); - } - } - break; - - case Qt::Key_Up: - { - if ((e->modifiers() & Qt::ControlModifier) != 0) - wheel(120); - else if ((e->modifiers() & Qt::ShiftModifier) != 0) - pan(0, -10); - else - rotate(0, -10); - } - break; - - case Qt::Key_Down: - { - if ((e->modifiers() & Qt::ControlModifier) != 0) - wheel(-120); - else if ((e->modifiers() & Qt::ShiftModifier) != 0) - pan(0, 10); - else - rotate(0, 10); - } - break; - } - QGLWidget::keyPressEvent(e); -} - -class QGLViewPickSurface : public QGLAbstractSurface -{ -public: - QGLViewPickSurface(QGLView *view, QGLFramebufferObject *fbo, - const QSize &areaSize); - - QPaintDevice *device() const; - bool activate(QGLAbstractSurface *prevSurface); - void deactivate(QGLAbstractSurface *nextSurface); - QRect viewportGL() const; - -private: - QGLView *m_view; - QGLFramebufferObject *m_fbo; - QRect m_viewportGL; -}; - -QGLViewPickSurface::QGLViewPickSurface - (QGLView *view, QGLFramebufferObject *fbo, const QSize &areaSize) - : QGLAbstractSurface(504) - , m_view(view) - , m_fbo(fbo) - , m_viewportGL(QPoint(0, 0), areaSize) -{ -} - -QPaintDevice *QGLViewPickSurface::device() const -{ - return m_view; -} - -bool QGLViewPickSurface::activate(QGLAbstractSurface *prevSurface) -{ - Q_UNUSED(prevSurface); - if (m_fbo) - m_fbo->bind(); - return true; -} - -void QGLViewPickSurface::deactivate(QGLAbstractSurface *nextSurface) -{ - Q_UNUSED(nextSurface); - if (m_fbo) - m_fbo->release(); -} - -QRect QGLViewPickSurface::viewportGL() const -{ - return m_viewportGL; -} - -/*! - Returns the registered object that is under the mouse position - specified by \a point. This function may need to regenerate - the contents of the pick buffer by repainting the scene - with paintGL(). - - \sa registerObject() -*/ -QObject *QGLView::objectForPoint(const QPoint &point) -{ - QPoint pt(point); - - // What is the size of the drawing area after correcting for stereo? - // Also adjust the mouse position to always be in the left half. - QSize areaSize = size(); - switch (d->stereoType) { - case QGLView::LeftRight: - case QGLView::RightLeft: - areaSize = QSize(areaSize.width() / 2, areaSize.height()); - if (pt.x() >= areaSize.width()) - pt.setX(pt.x() - areaSize.width()); - break; - case QGLView::TopBottom: - case QGLView::BottomTop: - areaSize = QSize(areaSize.width(), areaSize.height() / 2); - if (pt.y() >= areaSize.height()) - pt.setY(pt.y() - areaSize.height()); - break; - case QGLView::StretchedLeftRight: - case QGLView::StretchedRightLeft: { - int halfwid = areaSize.width() / 2; - if (pt.x() >= halfwid) - pt.setX((pt.x() - halfwid) * 2); - else - pt.setX(pt.x() * 2); - break; } - case QGLView::StretchedTopBottom: - case QGLView::StretchedBottomTop: { - int halfht = areaSize.height() / 2; - if (pt.y() >= halfht) - pt.setY((pt.y() - halfht) * 2); - else - pt.setY(pt.y() * 2); - break; } - default: break; - } - - // Check the area boundaries in case a mouse move has - // moved the pointer outside the window. - if (pt.x() < 0 || pt.x() >= areaSize.width() || - pt.y() < 0 || pt.y() >= areaSize.height()) - return 0; - - // Do we need to refresh the pick buffer contents? - QGLPainter painter(this); - if (d->pickBufferForceUpdate) { - // Initialize the painter, which will make the window context current. - painter.setPicking(true); - painter.clearPickObjects(); - - // Create a framebuffer object as big as the window to act - // as the pick buffer if we are single buffered. If we are - // double-buffered, then use the window back buffer. - bool useBackBuffer = doubleBuffer(); - if (!useBackBuffer) { - QSize fbosize = QGL::nextPowerOfTwo(areaSize); - if (!d->fbo) { - d->fbo = new QGLFramebufferObject(fbosize, QGLFramebufferObject::CombinedDepthStencil); - } else if (d->fbo->size() != fbosize) { - delete d->fbo; - d->fbo = new QGLFramebufferObject(fbosize, QGLFramebufferObject::CombinedDepthStencil); - } - } - - // Render the pick version of the scene. - QGLViewPickSurface surface(this, d->fbo, areaSize); - painter.pushSurface(&surface); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - painter.setEye(QGL::NoEye); - painter.setCamera(d->camera); - paintGL(&painter); - painter.setPicking(false); - painter.popSurface(); - - // The pick buffer contents are now valid, unless we are using - // the back buffer - we cannot rely upon it being valid next time. - d->pickBufferForceUpdate = useBackBuffer; - d->pickBufferMaybeInvalid = false; - } - - // Pick the object under the mouse. - if (d->fbo) - d->fbo->bind(); - int objectId = painter.pickObject(pt.x(), areaSize.height() - 1 - pt.y()); - QObject *object = d->objects.value(objectId, 0); - if (d->fbo) - d->fbo->release(); - - // Release the framebuffer object and return. - painter.end(); - doneCurrent(); - return object; -} - -void QGLView::sendEnterEvent(QObject *object) -{ - QEvent event(QEvent::Enter); - QCoreApplication::sendEvent(object, &event); -} - -void QGLView::sendLeaveEvent(QObject *object) -{ - QEvent event(QEvent::Leave); - QCoreApplication::sendEvent(object, &event); -} - -// Zoom in and out according to the change in wheel delta. -void QGLView::wheel(int delta) -{ - if (d->options & QGLView::FOVZoom) { - //Use field-of view as zoom (much like a traditional camera) - qreal scale = qAbs(viewDelta(delta, delta).x()); - if (delta < 0) - scale = -scale; - if (scale >= 0.0f) - scale += 1.0f; - else - scale = 1.0f / (1.0f - scale); - qreal fov = d->camera->fieldOfView(); - if (fov != 0.0f) - d->camera->setFieldOfView(d->camera->fieldOfView() / scale); - else - d->camera->setViewSize(d->camera->viewSize() / scale); - } else { - // enable this to get wheel navigation that actually zooms by moving the - // camera back, as opposed to making the angle of view wider. - QVector3D viewVector= camera()->eye() - camera()->center(); - qreal zoomMag = viewVector.length(); - qreal zoomIncrement = -float(delta) / 100.0f; - if (!qFuzzyIsNull(zoomIncrement)) - { - zoomMag += zoomIncrement; - if (zoomMag < 1.0f) - zoomMag = 1.0f; - - QRay3D viewLine(camera()->center(), viewVector.normalized()); - camera()->setEye(viewLine.point(zoomMag)); - } - } - -} - -// Pan left/right/up/down without rotating about the object. -void QGLView::pan(int deltax, int deltay) -{ - QPointF delta = viewDelta(deltax, deltay); - QVector3D t = d->camera->translation(delta.x(), -delta.y(), 0.0f); - - // Technically panning the eye left should make the object appear to - // move off to the right, but this looks weird on-screen where the user - // actually thinks they are picking up the object and dragging it rather - // than moving the eye. We therefore apply the inverse of the translation - // to make it "look right". - d->camera->setEye(d->camera->eye() - t); - d->camera->setCenter(d->camera->center() - t); -} - -// Rotate about the object being viewed. -void QGLView::rotate(int deltax, int deltay) -{ - int rotation = d->camera->screenRotation(); - if (rotation == 90 || rotation == 270) { - qSwap(deltax, deltay); - } - if (rotation == 90 || rotation == 180) { - deltax = -deltax; - } - if (rotation == 180 || rotation == 270) { - deltay = -deltay; - } - qreal anglex = deltax * 90.0f / width(); - qreal angley = deltay * 90.0f / height(); - QQuaternion q = d->camera->pan(-anglex); - q *= d->camera->tilt(-angley); - d->camera->rotateCenter(q); -} - -/*! - Converts \a deltax and \a deltay into percentages of the - view width and height. Returns a QPointF containing the - percentage values, typically between -1 and 1. - - This function is typically used by subclasses to convert a - change in mouse position into a relative distance travelled - across the field of view. - - The returned value is corrected for the camera() screen - rotation and view size. -*/ -QPointF QGLView::viewDelta(int deltax, int deltay) const -{ - int w = width(); - int h = height(); - bool scaleToWidth; - qreal scaleFactor, scaleX, scaleY; - QSizeF viewSize = d->camera->viewSize(); - if (w >= h) { - if (viewSize.width() >= viewSize.height()) - scaleToWidth = true; - else - scaleToWidth = false; - } else { - if (viewSize.width() >= viewSize.height()) - scaleToWidth = false; - else - scaleToWidth = true; - } - int rotation = d->camera->screenRotation(); - if (rotation == 90 || rotation == 270) { - scaleToWidth = !scaleToWidth; - qSwap(deltax, deltay); - } - if (rotation == 90 || rotation == 180) { - deltax = -deltax; - } - if (rotation == 180 || rotation == 270) { - deltay = -deltay; - } - if (scaleToWidth) { - scaleFactor = 2.0f / viewSize.width(); - scaleX = scaleFactor * ((qreal)h) / ((qreal)w); - scaleY = scaleFactor; - } else { - scaleFactor = 2.0f / viewSize.height(); - scaleX = scaleFactor; - scaleY = scaleFactor * ((qreal)w) / ((qreal)h); - } - return QPointF(deltax * scaleX / w, deltay * scaleY / h); -} - -/*! - \fn QPointF QGLView::viewDelta(const QPoint &delta) const - \overload - - Converts the x and y components of \a delta into percentages - of the view width and height. Returns a QPointF containing - the percentage values, typically between -1 and 1. -*/ - - -QT_END_NAMESPACE diff --git a/src/threed/viewing/qglview.h b/src/threed/viewing/qglview.h deleted file mode 100644 index 444854d9..00000000 --- a/src/threed/viewing/qglview.h +++ /dev/null @@ -1,146 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtQuick3D module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** 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.1, 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. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QGLVIEW_H -#define QGLVIEW_H - -#include "qglpainter.h" -#include "qglcamera.h" - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Qt3D) - -class QGLViewPrivate; - -class Q_QT3D_EXPORT QGLView : public QGLWidget -{ - Q_OBJECT -public: - explicit QGLView(QWidget *parent=0); - explicit QGLView(const QGLFormat& format, QWidget *parent=0); - ~QGLView(); - - enum Option - { - ObjectPicking = 0x0001, - ShowPicking = 0x0002, - CameraNavigation = 0x0004, - PaintingLog = 0x0008, - FOVZoom = 0x0010 - }; - Q_DECLARE_FLAGS(Options, Option) - - QGLView::Options options() const; - void setOptions(QGLView::Options value); - void setOption(QGLView::Option option, bool value); - - enum StereoType - { - Hardware, - RedCyanAnaglyph, - LeftRight, - RightLeft, - TopBottom, - BottomTop, - StretchedLeftRight, - StretchedRightLeft, - StretchedTopBottom, - StretchedBottomTop - }; - - QGLView::StereoType stereoType() const; - void setStereoType(QGLView::StereoType type); - - void registerObject(int objectId, QObject *object); - void deregisterObject(int objectId); - QObject *objectForPoint(const QPoint &point); - - QGLCamera *camera() const; - void setCamera(QGLCamera *camera); - - QVector3D mapPoint(const QPoint &point) const; - -protected: - void initializeGL(); - void resizeGL(int w, int h); - void paintGL(); - virtual void initializeGL(QGLPainter *painter); - virtual void earlyPaintGL(QGLPainter *painter); - virtual void paintGL(QGLPainter *painter) = 0; - - void mousePressEvent(QMouseEvent *e); - void mouseReleaseEvent(QMouseEvent *e); - void mouseDoubleClickEvent(QMouseEvent *e); - void mouseMoveEvent(QMouseEvent *e); - void leaveEvent(QEvent *e); -#ifndef QT_NO_WHEELEVENT - void wheelEvent(QWheelEvent *e); -#endif - void keyPressEvent(QKeyEvent *e); - - QPointF viewDelta(int deltax, int deltay) const; - QPointF viewDelta(const QPoint &delta) const - { return viewDelta(delta.x(), delta.y()); } - -private Q_SLOTS: - void cameraChanged(); - -private: - QGLViewPrivate *d; - - static void sendEnterEvent(QObject *object); - static void sendLeaveEvent(QObject *object); - - void wheel(int delta); - void pan(int deltax, int deltay); - void rotate(int deltax, int deltay); -}; - -Q_DECLARE_OPERATORS_FOR_FLAGS(QGLView::Options) - -QT_END_NAMESPACE - -QT_END_HEADER - -#endif diff --git a/src/threed/viewing/viewing.pri b/src/threed/viewing/viewing.pri deleted file mode 100644 index a6d7f7fd..00000000 --- a/src/threed/viewing/viewing.pri +++ /dev/null @@ -1,12 +0,0 @@ -INCLUDEPATH += $$PWD -VPATH += $$PWD - -HEADERS += \ - viewing/qglcamera.h \ - viewing/qglcameraanimation.h \ - viewing/qglview.h - -SOURCES += \ - qglcamera.cpp \ - qglcameraanimation.cpp \ - qglview.cpp |