blob: 75437c9cc7515c5f06b8db4d1f45f3880cc1dd9f [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Data Visualization module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:GPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 or (at your option) any later version
** approved by the KDE Free Qt Foundation. The licenses are as published by
** the Free Software Foundation and appearing in the file LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "q3dscene_p.h"
#include "q3dcamera_p.h"
#include "q3dlight_p.h"
QT_BEGIN_NAMESPACE_DATAVISUALIZATION
/*!
* \class Q3DScene
* \inmodule QtDataVisualization
* \brief Q3DScene class provides description of the 3D scene being visualized.
* \since QtDataVisualization 1.0
*
* The 3D scene contains a single active camera and a single active light source.
* Visualized data is assumed to be at a fixed location.
*
* The 3D scene also keeps track of the viewport in which visualization rendering is done,
* the primary subviewport inside the viewport where the main 3D data visualization view resides
* and the secondary subviewport where the 2D sliced view of the data resides. The subviewports are
* by default resized by the \a Q3DScene. To override the resize behavior you need to listen to both
* \l viewportChanged() and \l slicingActiveChanged() signals and recalculate the subviewports accordingly.
*
* Also the scene has flag for tracking if the secondary 2D slicing view is currently active or not.
* \note Not all visualizations support the secondary 2D slicing view.
*/
/*!
* \class Q3DSceneChangeBitField
* \internal
*/
/*!
* \qmltype Scene3D
* \inqmlmodule QtDataVisualization
* \since QtDataVisualization 1.0
* \ingroup datavisualization_qml
* \instantiates Q3DScene
* \brief Scene3D type provides description of the 3D scene being visualized.
*
* The 3D scene contains a single active camera and a single active light source.
* Visualized data is assumed to be at a fixed location.
*
* The 3D scene also keeps track of the viewport in which visualization rendering is done,
* the primary subviewport inside the viewport where the main 3D data visualization view resides
* and the secondary subviewport where the 2D sliced view of the data resides.
*
* Also the scene has flag for tracking if the secondary 2D slicing view is currently active or not.
* \note Not all visualizations support the secondary 2D slicing view.
*/
/*!
* \qmlproperty rect Scene3D::viewport
*
* The current viewport rectangle where all 3D rendering is targeted.
*/
/*!
* \qmlproperty rect Scene3D::primarySubViewport
*
* The current subviewport rectangle inside the viewport where the
* primary view of the data visualization is targeted.
*
* If slicingActive is \c false, the primary sub viewport will be equal to the
* viewport. If slicingActive is \c true and the primary sub viewport has not
* been explicitly set, it will be one fifth of the viewport.
* \note Setting primarySubViewport larger than or outside of viewport resizes viewport accordingly.
*/
/*!
* \qmlproperty rect Scene3D::secondarySubViewport
*
* The secondary viewport rectangle inside the viewport. The secondary viewport
* is used for drawing the 2D slice view in some visualizations. If it has not
* been explicitly set, it will be null. If slicingActive is \c true, it will
* be equal to the viewport.
* \note If the secondary sub viewport is larger than or outside of the
* viewport, the viewport is resized accordingly.
*/
/*!
* \qmlproperty point Scene3D::selectionQueryPosition
*
* The coordinates for the user input that should be processed
* by the scene as a selection. If this property is set to a value other than
* invalidSelectionPoint, the
* graph tries to select a data item at the given point within the primary viewport.
* After the rendering pass, the property is returned to its default state of
* invalidSelectionPoint.
*/
/*!
* \qmlproperty point Scene3D::graphPositionQuery
*
* The coordinates for the user input that should be processed by the scene as a
* graph position query. If this property is set to value other than
* invalidSelectionPoint, the graph tries to match a graph position to the given point
* within the primary viewport.
* After the rendering pass, this property is returned to its default state of
* invalidSelectionPoint. The queried graph position can be read from the
* AbstractGraph3D::queriedGraphPosition property after the next render pass.
*
* There is no single correct 3D coordinate to match a particular screen position, so to be
* consistent, the queries are always done against the inner sides of an invisible box surrounding
* the graph.
*
* \note Bar graphs allow graph position queries only at the graph floor level.
*
* \sa AbstractGraph3D::queriedGraphPosition
*/
/*!
* \qmlproperty bool Scene3D::slicingActive
*
* Defines whether the 2D slicing view is currently active. If \c true,
* AbstractGraph3D::selectionMode must have either the
* \l{QAbstract3DGraph::SelectionRow}{AbstractGraph3D.SelectionRow} or
* \l{QAbstract3DGraph::SelectionColumn}{AbstractGraph3D.SelectionColumn}
* set to a valid selection.
* \note Not all visualizations support the 2D slicing view.
*/
/*!
* \qmlproperty bool Scene3D::secondarySubviewOnTop
*
* Defines whether the 2D slicing view or the 3D view is drawn on top.
*/
/*!
* \qmlproperty Camera3D Scene3D::activeCamera
*
* The currently active camera in the 3D scene.
* When a Camera3D is set in the property, it is automatically added as child of
* the scene.
*/
/*!
* \qmlproperty Light3D Scene3D::activeLight
*
* The currently active light in the 3D scene.
* When a Light3D is set in the property, it is automatically added as child of
* the scene.
*/
/*!
* \qmlproperty float Scene3D::devicePixelRatio
*
* The current device pixel ratio that is used when mapping input
* coordinates to pixel coordinates.
*/
/*!
* \qmlproperty point Scene3D::invalidSelectionPoint
* A constant property providing an invalid point for selection.
*/
/*!
* Constructs a basic scene with one light and one camera in it. An
* optional \a parent parameter can be given and is then passed to QObject constructor.
*/
Q3DScene::Q3DScene(QObject *parent) :
QObject(parent),
d_ptr(new Q3DScenePrivate(this))
{
setActiveCamera(new Q3DCamera(0));
setActiveLight(new Q3DLight(0));
}
/*!
* Destroys the 3D scene and all the objects contained within it.
*/
Q3DScene::~Q3DScene()
{
}
/*!
* \property Q3DScene::viewport
*
* \brief A read only property that contains the current viewport rectangle
* where all the 3D rendering is targeted.
*/
QRect Q3DScene::viewport() const
{
return d_ptr->m_viewport;
}
/*!
* \property Q3DScene::primarySubViewport
*
* \brief The current subviewport rectangle inside the viewport where the
* primary view of the data visualization is targeted.
*
* If isSlicingActive() is \c false, the primary sub viewport is equal to
* viewport(). If isSlicingActive() is \c true and the primary sub viewport has
* not been explicitly set, it will be one fifth of viewport().
*
* \note Setting primarySubViewport larger than or outside of the viewport
* resizes the viewport accordingly.
*/
QRect Q3DScene::primarySubViewport() const
{
QRect primary = d_ptr->m_primarySubViewport;
if (primary.isNull()) {
if (d_ptr->m_isSlicingActive)
primary = d_ptr->m_defaultSmallViewport;
else
primary = d_ptr->m_defaultLargeViewport;
}
return primary;
}
void Q3DScene::setPrimarySubViewport(const QRect &primarySubViewport)
{
if (d_ptr->m_primarySubViewport != primarySubViewport) {
if (!primarySubViewport.isValid() && !primarySubViewport.isNull()) {
qWarning("Viewport is invalid.");
return;
}
// If viewport is smaller than primarySubViewport, enlarge it
if ((d_ptr->m_viewport.width() < (primarySubViewport.width()
+ primarySubViewport.x()))
|| (d_ptr->m_viewport.height() < (primarySubViewport.height()
+ primarySubViewport.y()))) {
d_ptr->m_viewport.setWidth(qMax(d_ptr->m_viewport.width(),
primarySubViewport.width() + primarySubViewport.x()));
d_ptr->m_viewport.setHeight(qMax(d_ptr->m_viewport.height(),
primarySubViewport.height() + primarySubViewport.y()));
d_ptr->calculateSubViewports();
}
d_ptr->m_primarySubViewport = primarySubViewport;
d_ptr->updateGLSubViewports();
d_ptr->m_changeTracker.primarySubViewportChanged = true;
d_ptr->m_sceneDirty = true;
emit primarySubViewportChanged(primarySubViewport);
emit d_ptr->needRender();
}
}
/*!
* Returns whether the given \a point resides inside the primary subview or not.
* \return \c true if the point is inside the primary subview.
* \note If subviews are superimposed, and the given \a point resides inside both, result is
* \c true only when the primary subview is on top.
*/
bool Q3DScene::isPointInPrimarySubView(const QPoint &point)
{
int x = point.x();
int y = point.y();
bool isInSecondary = d_ptr->isInArea(secondarySubViewport(), x, y);
if (!isInSecondary || (isInSecondary && !d_ptr->m_isSecondarySubviewOnTop))
return d_ptr->isInArea(primarySubViewport(), x, y);
else
return false;
}
/*!
* Returns whether the given \a point resides inside the secondary subview or not.
* \return \c true if the point is inside the secondary subview.
* \note If subviews are superimposed, and the given \a point resides inside both, result is
* \c true only when the secondary subview is on top.
*/
bool Q3DScene::isPointInSecondarySubView(const QPoint &point)
{
int x = point.x();
int y = point.y();
bool isInPrimary = d_ptr->isInArea(primarySubViewport(), x, y);
if (!isInPrimary || (isInPrimary && d_ptr->m_isSecondarySubviewOnTop))
return d_ptr->isInArea(secondarySubViewport(), x, y);
else
return false;
}
/*!
* \property Q3DScene::secondarySubViewport
*
* \brief The secondary viewport rectangle inside the viewport.
*
* The secondary viewport is used for drawing the 2D slice view in some
* visualizations. If it has not been explicitly set, it will be equal to
* QRect. If isSlicingActive() is \c true, it will be equal to \l viewport.
* \note If the secondary sub viewport is larger than or outside of the
* viewport, the viewport is resized accordingly.
*/
QRect Q3DScene::secondarySubViewport() const
{
QRect secondary = d_ptr->m_secondarySubViewport;
if (secondary.isNull() && d_ptr->m_isSlicingActive)
secondary = d_ptr->m_defaultLargeViewport;
return secondary;
}
void Q3DScene::setSecondarySubViewport(const QRect &secondarySubViewport)
{
if (d_ptr->m_secondarySubViewport != secondarySubViewport) {
if (!secondarySubViewport.isValid() && !secondarySubViewport.isNull()) {
qWarning("Viewport is invalid.");
return;
}
// If viewport is smaller than secondarySubViewport, enlarge it
if ((d_ptr->m_viewport.width() < (secondarySubViewport.width()
+ secondarySubViewport.x()))
|| (d_ptr->m_viewport.height() < (secondarySubViewport.height()
+ secondarySubViewport.y()))) {
d_ptr->m_viewport.setWidth(qMax(d_ptr->m_viewport.width(),
secondarySubViewport.width()
+ secondarySubViewport.x()));
d_ptr->m_viewport.setHeight(qMax(d_ptr->m_viewport.height(),
secondarySubViewport.height()
+ secondarySubViewport.y()));
d_ptr->calculateSubViewports();
}
d_ptr->m_secondarySubViewport = secondarySubViewport;
d_ptr->updateGLSubViewports();
d_ptr->m_changeTracker.secondarySubViewportChanged = true;
d_ptr->m_sceneDirty = true;
emit secondarySubViewportChanged(secondarySubViewport);
emit d_ptr->needRender();
}
}
/*!
* \property Q3DScene::selectionQueryPosition
*
* \brief The coordinates for the user input that should be processed
* by the scene as a selection.
*
* If this property is set to a value other than invalidSelectionPoint(), the
* graph tries to select a data item, axis label, or a custom item at the
* specified coordinates within the primary viewport.
* After the rendering pass, the property is returned to its default state of
* invalidSelectionPoint().
*
* \sa QAbstract3DGraph::selectedElement
*/
void Q3DScene::setSelectionQueryPosition(const QPoint &point)
{
if (point != d_ptr->m_selectionQueryPosition) {
d_ptr->m_selectionQueryPosition = point;
d_ptr->m_changeTracker.selectionQueryPositionChanged = true;
d_ptr->m_sceneDirty = true;
emit selectionQueryPositionChanged(point);
emit d_ptr->needRender();
}
}
QPoint Q3DScene::selectionQueryPosition() const
{
return d_ptr->m_selectionQueryPosition;
}
/*!
* \return a QPoint signifying an invalid selection position.
*/
QPoint Q3DScene::invalidSelectionPoint()
{
static const QPoint invalidSelectionPos(-1, -1);
return invalidSelectionPos;
}
/*!
* \property Q3DScene::graphPositionQuery
*
* \brief The coordinates for the user input that should be processed
* by the scene as a graph position query.
*
* If this property is set to a value other than invalidSelectionPoint(), the
* graph tries to match a graph position to the specified coordinates
* within the primary viewport.
* After the rendering pass, this property is returned to its default state of
* invalidSelectionPoint(). The queried graph position can be read from the
* QAbstract3DGraph::queriedGraphPosition property after the next render pass.
*
* There is no single correct 3D coordinate to match a particular screen position, so to be
* consistent, the queries are always done against the inner sides of an invisible box surrounding
* the graph.
*
* \note Bar graphs allow graph position queries only at the graph floor level.
*
* \sa QAbstract3DGraph::queriedGraphPosition
*/
void Q3DScene::setGraphPositionQuery(const QPoint &point)
{
if (point != d_ptr->m_graphPositionQueryPosition) {
d_ptr->m_graphPositionQueryPosition = point;
d_ptr->m_changeTracker.graphPositionQueryPositionChanged = true;
d_ptr->m_sceneDirty = true;
emit graphPositionQueryChanged(point);
emit d_ptr->needRender();
}
}
QPoint Q3DScene::graphPositionQuery() const
{
return d_ptr->m_graphPositionQueryPosition;
}
/*!
* \property Q3DScene::slicingActive
*
* \brief Whether the 2D slicing view is currently active.
*
* If \c true, QAbstract3DGraph::selectionMode must have either
* QAbstract3DGraph::SelectionRow or QAbstract3DGraph::SelectionColumn set
* to a valid selection.
* \note Not all visualizations support the 2D slicing view.
*/
bool Q3DScene::isSlicingActive() const
{
return d_ptr->m_isSlicingActive;
}
void Q3DScene::setSlicingActive(bool isSlicing)
{
if (d_ptr->m_isSlicingActive != isSlicing) {
d_ptr->m_isSlicingActive = isSlicing;
d_ptr->m_changeTracker.slicingActivatedChanged = true;
d_ptr->m_sceneDirty = true;
// Set secondary subview behind primary to achieve default functionality (= clicking on
// primary disables slice)
setSecondarySubviewOnTop(!isSlicing);
d_ptr->calculateSubViewports();
emit slicingActiveChanged(isSlicing);
emit d_ptr->needRender();
}
}
/*!
* \property Q3DScene::secondarySubviewOnTop
*
* \brief Whether the 2D slicing view or the 3D view is drawn on top.
*/
bool Q3DScene::isSecondarySubviewOnTop() const
{
return d_ptr->m_isSecondarySubviewOnTop;
}
void Q3DScene::setSecondarySubviewOnTop(bool isSecondaryOnTop)
{
if (d_ptr->m_isSecondarySubviewOnTop != isSecondaryOnTop) {
d_ptr->m_isSecondarySubviewOnTop = isSecondaryOnTop;
d_ptr->m_changeTracker.subViewportOrderChanged = true;
d_ptr->m_sceneDirty = true;
emit secondarySubviewOnTopChanged(isSecondaryOnTop);
emit d_ptr->needRender();
}
}
/*!
* \property Q3DScene::activeCamera
*
* \brief The currently active camera in the 3D scene.
*
* When a new Q3DCamera object is set, it is automatically added as child of
* the scene.
*/
Q3DCamera *Q3DScene::activeCamera() const
{
return d_ptr->m_camera;
}
void Q3DScene::setActiveCamera(Q3DCamera *camera)
{
Q_ASSERT(camera);
// Add new camera as child of the scene
if (camera->parent() != this)
camera->setParent(this);
if (camera != d_ptr->m_camera) {
if (d_ptr->m_camera) {
disconnect(d_ptr->m_camera, &Q3DCamera::xRotationChanged, d_ptr.data(),
&Q3DScenePrivate::needRender);
disconnect(d_ptr->m_camera, &Q3DCamera::yRotationChanged, d_ptr.data(),
&Q3DScenePrivate::needRender);
disconnect(d_ptr->m_camera, &Q3DCamera::zoomLevelChanged, d_ptr.data(),
&Q3DScenePrivate::needRender);
}
d_ptr->m_camera = camera;
d_ptr->m_changeTracker.cameraChanged = true;
d_ptr->m_sceneDirty = true;
if (camera) {
connect(camera, &Q3DCamera::xRotationChanged, d_ptr.data(),
&Q3DScenePrivate::needRender);
connect(camera, &Q3DCamera::yRotationChanged, d_ptr.data(),
&Q3DScenePrivate::needRender);
connect(camera, &Q3DCamera::zoomLevelChanged, d_ptr.data(),
&Q3DScenePrivate::needRender);
}
emit activeCameraChanged(camera);
emit d_ptr->needRender();
}
}
/*!
* \property Q3DScene::activeLight
*
* \brief The currently active light in the 3D scene.
*
* When a new Q3DLight objects is set, it is automatically added as child of
* the scene.
*/
Q3DLight *Q3DScene::activeLight() const
{
return d_ptr->m_light;
}
void Q3DScene::setActiveLight(Q3DLight *light)
{
Q_ASSERT(light);
// Add new light as child of the scene
if (light->parent() != this)
light->setParent(this);
if (light != d_ptr->m_light) {
d_ptr->m_light = light;
d_ptr->m_changeTracker.lightChanged = true;
d_ptr->m_sceneDirty = true;
emit activeLightChanged(light);
emit d_ptr->needRender();
}
}
/*!
* \property Q3DScene::devicePixelRatio
*
* \brief The device pixel ratio that is used when mapping input
* coordinates to pixel coordinates.
*/
float Q3DScene::devicePixelRatio() const
{
return d_ptr->m_devicePixelRatio;
}
void Q3DScene::setDevicePixelRatio(float pixelRatio)
{
if (d_ptr->m_devicePixelRatio != pixelRatio) {
d_ptr->m_devicePixelRatio = pixelRatio;
d_ptr->m_changeTracker.devicePixelRatioChanged = true;
d_ptr->m_sceneDirty = true;
emit devicePixelRatioChanged(pixelRatio);
d_ptr->updateGLViewport();
emit d_ptr->needRender();
}
}
Q3DScenePrivate::Q3DScenePrivate(Q3DScene *q) :
QObject(0),
q_ptr(q),
m_isSecondarySubviewOnTop(true),
m_devicePixelRatio(1.f),
m_camera(),
m_light(),
m_isUnderSideCameraEnabled(false),
m_isSlicingActive(false),
m_selectionQueryPosition(Q3DScene::invalidSelectionPoint()),
m_graphPositionQueryPosition(Q3DScene::invalidSelectionPoint()),
m_windowSize(QSize(0, 0)),
m_sceneDirty(true)
{
}
Q3DScenePrivate::~Q3DScenePrivate()
{
delete m_camera;
delete m_light;
}
// Copies changed values from this scene to the other scene. If the other scene had same changes,
// those changes are discarded.
void Q3DScenePrivate::sync(Q3DScenePrivate &other)
{
if (m_changeTracker.windowSizeChanged) {
other.setWindowSize(windowSize());
m_changeTracker.windowSizeChanged = false;
other.m_changeTracker.windowSizeChanged = false;
}
if (m_changeTracker.viewportChanged) {
other.setViewport(m_viewport);
m_changeTracker.viewportChanged = false;
other.m_changeTracker.viewportChanged = false;
}
if (m_changeTracker.subViewportOrderChanged) {
other.q_ptr->setSecondarySubviewOnTop(q_ptr->isSecondarySubviewOnTop());
m_changeTracker.subViewportOrderChanged = false;
other.m_changeTracker.subViewportOrderChanged = false;
}
if (m_changeTracker.primarySubViewportChanged) {
other.q_ptr->setPrimarySubViewport(q_ptr->primarySubViewport());
m_changeTracker.primarySubViewportChanged = false;
other.m_changeTracker.primarySubViewportChanged = false;
}
if (m_changeTracker.secondarySubViewportChanged) {
other.q_ptr->setSecondarySubViewport(q_ptr->secondarySubViewport());
m_changeTracker.secondarySubViewportChanged = false;
other.m_changeTracker.secondarySubViewportChanged = false;
}
if (m_changeTracker.selectionQueryPositionChanged) {
other.q_ptr->setSelectionQueryPosition(q_ptr->selectionQueryPosition());
m_changeTracker.selectionQueryPositionChanged = false;
other.m_changeTracker.selectionQueryPositionChanged = false;
}
if (m_changeTracker.graphPositionQueryPositionChanged) {
other.q_ptr->setGraphPositionQuery(q_ptr->graphPositionQuery());
m_changeTracker.graphPositionQueryPositionChanged = false;
other.m_changeTracker.graphPositionQueryPositionChanged = false;
}
if (m_changeTracker.cameraChanged) {
m_camera->setDirty(true);
m_changeTracker.cameraChanged = false;
other.m_changeTracker.cameraChanged = false;
}
m_camera->d_ptr->sync(*other.m_camera);
if (m_changeTracker.lightChanged) {
m_light->setDirty(true);
m_changeTracker.lightChanged = false;
other.m_changeTracker.lightChanged = false;
}
m_light->d_ptr->sync(*other.m_light);
if (m_changeTracker.slicingActivatedChanged) {
other.q_ptr->setSlicingActive(q_ptr->isSlicingActive());
m_changeTracker.slicingActivatedChanged = false;
other.m_changeTracker.slicingActivatedChanged = false;
}
if (m_changeTracker.devicePixelRatioChanged) {
other.q_ptr->setDevicePixelRatio(q_ptr->devicePixelRatio());
m_changeTracker.devicePixelRatioChanged = false;
other.m_changeTracker.devicePixelRatioChanged = false;
}
m_sceneDirty = false;
other.m_sceneDirty = false;
}
void Q3DScenePrivate::setViewport(const QRect &viewport)
{
if (m_viewport != viewport && viewport.isValid()) {
m_viewport = viewport;
calculateSubViewports();
emit needRender();
}
}
void Q3DScenePrivate::setViewportSize(int width, int height)
{
if (m_viewport.width() != width || m_viewport.height() != height) {
m_viewport.setWidth(width);
m_viewport.setHeight(height);
calculateSubViewports();
emit needRender();
}
}
/*!
* \internal
* Sets the size of the window being rendered to. With widget based graphs, this
* is equal to the size of the QWindow and is same as the bounding rectangle.
* With declarative graphs this is equal to the size of the QQuickWindow and
* can be different from the bounding rectangle.
*/
void Q3DScenePrivate::setWindowSize(const QSize &size)
{
if (m_windowSize != size) {
m_windowSize = size;
updateGLViewport();
m_changeTracker.windowSizeChanged = true;
emit needRender();
}
}
QSize Q3DScenePrivate::windowSize() const
{
return m_windowSize;
}
void Q3DScenePrivate::calculateSubViewports()
{
// Calculates the default subviewport layout, used when slicing
const float smallerViewPortRatio = 0.2f;
m_defaultSmallViewport = QRect(0, 0,
m_viewport.width() * smallerViewPortRatio,
m_viewport.height() * smallerViewPortRatio);
m_defaultLargeViewport = QRect(0, 0,
m_viewport.width(),
m_viewport.height());
updateGLViewport();
}
void Q3DScenePrivate::updateGLViewport()
{
// Update GL viewport
m_glViewport.setX(m_viewport.x() * m_devicePixelRatio);
m_glViewport.setY((m_windowSize.height() - (m_viewport.y() + m_viewport.height()))
* m_devicePixelRatio);
m_glViewport.setWidth(m_viewport.width() * m_devicePixelRatio);
m_glViewport.setHeight(m_viewport.height() * m_devicePixelRatio);
m_changeTracker.viewportChanged = true;
m_sceneDirty = true;
// Do default subviewport changes first, then allow signal listeners to override.
updateGLSubViewports();
emit q_ptr->viewportChanged(m_viewport);
}
void Q3DScenePrivate::updateGLSubViewports()
{
if (m_isSlicingActive) {
QRect primary = m_primarySubViewport;
QRect secondary = m_secondarySubViewport;
if (primary.isNull())
primary = m_defaultSmallViewport;
if (secondary.isNull())
secondary = m_defaultLargeViewport;
m_glPrimarySubViewport.setX((primary.x() + m_viewport.x()) * m_devicePixelRatio);
m_glPrimarySubViewport.setY((m_windowSize.height()
- (primary.y() + primary.height() + m_viewport.y()))
* m_devicePixelRatio);
m_glPrimarySubViewport.setWidth(primary.width() * m_devicePixelRatio);
m_glPrimarySubViewport.setHeight(primary.height() * m_devicePixelRatio);
m_glSecondarySubViewport.setX((secondary.x() + m_viewport.x()) * m_devicePixelRatio);
m_glSecondarySubViewport.setY((m_windowSize.height()
- (secondary.y() + secondary.height() + m_viewport.y()))
* m_devicePixelRatio);
m_glSecondarySubViewport.setWidth(secondary.width() * m_devicePixelRatio);
m_glSecondarySubViewport.setHeight(secondary.height() * m_devicePixelRatio);
} else {
m_glPrimarySubViewport.setX(m_viewport.x() * m_devicePixelRatio);
m_glPrimarySubViewport.setY((m_windowSize.height() - (m_viewport.y() + m_viewport.height()))
* m_devicePixelRatio);
m_glPrimarySubViewport.setWidth(m_viewport.width() * m_devicePixelRatio);
m_glPrimarySubViewport.setHeight(m_viewport.height() * m_devicePixelRatio);
m_glSecondarySubViewport = QRect();
}
}
QRect Q3DScenePrivate::glViewport()
{
return m_glViewport;
}
QRect Q3DScenePrivate::glPrimarySubViewport()
{
return m_glPrimarySubViewport;
}
QRect Q3DScenePrivate::glSecondarySubViewport()
{
return m_glSecondarySubViewport;
}
/*!
* \internal
* Calculates and sets the light position relative to the currently active camera using the given
* parameters.
* The relative 3D offset to the current camera position is defined in \a relativePosition.
* Optional \a fixedRotation fixes the light rotation around the data visualization area to the
* given value in degrees.
* Optional \a distanceModifier modifies the distance of the light from the data visualization.
*/
void Q3DScenePrivate::setLightPositionRelativeToCamera(const QVector3D &relativePosition,
float fixedRotation, float distanceModifier)
{
m_light->setPosition(m_camera->d_ptr->calculatePositionRelativeToCamera(relativePosition,
fixedRotation,
distanceModifier));
}
void Q3DScenePrivate::markDirty()
{
m_sceneDirty = true;
emit needRender();
}
bool Q3DScenePrivate::isInArea(const QRect &area, int x, int y) const
{
int areaMinX = area.x();
int areaMaxX = area.x() + area.width();
int areaMinY = area.y();
int areaMaxY = area.y() + area.height();
return ( x >= areaMinX && x <= areaMaxX && y >= areaMinY && y <= areaMaxY );
}
QT_END_NAMESPACE_DATAVISUALIZATION