1// Copyright (C) 2018 Klaralvdalens Datakonsult AB (KDAB).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "abstractpickingjob_p.h"
5#include <Qt3DRender/qgeometryrenderer.h>
6#include <Qt3DRender/private/nodemanagers_p.h>
7#include <Qt3DRender/private/entity_p.h>
8#include <Qt3DRender/private/objectpicker_p.h>
9#include <Qt3DRender/private/managers_p.h>
10#include <Qt3DRender/private/geometryrenderer_p.h>
11#include <Qt3DRender/private/rendersettings_p.h>
12#include <Qt3DRender/private/trianglesvisitor_p.h>
13#include <Qt3DRender/private/job_common_p.h>
14#include <QtGui/qoffscreensurface.h>
15#include <QtGui/qwindow.h>
16
17QT_BEGIN_NAMESPACE
18
19namespace Qt3DRender {
20
21namespace Render {
22
23AbstractPickingJob::AbstractPickingJob()
24 : Qt3DCore::QAspectJob()
25 , m_manager(nullptr)
26 , m_node(nullptr)
27 , m_frameGraphRoot(nullptr)
28 , m_renderSettings(nullptr)
29 , m_oneEnabledAtLeast(false)
30{
31}
32
33AbstractPickingJob::AbstractPickingJob(Qt3DCore::QAspectJobPrivate &dd)
34 : Qt3DCore::QAspectJob(dd)
35 , m_manager(nullptr)
36 , m_node(nullptr)
37 , m_frameGraphRoot(nullptr)
38 , m_renderSettings(nullptr)
39 , m_oneEnabledAtLeast(false)
40{
41
42}
43
44void AbstractPickingJob::setRoot(Entity *root)
45{
46 m_node = root;
47}
48
49void AbstractPickingJob::setFrameGraphRoot(FrameGraphNode *frameGraphRoot)
50{
51 m_frameGraphRoot = frameGraphRoot;
52}
53
54void AbstractPickingJob::setRenderSettings(RenderSettings *settings)
55{
56 m_renderSettings = settings;
57}
58
59void AbstractPickingJob::setManagers(NodeManagers *manager)
60{
61 m_manager = manager;
62}
63
64void AbstractPickingJob::run()
65{
66 Q_ASSERT(m_frameGraphRoot && m_renderSettings && m_node && m_manager);
67 runHelper();
68}
69
70RayCasting::QRay3D AbstractPickingJob::intersectionRay(const QPoint &pos, const Matrix4x4 &viewMatrix,
71 const Matrix4x4 &projectionMatrix, const QRect &viewport)
72{
73 Vector3D nearPos = Vector3D(pos.x(), pos.y(), 0.0f);
74 nearPos = nearPos.unproject(modelView: viewMatrix, projection: projectionMatrix, viewport);
75 Vector3D farPos = Vector3D(pos.x(), pos.y(), 1.0f);
76 farPos = farPos.unproject(modelView: viewMatrix, projection: projectionMatrix, viewport);
77
78 return RayCasting::QRay3D(nearPos,
79 (farPos - nearPos).normalized(),
80 (farPos - nearPos).length());
81}
82
83QRect AbstractPickingJob::windowViewport(const QSize &area, const QRectF &relativeViewport) const
84{
85 if (area.isValid()) {
86 const int areaWidth = area.width();
87 const int areaHeight = area.height();
88 return QRect(relativeViewport.x() * areaWidth,
89 (1.0 - relativeViewport.y() - relativeViewport.height()) * areaHeight,
90 relativeViewport.width() * areaWidth,
91 relativeViewport.height() * areaHeight);
92 }
93 return relativeViewport.toRect();
94}
95
96RayCasting::QRay3D AbstractPickingJob::rayForViewportAndCamera(const PickingUtils::ViewportCameraAreaDetails &vca,
97 QObject *eventSource,
98 const QPoint &pos) const
99{
100 static RayCasting::QRay3D invalidRay({}, {}, 0.f);
101
102 if (!vca.area.isValid())
103 return invalidRay;
104
105 Matrix4x4 viewMatrix;
106 Matrix4x4 projectionMatrix;
107 Render::CameraLens::viewMatrixForCamera(manager: m_manager->renderNodesManager(),
108 cameraId: vca.cameraId,
109 viewMatrix,
110 projectionMatrix);
111 // Returns viewport rect in GL coordinates (y inverted)
112 const QRect viewport = windowViewport(area: vca.area, relativeViewport: vca.viewport);
113 // In GL the y is inverted compared to Qt
114 const QPoint glCorrectPos = QPoint(pos.x(), vca.area.height() - pos.y());
115
116 if (!viewport.contains(p: glCorrectPos))
117 return invalidRay;
118 if (vca.surface) {
119 QSurface *surface = nullptr;
120 if (eventSource) {
121 QWindow *window = qobject_cast<QWindow *>(o: eventSource);
122 if (window) {
123 surface = static_cast<QSurface *>(window);
124 } else {
125 QOffscreenSurface *offscreen = qobject_cast<QOffscreenSurface *>(object: eventSource);
126 if (offscreen)
127 surface = static_cast<QSurface *>(offscreen);
128 }
129 }
130 if (surface && vca.surface != surface)
131 return invalidRay;
132 }
133
134 const auto ray = intersectionRay(pos: glCorrectPos, viewMatrix, projectionMatrix, viewport);
135 return ray;
136}
137
138} // namespace Render
139
140} // namespace Qt3DRender
141
142QT_END_NAMESPACE
143

source code of qt3d/src/render/jobs/abstractpickingjob.cpp