1/****************************************************************************
2**
3** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB).
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the Qt3D module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "qmlscenereader.h"
30#include "testpostmanarbiter.h"
31
32#include <QtTest/QTest>
33#include <Qt3DCore/qentity.h>
34#include <Qt3DCore/qtransform.h>
35#include <Qt3DCore/private/qaspectjobmanager_p.h>
36#include <Qt3DCore/private/qnodevisitor_p.h>
37#include <Qt3DCore/private/qaspectmanager_p.h>
38#include <Qt3DCore/private/qscene_p.h>
39#include <Qt3DCore/private/qaspectengine_p.h>
40#include <Qt3DCore/private/qaspectjob_p.h>
41#include <QtQuick/qquickwindow.h>
42
43#include <Qt3DRender/QCamera>
44#include <Qt3DRender/QObjectPicker>
45#include <Qt3DRender/QNoPicking>
46#include <Qt3DRender/QPickEvent>
47#include <Qt3DRender/QPickTriangleEvent>
48#include <Qt3DRender/QPickingSettings>
49#include <Qt3DRender/private/nodemanagers_p.h>
50#include <Qt3DRender/private/managers_p.h>
51#include <Qt3DRender/private/entity_p.h>
52#include <Qt3DRender/qrenderaspect.h>
53#include <Qt3DRender/private/rendersettings_p.h>
54#include <Qt3DRender/private/qrenderaspect_p.h>
55#include <Qt3DRender/private/pickboundingvolumejob_p.h>
56#include <Qt3DRender/private/pickboundingvolumeutils_p.h>
57#include <Qt3DRender/private/updatemeshtrianglelistjob_p.h>
58#include <Qt3DRender/private/updateworldboundingvolumejob_p.h>
59#include <Qt3DRender/private/updateworldtransformjob_p.h>
60#include <Qt3DRender/private/expandboundingvolumejob_p.h>
61#include <Qt3DRender/private/calcboundingvolumejob_p.h>
62#include <Qt3DRender/private/calcgeometrytrianglevolumes_p.h>
63#include <Qt3DRender/private/updateentitylayersjob_p.h>
64#include <Qt3DRender/private/loadbufferjob_p.h>
65#include <Qt3DRender/private/buffermanager_p.h>
66#include <Qt3DRender/private/geometryrenderermanager_p.h>
67#include <Qt3DRender/private/qobjectpicker_p.h>
68#include <Qt3DRender/private/nopicking_p.h>
69
70#include <QSignalSpy>
71
72#include <private/qpickevent_p.h>
73
74QT_BEGIN_NAMESPACE
75
76namespace Qt3DRender {
77
78QVector<Qt3DCore::QNode *> getNodesForCreation(Qt3DCore::QNode *root)
79{
80 using namespace Qt3DCore;
81
82 QVector<QNode *> nodes;
83 Qt3DCore::QNodeVisitor visitor;
84 visitor.traverse(rootNode_: root, fN: [&nodes](QNode *node) {
85 nodes.append(t: node);
86
87 // Store the metaobject of the node in the QNode so that we have it available
88 // to us during destruction in the QNode destructor. This allows us to send
89 // the QNodeId and the metaobject as typeinfo to the backend aspects so they
90 // in turn can find the correct QBackendNodeMapper object to handle the destruction
91 // of the corresponding backend nodes.
92 QNodePrivate *d = QNodePrivate::get(q: node);
93 d->m_typeInfo = const_cast<QMetaObject*>(QNodePrivate::findStaticMetaObject(metaObject: node->metaObject()));
94
95 // Mark this node as having been handled for creation so that it is picked up
96 d->m_hasBackendNode = true;
97 });
98
99 return nodes;
100}
101
102QVector<Qt3DCore::NodeTreeChange> nodeTreeChangesForNodes(const QVector<Qt3DCore::QNode *> nodes)
103{
104 QVector<Qt3DCore::NodeTreeChange> nodeTreeChanges;
105 nodeTreeChanges.reserve(size: nodes.size());
106
107 for (Qt3DCore::QNode *n : nodes) {
108 nodeTreeChanges.push_back(t: {
109 .id: n->id(),
110 .metaObj: Qt3DCore::QNodePrivate::get(q: n)->m_typeInfo,
111 .type: Qt3DCore::NodeTreeChange::Added,
112 .node: n
113 });
114 }
115
116 return nodeTreeChanges;
117}
118
119class TestAspect : public Qt3DRender::QRenderAspect
120{
121public:
122 TestAspect(Qt3DCore::QNode *root)
123 : Qt3DRender::QRenderAspect(Qt3DRender::QRenderAspect::Synchronous)
124 , m_sceneRoot(nullptr)
125 {
126 m_engine = new Qt3DCore::QAspectEngine(this);
127 m_engine->registerAspect(aspect: this);
128 Q_ASSERT(d_func()->m_aspectManager);
129
130 // do what QAspectEngine::setRootEntity does since we don't want to enter the simulation loop
131 Qt3DCore::QEntityPtr proot(qobject_cast<Qt3DCore::QEntity *>(object: root), [](Qt3DCore::QEntity *) { });
132 Qt3DCore::QAspectEnginePrivate *aed = Qt3DCore::QAspectEnginePrivate::get(engine: m_engine);
133 aed->m_root = proot;
134 aed->initialize();
135 aed->initNodeTree(node: root);
136 const QVector<Qt3DCore::QNode *> nodes = getNodesForCreation(root);
137 aed->m_aspectManager->setRootEntity(root: proot.data(), nodes);
138
139 Render::Entity *rootEntity = nodeManagers()->lookupResource<Render::Entity, Render::EntityManager>(id: rootEntityId());
140 Q_ASSERT(rootEntity);
141 m_sceneRoot = rootEntity;
142 }
143
144 ~TestAspect()
145 {
146 using namespace Qt3DCore;
147 QNodeVisitor visitor;
148 visitor.traverse(rootNode_: m_engine->rootEntity().data(), fN: [](QNode *node) {
149 QNodePrivate *d = QNodePrivate::get(q: node);
150 d->m_scene = nullptr;
151 d->m_changeArbiter = nullptr;
152 });
153
154 m_engine->unregisterAspect(aspect: this);
155 delete m_engine;
156 m_engine = nullptr;
157 }
158
159 void onRegistered() { QRenderAspect::onRegistered(); }
160 void onUnregistered() { QRenderAspect::onUnregistered(); }
161
162 Qt3DRender::Render::NodeManagers *nodeManagers() const { return d_func()->m_renderer->nodeManagers(); }
163 Qt3DRender::Render::FrameGraphNode *frameGraphRoot() const { return d_func()->m_renderer->frameGraphRoot(); }
164 Qt3DRender::Render::RenderSettings *renderSettings() const { return d_func()->m_renderer->settings(); }
165 Qt3DRender::Render::Entity *sceneRoot() const { return m_sceneRoot; }
166 Qt3DCore::QAspectManager *aspectManager() const { return d_func()->m_aspectManager; }
167 Qt3DCore::QChangeArbiter *arbiter() const { return d_func()->m_arbiter; }
168private:
169 Qt3DCore::QAspectEngine *m_engine;
170 Render::Entity *m_sceneRoot;
171};
172
173} // namespace Qt3DRender
174
175QT_END_NAMESPACE
176
177namespace {
178
179void runRequiredJobs(Qt3DRender::TestAspect *test)
180{
181 Qt3DRender::Render::UpdateWorldTransformJob updateWorldTransform;
182 updateWorldTransform.setRoot(test->sceneRoot());
183 updateWorldTransform.setManagers(test->nodeManagers());
184 updateWorldTransform.run();
185
186 // For each buffer
187 const std::vector<Qt3DRender::Render::HBuffer> &bufferHandles = test->nodeManagers()->bufferManager()->activeHandles();
188 for (auto bufferHandle : bufferHandles) {
189 Qt3DRender::Render::LoadBufferJob loadBuffer(bufferHandle);
190 loadBuffer.setNodeManager(test->nodeManagers());
191 loadBuffer.run();
192 }
193
194 Qt3DRender::Render::CalculateBoundingVolumeJob calcBVolume;
195 calcBVolume.setManagers(test->nodeManagers());
196 calcBVolume.setRoot(test->sceneRoot());
197 calcBVolume.run();
198
199 Qt3DRender::Render::UpdateWorldBoundingVolumeJob updateWorldBVolume;
200 updateWorldBVolume.setManager(test->nodeManagers()->renderNodesManager());
201 updateWorldBVolume.run();
202
203 Qt3DRender::Render::ExpandBoundingVolumeJob expandBVolume;
204 expandBVolume.setRoot(test->sceneRoot());
205 expandBVolume.setManagers(test->nodeManagers());
206 expandBVolume.run();
207
208 Qt3DRender::Render::UpdateMeshTriangleListJob updateTriangleList;
209 updateTriangleList.setManagers(test->nodeManagers());
210 updateTriangleList.run();
211
212 // For each geometry id
213 const std::vector<Qt3DRender::Render::HGeometryRenderer> &geometryRenderHandles = test->nodeManagers()->geometryRendererManager()->activeHandles();
214 for (auto geometryRenderHandle : geometryRenderHandles) {
215 Qt3DCore::QNodeId geometryRendererId = test->nodeManagers()->geometryRendererManager()->data(handle: geometryRenderHandle)->peerId();
216 Qt3DRender::Render::CalcGeometryTriangleVolumes calcGeometryTriangles(geometryRendererId, test->nodeManagers());
217 calcGeometryTriangles.run();
218 }
219
220 Qt3DRender::Render::UpdateEntityLayersJob updateEntityLayer;
221 updateEntityLayer.setManager(test->nodeManagers());
222 updateEntityLayer.run();
223}
224
225void initializePickBoundingVolumeJob(Qt3DRender::Render::PickBoundingVolumeJob *job, Qt3DRender::TestAspect *test)
226{
227 job->setFrameGraphRoot(test->frameGraphRoot());
228 job->setRoot(test->sceneRoot());
229 job->setManagers(test->nodeManagers());
230 job->setRenderSettings(test->renderSettings());
231}
232
233} // anonymous
234
235class tst_PickBoundingVolumeJob : public QObject
236{
237 Q_OBJECT
238private:
239 void generateAllPickingSettingsCombinations()
240 {
241 QTest::addColumn<Qt3DRender::QPickingSettings::PickMethod>(name: "pickMethod");
242 QTest::addColumn<Qt3DRender::QPickingSettings::PickResultMode>(name: "pickResultMode");
243 QTest::addColumn<Qt3DRender::QPickingSettings::FaceOrientationPickingMode>(name: "faceOrientationPickingMode");
244
245 QTest::newRow(dataTag: "volume, nearest, front") << Qt3DRender::QPickingSettings::BoundingVolumePicking
246 << Qt3DRender::QPickingSettings::NearestPick
247 << Qt3DRender::QPickingSettings::FrontFace;
248
249 QTest::newRow(dataTag: "volume, nearest, back") << Qt3DRender::QPickingSettings::BoundingVolumePicking
250 << Qt3DRender::QPickingSettings::NearestPick
251 << Qt3DRender::QPickingSettings::BackFace;
252
253 QTest::newRow(dataTag: "volume, nearest, front+back") << Qt3DRender::QPickingSettings::BoundingVolumePicking
254 << Qt3DRender::QPickingSettings::NearestPick
255 << Qt3DRender::QPickingSettings::FrontAndBackFace;
256
257 QTest::newRow(dataTag: "volume, all, front") << Qt3DRender::QPickingSettings::BoundingVolumePicking
258 << Qt3DRender::QPickingSettings::AllPicks
259 << Qt3DRender::QPickingSettings::FrontFace;
260
261 QTest::newRow(dataTag: "volume, all, back") << Qt3DRender::QPickingSettings::BoundingVolumePicking
262 << Qt3DRender::QPickingSettings::AllPicks
263 << Qt3DRender::QPickingSettings::BackFace;
264
265 QTest::newRow(dataTag: "volume, all, front+back") << Qt3DRender::QPickingSettings::BoundingVolumePicking
266 << Qt3DRender::QPickingSettings::AllPicks
267 << Qt3DRender::QPickingSettings::FrontAndBackFace;
268
269 QTest::newRow(dataTag: "triangle, nearest, front") << Qt3DRender::QPickingSettings::TrianglePicking
270 << Qt3DRender::QPickingSettings::NearestPick
271 << Qt3DRender::QPickingSettings::FrontFace;
272
273 QTest::newRow(dataTag: "triangle, nearest, back") << Qt3DRender::QPickingSettings::TrianglePicking
274 << Qt3DRender::QPickingSettings::NearestPick
275 << Qt3DRender::QPickingSettings::BackFace;
276
277 QTest::newRow(dataTag: "triangle, nearest, front+back") << Qt3DRender::QPickingSettings::TrianglePicking
278 << Qt3DRender::QPickingSettings::NearestPick
279 << Qt3DRender::QPickingSettings::FrontAndBackFace;
280
281 QTest::newRow(dataTag: "triangle, all, front") << Qt3DRender::QPickingSettings::TrianglePicking
282 << Qt3DRender::QPickingSettings::AllPicks
283 << Qt3DRender::QPickingSettings::FrontFace;
284
285 QTest::newRow(dataTag: "triangle, all, back") << Qt3DRender::QPickingSettings::TrianglePicking
286 << Qt3DRender::QPickingSettings::AllPicks
287 << Qt3DRender::QPickingSettings::BackFace;
288
289 QTest::newRow(dataTag: "triangle, all, front+back") << Qt3DRender::QPickingSettings::TrianglePicking
290 << Qt3DRender::QPickingSettings::AllPicks
291 << Qt3DRender::QPickingSettings::FrontAndBackFace;
292 }
293
294private Q_SLOTS:
295 void viewportCameraAreaGather()
296 {
297 // GIVEN
298 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
299 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
300 QVERIFY(root);
301 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
302
303 // THEN
304 QVERIFY(test->frameGraphRoot() != nullptr);
305 Qt3DRender::QCamera *camera = root->findChild<Qt3DRender::QCamera *>();
306 QVERIFY(camera != nullptr);
307 QQuickWindow *window = root->findChild<QQuickWindow *>();
308 QVERIFY(camera != nullptr);
309 QCOMPARE(window->size(), QSize(600, 600));
310
311 // WHEN
312 Qt3DRender::Render::PickingUtils::ViewportCameraAreaGatherer gatherer;
313 QVector<Qt3DRender::Render::PickingUtils::ViewportCameraAreaDetails> results = gatherer.gather(root: test->frameGraphRoot());
314
315 // THEN
316 QCOMPARE(results.size(), 1);
317 auto vca = results.first();
318 QCOMPARE(vca.area, QSize(600, 600));
319 QCOMPARE(vca.cameraId, camera->id());
320 QCOMPARE(vca.viewport, QRectF(0., 0., 1., 1.));
321 }
322
323 void checkCurrentPickerChange_data()
324 {
325 generateAllPickingSettingsCombinations();
326 }
327
328 void checkCurrentPickerChange()
329 {
330 // GIVEN
331 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
332 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
333 QVERIFY(root);
334
335 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
336 QCOMPARE(renderSettings.size(), 1);
337 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
338
339 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
340 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
341 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
342 settings->setPickMethod(pickMethod);
343 settings->setPickResultMode(pickResultMode);
344 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
345
346 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
347
348 // Runs Required jobs
349 runRequiredJobs(test: test.data());
350
351 // THEN
352 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
353 QCOMPARE(pickers.size(), 2);
354
355 Qt3DRender::QObjectPicker *picker1 = nullptr;
356 Qt3DRender::QObjectPicker *picker2 = nullptr;
357
358 if (pickers.first()->objectName() == QLatin1String("Picker1")) {
359 picker1 = pickers.first();
360 picker2 = pickers.last();
361 } else {
362 picker1 = pickers.last();
363 picker2 = pickers.first();
364 }
365
366 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
367 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
368 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
369
370 // WHEN
371 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
372 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
373
374 // THEN
375 QVERIFY(pickBVJob.currentPicker().isNull());
376
377 // WHEN
378 QList<QPair<QObject *,QMouseEvent>> events;
379 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207., 303.), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
380 pickBVJob.setMouseEvents(events);
381 bool earlyReturn = !pickBVJob.runHelper();
382
383 // THEN
384 QVERIFY(!earlyReturn);
385 QVERIFY(!pickBVJob.currentPicker().isNull());
386 Qt3DRender::Render::ObjectPicker *backendPicker = test->nodeManagers()->data<Qt3DRender::Render::ObjectPicker, Qt3DRender::Render::ObjectPickerManager>(handle: pickBVJob.currentPicker());
387 QVERIFY(backendPicker != nullptr);
388 QCOMPARE(backendPicker->peerId(), picker1->id());
389
390 // WHEN
391 events.clear();
392 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(207., 303.), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
393 pickBVJob.setMouseEvents(events);
394 earlyReturn = !pickBVJob.runHelper();
395
396 // THEN
397 QVERIFY(!earlyReturn);
398 QVERIFY(pickBVJob.currentPicker().isNull());
399
400 // WHEN
401 events.clear();
402 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(390., 300.), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
403 pickBVJob.setMouseEvents(events);
404 earlyReturn = !pickBVJob.runHelper();
405
406 // THEN
407 QVERIFY(!earlyReturn);
408 QVERIFY(!pickBVJob.currentPicker().isNull());
409 backendPicker = test->nodeManagers()->data<Qt3DRender::Render::ObjectPicker, Qt3DRender::Render::ObjectPickerManager>(handle: pickBVJob.currentPicker());
410 QVERIFY(backendPicker != nullptr);
411 QCOMPARE(backendPicker->peerId(), picker2->id());
412
413 // WHEN
414 events.clear();
415 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(390., 300.), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
416 pickBVJob.setMouseEvents(events);
417 earlyReturn = !pickBVJob.runHelper();
418
419 // THEN
420 QVERIFY(!earlyReturn);
421 QVERIFY(pickBVJob.currentPicker().isNull());
422 }
423
424 void checkEarlyReturnWhenNoMouseEvents_data()
425 {
426 generateAllPickingSettingsCombinations();
427 }
428
429 void checkEarlyReturnWhenNoMouseEvents()
430 {
431 // GIVEN
432 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
433 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
434 QVERIFY(root);
435
436 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
437 QCOMPARE(renderSettings.size(), 1);
438 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
439
440 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
441 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
442 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
443 settings->setPickMethod(pickMethod);
444 settings->setPickResultMode(pickResultMode);
445 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
446
447 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
448
449 // Runs Required jobs
450 runRequiredJobs(test: test.data());
451
452 // THEN
453 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
454 QCOMPARE(pickers.size(), 2);
455
456 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
457 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
458 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
459
460 // WHEN
461 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
462 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
463
464 // THEN
465 QVERIFY(pickBVJob.currentPicker().isNull());
466
467 // WHEN
468 bool earlyReturn = !pickBVJob.runHelper();
469
470 // THEN
471 QVERIFY(earlyReturn);
472
473 // WHEN
474 QList<QPair<QObject *, QMouseEvent>> events;
475 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400., 440.),
476 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
477 pickBVJob.setMouseEvents(events);
478 earlyReturn = !pickBVJob.runHelper();
479
480 // THEN
481 QVERIFY(!earlyReturn);
482 }
483
484 void checkEarlyReturnWhenMoveEventsAndNoCurrentPickers_data()
485 {
486 generateAllPickingSettingsCombinations();
487 }
488
489 void checkEarlyReturnWhenMoveEventsAndNoCurrentPickers()
490 {
491 // GIVEN
492 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
493 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
494 QVERIFY(root);
495
496 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
497 QCOMPARE(renderSettings.size(), 1);
498 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
499
500 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
501 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
502 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
503 settings->setPickMethod(pickMethod);
504 settings->setPickResultMode(pickResultMode);
505 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
506
507 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
508
509 // Runs Required jobs
510 runRequiredJobs(test: test.data());
511
512 // THEN
513 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
514 QCOMPARE(pickers.size(), 2);
515
516 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
517 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
518 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
519
520 // WHEN
521 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
522 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
523
524 QList<QPair<QObject *, QMouseEvent>> events;
525 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(207., 303.),
526 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
527 pickBVJob.setMouseEvents(events);
528
529 // THEN
530 QVERIFY(pickBVJob.currentPicker().isNull());
531
532 // WHEN
533 const bool earlyReturn = !pickBVJob.runHelper();
534
535 // THEN
536 QVERIFY(earlyReturn);
537 }
538
539 void checkEarlyReturnWhenAllPickersDisabled_data()
540 {
541 generateAllPickingSettingsCombinations();
542 }
543
544 void checkEarlyReturnWhenAllPickersDisabled()
545 {
546 // GIVEN
547 QmlSceneReader sceneReader(QUrl("qrc:/testscene_pickersdisabled.qml"));
548 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
549 QVERIFY(root);
550
551 QList<Qt3DRender::QRenderSettings *> renderSettings =
552 root->findChildren<Qt3DRender::QRenderSettings *>();
553 QCOMPARE(renderSettings.size(), 1);
554 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
555
556 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
557 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
558 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
559 settings->setPickMethod(pickMethod);
560 settings->setPickResultMode(pickResultMode);
561 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
562
563 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
564
565 // Runs Required jobs
566 runRequiredJobs(test: test.data());
567
568 // THEN
569 QList<Qt3DRender::QObjectPicker *> pickers =
570 root->findChildren<Qt3DRender::QObjectPicker *>();
571 QCOMPARE(pickers.size(), 2);
572
573 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
574 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
575 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
576
577 // WHEN
578 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
579 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
580
581 QList<QPair<QObject *, QMouseEvent>> events;
582 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207., 303.),
583 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
584 pickBVJob.setMouseEvents(events);
585 bool earlyReturn = !pickBVJob.runHelper();
586
587 // THEN
588 QVERIFY(earlyReturn);
589 }
590
591 void checkEarlyReturnWhenMoveEventsAndDragDisabledPickers_data()
592 {
593 generateAllPickingSettingsCombinations();
594 }
595
596 void checkEarlyReturnWhenMoveEventsAndDragDisabledPickers()
597 {
598 // GIVEN
599 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragdisabled.qml"));
600 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
601 QVERIFY(root);
602
603 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
604 QCOMPARE(renderSettings.size(), 1);
605 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
606
607 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
608 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
609 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
610 settings->setPickMethod(pickMethod);
611 settings->setPickResultMode(pickResultMode);
612 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
613
614 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
615
616 // Runs Required jobs
617 runRequiredJobs(test: test.data());
618
619 // THEN
620 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
621 QCOMPARE(pickers.size(), 2);
622
623 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
624 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
625 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
626
627 // WHEN
628 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
629 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
630
631 QList<QPair<QObject *, QMouseEvent>> events;
632 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207., 303.),
633 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
634 pickBVJob.setMouseEvents(events);
635 bool earlyReturn = !pickBVJob.runHelper();
636
637 // THEN
638 QVERIFY(!pickBVJob.currentPicker().isNull());
639 QVERIFY(!earlyReturn);
640
641 // WHEN
642 events.clear();
643 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(207., 303.),
644 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
645 pickBVJob.setMouseEvents(events);
646 earlyReturn = !pickBVJob.runHelper();
647
648 // THEN
649 QVERIFY(earlyReturn);
650 }
651
652 void checkNoEarlyReturnWhenMoveEventsAndDragEnabledPickers_data()
653 {
654 generateAllPickingSettingsCombinations();
655 }
656
657 void checkNoEarlyReturnWhenMoveEventsAndDragEnabledPickers()
658 {
659 // GIVEN
660 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
661 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
662 QVERIFY(root);
663
664 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
665 QCOMPARE(renderSettings.size(), 1);
666 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
667
668 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
669 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
670 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
671 settings->setPickMethod(pickMethod);
672 settings->setPickResultMode(pickResultMode);
673 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
674
675 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
676
677 // Runs Required jobs
678 runRequiredJobs(test: test.data());
679
680 // THEN
681 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
682 QCOMPARE(pickers.size(), 2);
683
684 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
685 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
686 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
687
688 // WHEN
689 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
690 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
691
692 QList<QPair<QObject *, QMouseEvent>> events;
693 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207., 303.),
694 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
695 pickBVJob.setMouseEvents(events);
696 bool earlyReturn = !pickBVJob.runHelper();
697
698 // THEN
699 QVERIFY(!pickBVJob.currentPicker().isNull());
700 QVERIFY(!earlyReturn);
701
702 // WHEN
703 events.clear();
704 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(207., 303.),
705 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
706 pickBVJob.setMouseEvents(events);
707 earlyReturn = !pickBVJob.runHelper();
708
709 // THEN
710 QVERIFY(!earlyReturn);
711 }
712
713 void checkEarlyReturnWhenNoProperFrameGraph_data()
714 {
715 generateAllPickingSettingsCombinations();
716 }
717
718 void checkEarlyReturnWhenNoProperFrameGraph()
719 {
720 // GIVEN
721 QmlSceneReader sceneReader(QUrl("qrc:/testscene_improperframegraph.qml"));
722 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
723 QVERIFY(root);
724
725 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
726 QCOMPARE(renderSettings.size(), 1);
727 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
728
729 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
730 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
731 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
732 settings->setPickMethod(pickMethod);
733 settings->setPickResultMode(pickResultMode);
734 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
735
736 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
737
738 // Runs Required jobs
739 runRequiredJobs(test: test.data());
740
741 // THEN
742 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
743 QCOMPARE(pickers.size(), 2);
744
745 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
746 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
747 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
748
749 // WHEN
750 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
751 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
752
753 QList<QPair<QObject *, QMouseEvent>> events;
754 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207., 303.),
755 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
756 pickBVJob.setMouseEvents(events);
757 const bool earlyReturn = !pickBVJob.runHelper();
758
759 // THEN
760 QVERIFY(pickBVJob.currentPicker().isNull());
761 QVERIFY(earlyReturn);
762 }
763
764 void checkDispatchMouseEvent_data()
765 {
766 generateAllPickingSettingsCombinations();
767 }
768
769 void checkDispatchMouseEvent()
770 {
771 // GIVEN
772 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
773 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
774 QVERIFY(root);
775 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
776
777 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
778 QCOMPARE(renderSettings.size(), 1);
779 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
780
781 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
782 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
783 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
784 settings->setPickMethod(pickMethod);
785 settings->setPickResultMode(pickResultMode);
786 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
787 test->renderSettings()->syncFromFrontEnd(frontEnd: renderSettings.first(), firstTime: false);
788
789 // Runs Required jobs
790 runRequiredJobs(test: test.data());
791
792 // THEN
793 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
794 QCOMPARE(pickers.size(), 2);
795
796 Qt3DRender::QObjectPicker *picker1 = nullptr;
797 if (pickers.first()->objectName() == QLatin1String("Picker1"))
798 picker1 = pickers.first();
799 else
800 picker1 = pickers.last();
801
802 Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker1->id());
803 QVERIFY(backendPicker1);
804 Qt3DCore::QBackendNodePrivate::get(n: backendPicker1)->setArbiter(test->arbiter());
805
806 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
807 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
808 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
809
810 const bool backAndFrontPicking =
811 (pickMethod == Qt3DRender::QPickingSettings::TrianglePicking) &&
812 (pickResultMode == Qt3DRender::QPickingSettings::AllPicks) &&
813 (faceOrientationPickingMode == Qt3DRender::QPickingSettings::FrontAndBackFace);
814
815 // WHEN -> Pressed on object
816 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
817 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
818
819 QSignalSpy mouseButtonPressedSpy(picker1, &Qt3DRender::QObjectPicker::pressed);
820 QSignalSpy mouseMovedSpy(picker1, &Qt3DRender::QObjectPicker::moved);
821 QSignalSpy mouseButtonReleasedSpy(picker1, &Qt3DRender::QObjectPicker::released);
822 QSignalSpy mouseClickedSpy(picker1, &Qt3DRender::QObjectPicker::clicked);
823
824 QVERIFY(mouseButtonPressedSpy.isValid());
825 QVERIFY(mouseMovedSpy.isValid());
826 QVERIFY(mouseButtonReleasedSpy.isValid());
827 QVERIFY(mouseClickedSpy.isValid());
828
829 QList<QPair<QObject *, QMouseEvent>> events;
830 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0, 303.0),
831 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
832 pickBVJob.setMouseEvents(events);
833 bool earlyReturn = !pickBVJob.runHelper();
834 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
835
836 // THEN -> Pressed
837 QVERIFY(!earlyReturn);
838 QVERIFY(backendPicker1->isPressed());
839 QVERIFY(picker1->isPressed());
840 QCOMPARE(mouseButtonPressedSpy.count(), backAndFrontPicking ? 2 : 1);
841 QCOMPARE(mouseMovedSpy.count(), 0);
842 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
843 QCOMPARE(mouseClickedSpy.count(), 0);
844
845 // WHEN -> Move on same object
846 events.clear();
847 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(207.0, 303.0),
848 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
849 pickBVJob.setMouseEvents(events);
850 earlyReturn = !pickBVJob.runHelper();
851 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
852
853 // THEN -> Moved
854 QVERIFY(!earlyReturn);
855 QVERIFY(backendPicker1->isPressed());
856 QVERIFY(picker1->isPressed());
857 QCOMPARE(mouseButtonPressedSpy.count(), backAndFrontPicking ? 2 : 1);
858 QCOMPARE(mouseMovedSpy.count(), backAndFrontPicking ? 2 : 1);
859 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
860 QCOMPARE(mouseClickedSpy.count(), 0);
861
862 // WHEN -> Release on object
863 events.clear();
864 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(207.0, 303.0),
865 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
866 pickBVJob.setMouseEvents(events);
867 earlyReturn = !pickBVJob.runHelper();
868 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
869
870 // THEN -> Released + Clicked
871 QVERIFY(!earlyReturn);
872 QVERIFY(!backendPicker1->isPressed());
873 QVERIFY(!picker1->isPressed());
874 QCOMPARE(mouseButtonPressedSpy.count(), backAndFrontPicking ? 2 : 1);
875 QCOMPARE(mouseMovedSpy.count(), backAndFrontPicking ? 2 : 1);
876 QCOMPARE(mouseButtonReleasedSpy.count(), /*backAndFrontPicking ? 2 :*/ 1);
877 QCOMPARE(mouseClickedSpy.count(), 1);
878
879 mouseButtonPressedSpy.clear();
880 mouseMovedSpy.clear();
881 mouseButtonReleasedSpy.clear();
882 mouseClickedSpy.clear();
883
884 // WHEN -> Release outside of object
885 events.clear();
886 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0, 303.0),
887 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
888 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(0.0, 0.0),
889 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
890 pickBVJob.setMouseEvents(events);
891 earlyReturn = !pickBVJob.runHelper();
892 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
893
894 // THEN -> Released
895 QVERIFY(!earlyReturn);
896 QVERIFY(!backendPicker1->isPressed());
897 QVERIFY(!picker1->isPressed());
898 QCOMPARE(mouseButtonPressedSpy.count(), backAndFrontPicking ? 2 : 1);
899 QCOMPARE(mouseMovedSpy.count(), 0);
900 QCOMPARE(mouseButtonReleasedSpy.count(), 1);
901 }
902
903 void checkDispatchReleaseEventOnLastPickerWhenMovingOutOfViewport()
904 {
905 // GIVEN
906 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabled.qml"));
907 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
908 QVERIFY(root);
909
910 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
911 QCOMPARE(renderSettings.size(), 1);
912 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
913
914 settings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
915 settings->setPickResultMode(Qt3DRender::QPickingSettings::NearestPick);
916 settings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontAndBackFace);
917
918 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
919 TestArbiter arbiter;
920
921 // Runs Required jobs
922 runRequiredJobs(test: test.data());
923
924 // THEN
925 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
926 QCOMPARE(pickers.size(), 2);
927
928 Qt3DRender::QObjectPicker *picker1 = nullptr;
929 if (pickers.first()->objectName() == QLatin1String("Picker1"))
930 picker1 = pickers.first();
931 else
932 picker1 = pickers.last();
933
934 Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker1->id());
935 QVERIFY(backendPicker1);
936 Qt3DCore::QBackendNodePrivate::get(n: backendPicker1)->setArbiter(&arbiter);
937
938 QSignalSpy mouseButtonPressedSpy(picker1, &Qt3DRender::QObjectPicker::pressed);
939 QSignalSpy mouseMovedSpy(picker1, &Qt3DRender::QObjectPicker::moved);
940 QSignalSpy mouseButtonReleasedSpy(picker1, &Qt3DRender::QObjectPicker::released);
941 QSignalSpy mouseClickedSpy(picker1, &Qt3DRender::QObjectPicker::clicked);
942
943 QVERIFY(mouseButtonPressedSpy.isValid());
944 QVERIFY(mouseMovedSpy.isValid());
945 QVERIFY(mouseButtonReleasedSpy.isValid());
946 QVERIFY(mouseClickedSpy.isValid());
947
948
949 // WHEN -> Pressed on object
950 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
951 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
952
953 QList<QPair<QObject *, QMouseEvent>> events;
954 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(207.0, 303.0),
955 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
956 pickBVJob.setMouseEvents(events);
957 bool earlyReturn = !pickBVJob.runHelper();
958 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
959
960 // THEN -> Pressed
961 QVERIFY(!earlyReturn);
962 QVERIFY(backendPicker1->isPressed());
963 QVERIFY(picker1->isPressed());
964 QCOMPARE(mouseButtonPressedSpy.count(), 1);
965 QCOMPARE(mouseMovedSpy.count(), 0);
966 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
967
968 // WHEN -> Releasing out of the viewport
969 events.clear();
970 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(10000.0, 10000.0),
971 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
972 pickBVJob.setMouseEvents(events);
973 earlyReturn = !pickBVJob.runHelper();
974 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
975
976 // THEN -> Should have received released event
977 QVERIFY(!earlyReturn);
978 QVERIFY(!backendPicker1->isPressed());
979 QVERIFY(!picker1->isPressed());
980 QCOMPARE(mouseButtonPressedSpy.count(), 1);
981 QCOMPARE(mouseMovedSpy.count(), 0);
982 QCOMPARE(mouseButtonReleasedSpy.count(), 1);
983
984
985 // WHEN -> Releasing out of the viewport
986 mouseButtonPressedSpy.clear();
987 mouseMovedSpy.clear();
988 mouseButtonReleasedSpy.clear();
989 events.clear();
990 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(10000.0, 10000.0),
991 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
992 pickBVJob.setMouseEvents(events);
993 earlyReturn = !pickBVJob.runHelper();
994 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
995
996 // THEN -> Should have received nothing
997 QVERIFY(!backendPicker1->isPressed());
998 QVERIFY(!picker1->isPressed());
999 QCOMPARE(mouseButtonPressedSpy.count(), 0);
1000 QCOMPARE(mouseMovedSpy.count(), 0);
1001 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
1002 }
1003
1004 void checkDispatchHoverEvent_data()
1005 {
1006 generateAllPickingSettingsCombinations();
1007 }
1008
1009 void checkDispatchHoverEvent()
1010 {
1011 // GIVEN
1012 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabledhoverenabled.qml"));
1013 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
1014 QVERIFY(root);
1015
1016 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
1017 QCOMPARE(renderSettings.size(), 1);
1018 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
1019
1020 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
1021 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
1022 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
1023 settings->setPickMethod(pickMethod);
1024 settings->setPickResultMode(pickResultMode);
1025 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
1026
1027 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
1028 TestArbiter arbiter;
1029
1030 // Runs Required jobs
1031 runRequiredJobs(test: test.data());
1032
1033 // THEN
1034 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
1035 QCOMPARE(pickers.size(), 2);
1036
1037 Qt3DRender::QObjectPicker *picker1 = nullptr;
1038 if (pickers.first()->objectName() == QLatin1String("Picker1"))
1039 picker1 = pickers.first();
1040 else
1041 picker1 = pickers.last();
1042
1043 Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker1->id());
1044 QVERIFY(backendPicker1);
1045 Qt3DCore::QBackendNodePrivate::get(n: backendPicker1)->setArbiter(&arbiter);
1046
1047 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
1048 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
1049 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
1050
1051 QSignalSpy mouseEntered(picker1, &Qt3DRender::QObjectPicker::entered);
1052 QSignalSpy mouseExited(picker1, &Qt3DRender::QObjectPicker::exited);
1053
1054 QVERIFY(mouseEntered.isValid());
1055 QVERIFY(mouseExited.isValid());
1056
1057 // WHEN -> Hover on object
1058 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
1059 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
1060
1061 QList<QPair<QObject *, QMouseEvent>> events;
1062 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::HoverMove, QPointF(207.0, 303.0),
1063 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1064 pickBVJob.setMouseEvents(events);
1065 bool earlyReturn = !pickBVJob.runHelper();
1066 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1067
1068 // THEN -> Entered
1069 QVERIFY(!earlyReturn);
1070 QVERIFY(!backendPicker1->isPressed());
1071 QVERIFY(!picker1->isPressed());
1072 QCOMPARE(mouseEntered.count(), 1);
1073 QCOMPARE(mouseExited.count(), 0);
1074
1075 // WHEN -> HoverMove Out
1076 events.clear();
1077 events.push_back(t: {nullptr, QMouseEvent(QEvent::HoverMove, QPointF(20.0, 40.0),
1078 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1079 pickBVJob.setMouseEvents(events);
1080 earlyReturn = !pickBVJob.runHelper();
1081 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1082
1083 // THEN - Exited
1084 QVERIFY(!earlyReturn);
1085 QVERIFY(!backendPicker1->isPressed());
1086 QVERIFY(!picker1->isPressed());
1087 QCOMPARE(mouseEntered.count(), 1);
1088 QCOMPARE(mouseExited.count(), 1);
1089
1090 mouseEntered.clear();
1091 mouseExited.clear();
1092
1093 // WHEN -> HoverMove In + Pressed other
1094 events.clear();
1095 events.push_back(t: {nullptr, QMouseEvent(QEvent::HoverMove, QPointF(207.0, 303.0),
1096 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1097 events.push_back(t: {nullptr, QMouseEvent(QEvent::MouseButtonPress, QPointF(0.0, 0.0),
1098 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1099 pickBVJob.setMouseEvents(events);
1100 earlyReturn = !pickBVJob.runHelper();
1101 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1102
1103 // THEN - Entered, Exited
1104 QVERIFY(!earlyReturn);
1105 QVERIFY(!backendPicker1->isPressed());
1106 QVERIFY(!picker1->isPressed());
1107 QCOMPARE(mouseEntered.count(), 1);
1108 QCOMPARE(mouseExited.count(), 1);
1109 }
1110
1111 void shouldDispatchMouseEventFromChildren_data()
1112 {
1113 generateAllPickingSettingsCombinations();
1114 }
1115
1116 void shouldDispatchMouseEventFromChildren()
1117 {
1118 // GIVEN
1119 QmlSceneReader sceneReader(QUrl("qrc:/testscene_childentity.qml"));
1120 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
1121 QVERIFY(root);
1122
1123 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
1124 QCOMPARE(renderSettings.size(), 1);
1125 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
1126
1127 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
1128 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
1129 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
1130 settings->setPickMethod(pickMethod);
1131 settings->setPickResultMode(pickResultMode);
1132 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
1133
1134 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
1135 TestArbiter arbiter;
1136
1137 // Runs Required jobs
1138 runRequiredJobs(test: test.data());
1139
1140 // THEN
1141 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
1142 QCOMPARE(pickers.size(), 1);
1143
1144 Qt3DRender::QObjectPicker *picker = pickers.first();
1145 QCOMPARE(pickers.first()->objectName(), QLatin1String("Picker"));
1146
1147 Qt3DRender::Render::ObjectPicker *backendPicker = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker->id());
1148 QVERIFY(backendPicker);
1149 Qt3DCore::QBackendNodePrivate::get(n: backendPicker)->setArbiter(&arbiter);
1150
1151 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
1152 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
1153 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
1154
1155 const bool backAndFrontPicking =
1156 (pickMethod == Qt3DRender::QPickingSettings::TrianglePicking) &&
1157 (pickResultMode == Qt3DRender::QPickingSettings::AllPicks) &&
1158 (faceOrientationPickingMode == Qt3DRender::QPickingSettings::FrontAndBackFace);
1159
1160 QSignalSpy mouseButtonPressedSpy(picker, &Qt3DRender::QObjectPicker::pressed);
1161 QSignalSpy mouseMovedSpy(picker, &Qt3DRender::QObjectPicker::moved);
1162 QSignalSpy mouseButtonReleasedSpy(picker, &Qt3DRender::QObjectPicker::released);
1163 QSignalSpy mouseClickedSpy(picker, &Qt3DRender::QObjectPicker::clicked);
1164
1165 QVERIFY(mouseButtonPressedSpy.isValid());
1166 QVERIFY(mouseMovedSpy.isValid());
1167 QVERIFY(mouseButtonReleasedSpy.isValid());
1168 QVERIFY(mouseClickedSpy.isValid());
1169
1170 // WHEN -> Pressed on object
1171 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
1172 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
1173
1174 QList<QPair<QObject *, QMouseEvent>> events;
1175 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400.0, 300.0),
1176 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1177 pickBVJob.setMouseEvents(events);
1178 bool earlyReturn = !pickBVJob.runHelper();
1179 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1180
1181 // THEN -> Pressed
1182 QVERIFY(!earlyReturn);
1183 QVERIFY(backendPicker->isPressed());
1184 QVERIFY(picker->isPressed());
1185 QCOMPARE(mouseButtonPressedSpy.count(), backAndFrontPicking ? 2 : 1);
1186 QCOMPARE(mouseMovedSpy.count(), 0);
1187 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
1188 QCOMPARE(mouseClickedSpy.count(), 0);
1189
1190 // WHEN -> Move on same object
1191 mouseButtonPressedSpy.clear();
1192 events.clear();
1193 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(400.0, 300.0),
1194 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1195 pickBVJob.setMouseEvents(events);
1196 earlyReturn = !pickBVJob.runHelper();
1197 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1198
1199 // THEN -> Moved
1200 QVERIFY(!earlyReturn);
1201 QVERIFY(backendPicker->isPressed());
1202 QVERIFY(picker->isPressed());
1203 QCOMPARE(mouseButtonPressedSpy.count(), 0);
1204 QCOMPARE(mouseMovedSpy.count(), backAndFrontPicking ? 2 : 1);
1205 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
1206 QCOMPARE(mouseClickedSpy.count(), 0);
1207
1208 // WHEN -> Release on object
1209 mouseMovedSpy.clear();
1210 events.clear();
1211 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(400.0, 300.0),
1212 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1213 pickBVJob.setMouseEvents(events);
1214 earlyReturn = !pickBVJob.runHelper();
1215 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1216
1217 // THEN -> Released + Clicked
1218 QVERIFY(!earlyReturn);
1219 QVERIFY(!backendPicker->isPressed());
1220 QVERIFY(!picker->isPressed());
1221 QCOMPARE(mouseButtonPressedSpy.count(), 0);
1222 QCOMPARE(mouseMovedSpy.count(), 0);
1223 QCOMPARE(mouseButtonReleasedSpy.count(), 1);
1224 QCOMPARE(mouseClickedSpy.count(), 1);
1225
1226 // WHEN -> Release outside of object
1227 events.clear();
1228 mouseButtonPressedSpy.clear();
1229 mouseMovedSpy.clear();
1230 mouseButtonReleasedSpy.clear();
1231
1232 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400., 300.),
1233 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1234 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(0., 0.),
1235 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1236 pickBVJob.setMouseEvents(events);
1237 earlyReturn = !pickBVJob.runHelper();
1238 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1239
1240 // THEN -> Released
1241 QVERIFY(!earlyReturn);
1242 QVERIFY(!backendPicker->isPressed());
1243 QVERIFY(!picker->isPressed());
1244 QCOMPARE(mouseButtonPressedSpy.count(), backAndFrontPicking ? 2 : 1);
1245 QCOMPARE(mouseMovedSpy.count(), 0);
1246 QCOMPARE(mouseButtonReleasedSpy.count(), 1);
1247 QCOMPARE(mouseClickedSpy.count(), 1);
1248 }
1249
1250 void checkPickerGrabbing_data()
1251 {
1252 generateAllPickingSettingsCombinations();
1253 }
1254
1255 void checkPickerGrabbing()
1256 {
1257 // GIVEN
1258 QmlSceneReader sceneReader(QUrl("qrc:/testscene_dragenabledoverlapping.qml"));
1259 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
1260 QVERIFY(root);
1261
1262 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
1263 QCOMPARE(renderSettings.size(), 1);
1264 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
1265
1266 QFETCH(Qt3DRender::QPickingSettings::PickMethod, pickMethod);
1267 QFETCH(Qt3DRender::QPickingSettings::PickResultMode, pickResultMode);
1268 QFETCH(Qt3DRender::QPickingSettings::FaceOrientationPickingMode, faceOrientationPickingMode);
1269 settings->setPickMethod(pickMethod);
1270 settings->setPickResultMode(pickResultMode);
1271 settings->setFaceOrientationPickingMode(faceOrientationPickingMode);
1272
1273 const bool backAndFrontPicking =
1274 (pickMethod == Qt3DRender::QPickingSettings::TrianglePicking) &&
1275 (pickResultMode == Qt3DRender::QPickingSettings::AllPicks) &&
1276 (faceOrientationPickingMode == Qt3DRender::QPickingSettings::FrontAndBackFace);
1277
1278 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
1279 TestArbiter arbiter1;
1280 TestArbiter arbiter2;
1281
1282 // Runs Required jobs
1283 runRequiredJobs(test: test.data());
1284
1285 // THEN
1286 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
1287 QCOMPARE(pickers.size(), 2);
1288
1289 Qt3DRender::QObjectPicker *picker1 = nullptr;
1290 Qt3DRender::QObjectPicker *picker2 = nullptr;
1291 if (pickers.first()->objectName() == QLatin1String("Picker1")) {
1292 picker1 = pickers.first();
1293 picker2 = pickers.last();
1294 } else {
1295 picker1 = pickers.last();
1296 picker2 = pickers.first();
1297 }
1298
1299 Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker1->id());
1300 QVERIFY(backendPicker1);
1301 Qt3DCore::QBackendNodePrivate::get(n: backendPicker1)->setArbiter(&arbiter1);
1302
1303 Qt3DRender::Render::ObjectPicker *backendPicker2 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker2->id());
1304 QVERIFY(backendPicker2);
1305 Qt3DCore::QBackendNodePrivate::get(n: backendPicker2)->setArbiter(&arbiter2);
1306
1307 QCOMPARE(test->renderSettings()->pickMethod(), pickMethod);
1308 QCOMPARE(test->renderSettings()->pickResultMode(), pickResultMode);
1309 QCOMPARE(test->renderSettings()->faceOrientationPickingMode(), faceOrientationPickingMode);
1310
1311 QSignalSpy mouseEntered1(picker1, &Qt3DRender::QObjectPicker::entered);
1312 QSignalSpy mouseExited1(picker1, &Qt3DRender::QObjectPicker::exited);
1313 QSignalSpy mouseButtonPressedSpy1(picker1, &Qt3DRender::QObjectPicker::pressed);
1314 QSignalSpy mouseMovedSpy1(picker1, &Qt3DRender::QObjectPicker::moved);
1315 QSignalSpy mouseButtonReleasedSpy1(picker1, &Qt3DRender::QObjectPicker::released);
1316 QSignalSpy mouseClickedSpy1(picker1, &Qt3DRender::QObjectPicker::clicked);
1317
1318 QVERIFY(mouseButtonPressedSpy1.isValid());
1319 QVERIFY(mouseMovedSpy1.isValid());
1320 QVERIFY(mouseButtonReleasedSpy1.isValid());
1321 QVERIFY(mouseClickedSpy1.isValid());
1322 QVERIFY(mouseEntered1.isValid());
1323 QVERIFY(mouseExited1.isValid());
1324
1325 QSignalSpy mouseEntered2(picker2, &Qt3DRender::QObjectPicker::entered);
1326 QSignalSpy mouseExited2(picker2, &Qt3DRender::QObjectPicker::exited);
1327 QSignalSpy mouseButtonPressedSpy2(picker2, &Qt3DRender::QObjectPicker::pressed);
1328 QSignalSpy mouseMovedSpy2(picker2, &Qt3DRender::QObjectPicker::moved);
1329 QSignalSpy mouseButtonReleasedSpy2(picker2, &Qt3DRender::QObjectPicker::released);
1330 QSignalSpy mouseClickedSpy2(picker2, &Qt3DRender::QObjectPicker::clicked);
1331
1332 QVERIFY(mouseButtonPressedSpy2.isValid());
1333 QVERIFY(mouseMovedSpy2.isValid());
1334 QVERIFY(mouseButtonReleasedSpy2.isValid());
1335 QVERIFY(mouseClickedSpy2.isValid());
1336 QVERIFY(mouseEntered2.isValid());
1337 QVERIFY(mouseExited2.isValid());
1338
1339 // WHEN -> Pressed on object
1340 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
1341 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
1342
1343 QList<QPair<QObject *, QMouseEvent>> events;
1344 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(320., 303.),
1345 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1346 pickBVJob.setMouseEvents(events);
1347 bool earlyReturn = !pickBVJob.runHelper();
1348 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1349
1350 // THEN -> Pressed
1351 QVERIFY(!earlyReturn);
1352 QVERIFY(backendPicker1->isPressed());
1353 QVERIFY(picker1->isPressed());
1354
1355 QCOMPARE(mouseButtonPressedSpy1.count(), backAndFrontPicking ? 2 : 1);
1356 QCOMPARE(mouseMovedSpy1.count(), 0);
1357 QCOMPARE(mouseButtonReleasedSpy1.count(), 0);
1358 QCOMPARE(mouseClickedSpy1.count(), 0);
1359 QCOMPARE(mouseEntered1.count(), 0);
1360 QCOMPARE(mouseExited1.count(), 0);
1361
1362 // WHEN -> Move on next object, show stay on previous picker unless all picks are requested
1363 events.clear();
1364 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseMove, QPointF(280., 303.),
1365 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1366 pickBVJob.setMouseEvents(events);
1367 earlyReturn = !pickBVJob.runHelper();
1368 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1369
1370 // THEN -> Moved over the second picker, is the first one still pressed
1371 QVERIFY(!earlyReturn);
1372 if (pickResultMode != Qt3DRender::QPickingSettings::AllPicks) {
1373 QVERIFY(backendPicker1->isPressed());
1374 QVERIFY(picker1->isPressed());
1375 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1376 QCOMPARE(mouseMovedSpy1.count(), 1);
1377 QCOMPARE(mouseButtonReleasedSpy1.count(), 0);
1378 QCOMPARE(mouseClickedSpy1.count(), 0);
1379 QCOMPARE(mouseEntered1.count(), 0);
1380 QCOMPARE(mouseExited1.count(), 0);
1381 } else {
1382 QVERIFY(!picker2->isPressed());
1383 QCOMPARE(mouseButtonPressedSpy2.count(), 0);
1384 QCOMPARE(mouseMovedSpy2.count(), backAndFrontPicking ? 2 : 1);
1385 QCOMPARE(mouseButtonReleasedSpy2.count(), 0);
1386 QCOMPARE(mouseClickedSpy2.count(), 0);
1387 QCOMPARE(mouseEntered2.count(), 1);
1388 QCOMPARE(mouseExited2.count(), 0);
1389 }
1390 }
1391
1392 void checkParentNoPickerChildPicker()
1393 {
1394 // GIVEN
1395 QmlSceneReader sceneReader(QUrl("qrc:/testscene_parententity.qml"));
1396 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
1397 QVERIFY(root);
1398
1399 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
1400 QCOMPARE(renderSettings.size(), 1);
1401 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
1402
1403 settings->setPickMethod(Qt3DRender::QPickingSettings::BoundingVolumePicking);
1404 settings->setPickResultMode(Qt3DRender::QPickingSettings::NearestPick);
1405 settings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontFace);
1406
1407 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
1408 TestArbiter arbiter;
1409
1410 // Runs Required jobs
1411 runRequiredJobs(test: test.data());
1412
1413 // THEN
1414 // large no pickable object encapsing child and camera should not interfere with smaller picking object
1415 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
1416 QCOMPARE(pickers.size(), 1);
1417
1418 Qt3DRender::QObjectPicker *picker = pickers.first();
1419 QCOMPARE(pickers.first()->objectName(), QLatin1String("Picker"));
1420
1421 Qt3DRender::Render::ObjectPicker *backendPicker = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker->id());
1422 QVERIFY(backendPicker);
1423 Qt3DCore::QBackendNodePrivate::get(n: backendPicker)->setArbiter(&arbiter);
1424
1425 QSignalSpy mouseEntered(picker, &Qt3DRender::QObjectPicker::entered);
1426 QSignalSpy mouseExited(picker, &Qt3DRender::QObjectPicker::exited);
1427 QSignalSpy mouseButtonPressedSpy(picker, &Qt3DRender::QObjectPicker::pressed);
1428 QSignalSpy mouseMovedSpy(picker, &Qt3DRender::QObjectPicker::moved);
1429 QSignalSpy mouseButtonReleasedSpy(picker, &Qt3DRender::QObjectPicker::released);
1430 QSignalSpy mouseClickedSpy(picker, &Qt3DRender::QObjectPicker::clicked);
1431
1432 QVERIFY(mouseButtonPressedSpy.isValid());
1433 QVERIFY(mouseMovedSpy.isValid());
1434 QVERIFY(mouseButtonReleasedSpy.isValid());
1435 QVERIFY(mouseClickedSpy.isValid());
1436 QVERIFY(mouseEntered.isValid());
1437 QVERIFY(mouseExited.isValid());
1438
1439 // WHEN -> Pressed on object
1440 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
1441 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
1442
1443 QList<QPair<QObject *, QMouseEvent>> events;
1444 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(400., 300.),
1445 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1446 pickBVJob.setMouseEvents(events);
1447 bool earlyReturn = !pickBVJob.runHelper();
1448 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1449
1450 // THEN -> Pressed
1451 QVERIFY(!earlyReturn);
1452 QVERIFY(backendPicker->isPressed());
1453 QVERIFY(picker->isPressed());
1454 QCOMPARE(mouseButtonPressedSpy.count(), 1);
1455 QCOMPARE(mouseMovedSpy.count(), 0);
1456 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
1457 QCOMPARE(mouseClickedSpy.count(), 0);
1458 QCOMPARE(mouseEntered.count(), 0);
1459 QCOMPARE(mouseExited.count(), 0);
1460 }
1461
1462 void checkPickerAndViewports()
1463 {
1464 // GIVEN
1465 QmlSceneReader sceneReader(QUrl("qrc:/testscene_viewports.qml"));
1466 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
1467 QVERIFY(root);
1468
1469 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
1470 QCOMPARE(renderSettings.size(), 1);
1471 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
1472
1473 settings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
1474 settings->setPickResultMode(Qt3DRender::QPickingSettings::NearestPick);
1475 settings->setFaceOrientationPickingMode(Qt3DRender::QPickingSettings::FrontFace);
1476
1477 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
1478 TestArbiter arbiter;
1479
1480 // Runs Required jobs
1481 runRequiredJobs(test: test.data());
1482
1483 // THEN
1484 // object partially obscured by another viewport, make sure only visible portion is pickable
1485 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
1486 QCOMPARE(pickers.size(), 2);
1487
1488 Qt3DRender::QObjectPicker *picker = pickers.last();
1489 QCOMPARE(picker->objectName(), QLatin1String("Picker2"));
1490
1491 Qt3DRender::Render::ObjectPicker *backendPicker = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker->id());
1492 QVERIFY(backendPicker);
1493 Qt3DCore::QBackendNodePrivate::get(n: backendPicker)->setArbiter(&arbiter);
1494
1495 QSignalSpy mouseEntered(picker, &Qt3DRender::QObjectPicker::entered);
1496 QSignalSpy mouseExited(picker, &Qt3DRender::QObjectPicker::exited);
1497 QSignalSpy mouseButtonPressedSpy(picker, &Qt3DRender::QObjectPicker::pressed);
1498 QSignalSpy mouseMovedSpy(picker, &Qt3DRender::QObjectPicker::moved);
1499 QSignalSpy mouseButtonReleasedSpy(picker, &Qt3DRender::QObjectPicker::released);
1500 QSignalSpy mouseClickedSpy(picker, &Qt3DRender::QObjectPicker::clicked);
1501
1502 QVERIFY(mouseButtonPressedSpy.isValid());
1503 QVERIFY(mouseMovedSpy.isValid());
1504 QVERIFY(mouseButtonReleasedSpy.isValid());
1505 QVERIFY(mouseClickedSpy.isValid());
1506 QVERIFY(mouseEntered.isValid());
1507 QVERIFY(mouseExited.isValid());
1508
1509 // WHEN -> Pressed on object in vp1
1510 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
1511 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
1512
1513 QList<QPair<QObject *, QMouseEvent>> events;
1514 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(280., 300.),
1515 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1516 pickBVJob.setMouseEvents(events);
1517 bool earlyReturn = !pickBVJob.runHelper();
1518 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1519
1520 // THEN -> Pressed
1521 QVERIFY(!earlyReturn);
1522 QVERIFY(backendPicker->isPressed());
1523 QVERIFY(picker->isPressed());
1524 QCOMPARE(mouseButtonPressedSpy.count(), 1);
1525 QCOMPARE(mouseMovedSpy.count(), 0);
1526 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
1527 QCOMPARE(mouseClickedSpy.count(), 0);
1528 QCOMPARE(mouseEntered.count(), 0);
1529 QCOMPARE(mouseExited.count(), 0);
1530
1531 // WHEN reset -> Presset on object in vp2
1532 backendPicker->cleanup();
1533 backendPicker->setEnabled(true);
1534 events.clear();
1535
1536 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(320., 300.),
1537 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1538 pickBVJob.setMouseEvents(events);
1539 earlyReturn = !pickBVJob.runHelper();
1540 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1541
1542 // THEN -> Nothing happened
1543 QVERIFY(!earlyReturn);
1544 QVERIFY(!backendPicker->isPressed());
1545 QVERIFY(picker->isPressed());
1546 QCOMPARE(mouseButtonPressedSpy.count(), 1);
1547 QCOMPARE(mouseMovedSpy.count(), 0);
1548 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
1549 QCOMPARE(mouseClickedSpy.count(), 0);
1550 QCOMPARE(mouseEntered.count(), 0);
1551 QCOMPARE(mouseExited.count(), 0);
1552 }
1553
1554 void checkPickerAndLayerFilters()
1555 {
1556 // GIVEN
1557 QmlSceneReader sceneReader(QUrl("qrc:/testscene_layerfilter.qml"));
1558 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
1559 QVERIFY(root);
1560
1561 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
1562 TestArbiter arbiter;
1563
1564 // Runs Required jobs
1565 runRequiredJobs(test: test.data());
1566
1567 // THEN
1568 // object partially obscured by another viewport, make sure only visible portion is pickable
1569 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
1570 QCOMPARE(pickers.size(), 2);
1571
1572 Qt3DRender::QObjectPicker *picker1 = pickers.front();
1573 QCOMPARE(picker1->objectName(), QLatin1String("Picker1"));
1574
1575 Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker1->id());
1576 QVERIFY(backendPicker1);
1577
1578 QSignalSpy mouseButtonPressedSpy1(picker1, &Qt3DRender::QObjectPicker::pressed);
1579
1580 QVERIFY(mouseButtonPressedSpy1.isValid());
1581
1582 Qt3DRender::QObjectPicker *picker2 = pickers.last();
1583 QCOMPARE(picker2->objectName(), QLatin1String("Picker2"));
1584
1585 Qt3DRender::Render::ObjectPicker *backendPicker2 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker2->id());
1586 QVERIFY(backendPicker2);
1587
1588 QSignalSpy mouseButtonPressedSpy2(picker2, &Qt3DRender::QObjectPicker::pressed);
1589
1590 QVERIFY(mouseButtonPressedSpy2.isValid());
1591
1592 // WHEN -> Pressed on object in vp1
1593 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
1594 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
1595
1596 {
1597 QList<QPair<QObject *, QMouseEvent>> events;
1598 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(150., 300.),
1599 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier) });
1600 pickBVJob.setMouseEvents(events);
1601 bool earlyReturn = !pickBVJob.runHelper();
1602 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1603
1604 // THEN -> Pressed
1605 QVERIFY(!earlyReturn);
1606 QVERIFY(backendPicker1->isPressed());
1607 QVERIFY(picker1->isPressed());
1608 QVERIFY(!backendPicker2->isPressed());
1609 QVERIFY(!picker2->isPressed());
1610 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1611 QCOMPARE(mouseButtonPressedSpy2.count(), 0);
1612
1613 events.clear();
1614
1615 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(150., 300.),
1616 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1617 pickBVJob.setMouseEvents(events);
1618 pickBVJob.runHelper();
1619 }
1620
1621 {
1622 QList<QPair<QObject *, QMouseEvent>> events;
1623 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(450., 300.),
1624 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1625 pickBVJob.setMouseEvents(events);
1626 bool earlyReturn = !pickBVJob.runHelper();
1627 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1628
1629 // THEN -> Nothing happened
1630 QVERIFY(!earlyReturn);
1631 QVERIFY(backendPicker2->isPressed());
1632 QVERIFY(picker2->isPressed());
1633 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1634 QCOMPARE(mouseButtonPressedSpy2.count(), 1);
1635 }
1636 }
1637
1638 void checkPickerAndNestedLayerFilters()
1639 {
1640 // GIVEN
1641 QmlSceneReader sceneReader(QUrl("qrc:/testscene_nested_layerfilter.qml"));
1642 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
1643 QVERIFY(root);
1644
1645 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
1646 TestArbiter arbiter;
1647
1648 // Runs Required jobs
1649 runRequiredJobs(test: test.data());
1650
1651 // THEN
1652 // object partially obscured by another viewport, make sure only visible portion is pickable
1653 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
1654 QCOMPARE(pickers.size(), 5);
1655
1656 Qt3DRender::QObjectPicker *picker1 = pickers[0];
1657 QCOMPARE(picker1->objectName(), QLatin1String("Picker1"));
1658 Qt3DRender::QObjectPicker *picker2 = pickers[1];
1659 QCOMPARE(picker2->objectName(), QLatin1String("Picker2"));
1660 Qt3DRender::QObjectPicker *picker3 = pickers[2];
1661 QCOMPARE(picker3->objectName(), QLatin1String("Picker3"));
1662 Qt3DRender::QObjectPicker *picker4 = pickers[3];
1663 QCOMPARE(picker4->objectName(), QLatin1String("Picker4"));
1664 Qt3DRender::QObjectPicker *picker5 = pickers[4];
1665 QCOMPARE(picker5->objectName(), QLatin1String("Picker5"));
1666
1667 Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker1->id());
1668 QVERIFY(backendPicker1);
1669
1670 QSignalSpy mouseButtonPressedSpy1(picker1, &Qt3DRender::QObjectPicker::pressed);
1671 QVERIFY(mouseButtonPressedSpy1.isValid());
1672
1673 Qt3DRender::Render::ObjectPicker *backendPicker2 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker2->id());
1674 QVERIFY(backendPicker2);
1675
1676 QSignalSpy mouseButtonPressedSpy2(picker2, &Qt3DRender::QObjectPicker::pressed);
1677 QVERIFY(mouseButtonPressedSpy2.isValid());
1678
1679 Qt3DRender::Render::ObjectPicker *backendPicker3 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker3->id());
1680 QVERIFY(backendPicker3);
1681
1682 QSignalSpy mouseButtonPressedSpy3(picker3, &Qt3DRender::QObjectPicker::pressed);
1683 QVERIFY(mouseButtonPressedSpy3.isValid());
1684
1685 Qt3DRender::Render::ObjectPicker *backendPicker4 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker4->id());
1686 QVERIFY(backendPicker4);
1687
1688 QSignalSpy mouseButtonPressedSpy4(picker4, &Qt3DRender::QObjectPicker::pressed);
1689 QVERIFY(mouseButtonPressedSpy4.isValid());
1690
1691 Qt3DRender::Render::ObjectPicker *backendPicker5 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker5->id());
1692 QVERIFY(backendPicker5);
1693
1694 QSignalSpy mouseButtonPressedSpy5(picker5, &Qt3DRender::QObjectPicker::pressed);
1695 QVERIFY(mouseButtonPressedSpy5.isValid());
1696
1697 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
1698 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
1699
1700 // Picker1 -> Viewport 1
1701 // Picker2 -> Viewport 2
1702 // Picker3 -> No Viewport
1703 // Picker4 -> Viewport 1 and 2
1704 // Picker5 -> Viewport 1
1705
1706 // WHEN -> Pressed on object1 in VP1
1707 {
1708 QList<QPair<QObject *, QMouseEvent>> events;
1709 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(200.0f, 300.0f),
1710 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1711 pickBVJob.setMouseEvents(events);
1712 bool earlyReturn = !pickBVJob.runHelper();
1713 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1714
1715 // THEN -> Pressed
1716 QVERIFY(!earlyReturn);
1717 QVERIFY(backendPicker1->isPressed());
1718 QVERIFY(picker1->isPressed());
1719 QVERIFY(!backendPicker2->isPressed());
1720 QVERIFY(!picker2->isPressed());
1721 QVERIFY(!backendPicker3->isPressed());
1722 QVERIFY(!picker3->isPressed());
1723 QVERIFY(!backendPicker4->isPressed());
1724 QVERIFY(!picker4->isPressed());
1725 QVERIFY(!backendPicker5->isPressed());
1726 QVERIFY(!picker5->isPressed());
1727 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1728 QCOMPARE(mouseButtonPressedSpy2.count(), 0);
1729 QCOMPARE(mouseButtonPressedSpy3.count(), 0);
1730 QCOMPARE(mouseButtonPressedSpy4.count(), 0);
1731 QCOMPARE(mouseButtonPressedSpy5.count(), 0);
1732
1733 events.clear();
1734
1735 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(200.0f, 300.0f),
1736 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1737 pickBVJob.setMouseEvents(events);
1738 pickBVJob.runHelper();
1739 }
1740
1741 // WHEN -> Pressed on object2 in VP2
1742 {
1743 QList<QPair<QObject *, QMouseEvent>> events;
1744 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(541.0f, 183.0f),
1745 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1746 pickBVJob.setMouseEvents(events);
1747 bool earlyReturn = !pickBVJob.runHelper();
1748 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1749
1750 // THEN -> Pressed
1751 QVERIFY(!earlyReturn);
1752 QVERIFY(!backendPicker1->isPressed());
1753 QVERIFY(!picker1->isPressed());
1754 QVERIFY(backendPicker2->isPressed());
1755 QVERIFY(picker2->isPressed());
1756 QVERIFY(!backendPicker3->isPressed());
1757 QVERIFY(!picker3->isPressed());
1758 QVERIFY(!backendPicker4->isPressed());
1759 QVERIFY(!picker4->isPressed());
1760 QVERIFY(!backendPicker5->isPressed());
1761 QVERIFY(!picker5->isPressed());
1762 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1763 QCOMPARE(mouseButtonPressedSpy2.count(), 1);
1764 QCOMPARE(mouseButtonPressedSpy3.count(), 0);
1765 QCOMPARE(mouseButtonPressedSpy4.count(), 0);
1766 QCOMPARE(mouseButtonPressedSpy5.count(), 0);
1767
1768 events.clear();
1769
1770 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(541.0f, 183.0f),
1771 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1772 pickBVJob.setMouseEvents(events);
1773 pickBVJob.runHelper();
1774 }
1775
1776 // WHEN -> Pressed on object3 in VP1
1777 {
1778 QList<QPair<QObject *, QMouseEvent>> events;
1779 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(80.0f, 150.0f),
1780 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1781 pickBVJob.setMouseEvents(events);
1782 bool earlyReturn = !pickBVJob.runHelper();
1783 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1784
1785 // THEN -> Nothing Pressed as not selected by Layer
1786 QVERIFY(!earlyReturn);
1787 QVERIFY(!backendPicker1->isPressed());
1788 QVERIFY(!picker1->isPressed());
1789 QVERIFY(!backendPicker2->isPressed());
1790 QVERIFY(!picker2->isPressed());
1791 QVERIFY(!backendPicker3->isPressed());
1792 QVERIFY(!picker3->isPressed());
1793 QVERIFY(!backendPicker4->isPressed());
1794 QVERIFY(!picker4->isPressed());
1795 QVERIFY(!backendPicker5->isPressed());
1796 QVERIFY(!picker5->isPressed());
1797 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1798 QCOMPARE(mouseButtonPressedSpy2.count(), 1);
1799 QCOMPARE(mouseButtonPressedSpy3.count(), 0);
1800 QCOMPARE(mouseButtonPressedSpy4.count(), 0);
1801 QCOMPARE(mouseButtonPressedSpy5.count(), 0);
1802 }
1803
1804 // WHEN -> Pressed on object3 in VP2
1805 {
1806 QList<QPair<QObject *, QMouseEvent>> events;
1807 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(504.0f, 263.0f),
1808 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1809 pickBVJob.setMouseEvents(events);
1810 bool earlyReturn = !pickBVJob.runHelper();
1811 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1812
1813 // THEN -> Nothing Pressed as not selected by Layer
1814 QVERIFY(!earlyReturn);
1815 QVERIFY(!backendPicker1->isPressed());
1816 QVERIFY(!picker1->isPressed());
1817 QVERIFY(!backendPicker2->isPressed());
1818 QVERIFY(!picker2->isPressed());
1819 QVERIFY(!backendPicker3->isPressed());
1820 QVERIFY(!picker3->isPressed());
1821 QVERIFY(!backendPicker4->isPressed());
1822 QVERIFY(!picker4->isPressed());
1823 QVERIFY(!backendPicker5->isPressed());
1824 QVERIFY(!picker5->isPressed());
1825 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1826 QCOMPARE(mouseButtonPressedSpy2.count(), 1);
1827 QCOMPARE(mouseButtonPressedSpy3.count(), 0);
1828 QCOMPARE(mouseButtonPressedSpy4.count(), 0);
1829 QCOMPARE(mouseButtonPressedSpy5.count(), 0);
1830 }
1831
1832 // WHEN -> Pressed on object4 in VP1
1833 {
1834 QList<QPair<QObject *, QMouseEvent>> events;
1835 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(160.0f, 431.0f),
1836 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1837 pickBVJob.setMouseEvents(events);
1838 bool earlyReturn = !pickBVJob.runHelper();
1839 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1840
1841 // THEN -> Pressed
1842 QVERIFY(!earlyReturn);
1843 QVERIFY(!backendPicker1->isPressed());
1844 QVERIFY(!picker1->isPressed());
1845 QVERIFY(!backendPicker2->isPressed());
1846 QVERIFY(!picker2->isPressed());
1847 QVERIFY(!backendPicker3->isPressed());
1848 QVERIFY(!picker3->isPressed());
1849 QVERIFY(backendPicker4->isPressed());
1850 QVERIFY(picker4->isPressed());
1851 QVERIFY(!backendPicker5->isPressed());
1852 QVERIFY(!picker5->isPressed());
1853 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1854 QCOMPARE(mouseButtonPressedSpy2.count(), 1);
1855 QCOMPARE(mouseButtonPressedSpy3.count(), 0);
1856 QCOMPARE(mouseButtonPressedSpy4.count(), 1);
1857 QCOMPARE(mouseButtonPressedSpy5.count(), 0);
1858
1859 events.clear();
1860
1861 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(160.0f, 431.0f),
1862 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1863 pickBVJob.setMouseEvents(events);
1864 pickBVJob.runHelper();
1865 }
1866
1867 // WHEN -> Pressed on object4 in VP2
1868 {
1869 QList<QPair<QObject *, QMouseEvent>> events;
1870 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(447.0f, 472.0f),
1871 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1872 pickBVJob.setMouseEvents(events);
1873 bool earlyReturn = !pickBVJob.runHelper();
1874 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1875
1876 // THEN -> Pressed
1877 QVERIFY(!earlyReturn);
1878 QVERIFY(!backendPicker1->isPressed());
1879 QVERIFY(!picker1->isPressed());
1880 QVERIFY(!backendPicker2->isPressed());
1881 QVERIFY(!picker2->isPressed());
1882 QVERIFY(!backendPicker3->isPressed());
1883 QVERIFY(!picker3->isPressed());
1884 QVERIFY(backendPicker4->isPressed());
1885 QVERIFY(picker4->isPressed());
1886 QVERIFY(!backendPicker5->isPressed());
1887 QVERIFY(!picker5->isPressed());
1888 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1889 QCOMPARE(mouseButtonPressedSpy2.count(), 1);
1890 QCOMPARE(mouseButtonPressedSpy3.count(), 0);
1891 QCOMPARE(mouseButtonPressedSpy4.count(), 2);
1892 QCOMPARE(mouseButtonPressedSpy5.count(), 0);
1893
1894 events.clear();
1895
1896 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(447.0f, 472.0f),
1897 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1898 pickBVJob.setMouseEvents(events);
1899 pickBVJob.runHelper();
1900 }
1901
1902 // WHEN -> Pressed on object5 in VP1
1903 {
1904 QList<QPair<QObject *, QMouseEvent>> events;
1905 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(153.0f, 195.0f),
1906 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1907 pickBVJob.setMouseEvents(events);
1908 bool earlyReturn = !pickBVJob.runHelper();
1909 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
1910
1911 // THEN -> Pressed
1912 QVERIFY(!earlyReturn);
1913 QVERIFY(!backendPicker1->isPressed());
1914 QVERIFY(!picker1->isPressed());
1915 QVERIFY(!backendPicker2->isPressed());
1916 QVERIFY(!picker2->isPressed());
1917 QVERIFY(!backendPicker3->isPressed());
1918 QVERIFY(!picker3->isPressed());
1919 QVERIFY(!backendPicker4->isPressed());
1920 QVERIFY(!picker4->isPressed());
1921 QVERIFY(backendPicker5->isPressed());
1922 QVERIFY(picker5->isPressed());
1923 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
1924 QCOMPARE(mouseButtonPressedSpy2.count(), 1);
1925 QCOMPARE(mouseButtonPressedSpy3.count(), 0);
1926 QCOMPARE(mouseButtonPressedSpy4.count(), 2);
1927 QCOMPARE(mouseButtonPressedSpy5.count(), 1);
1928
1929 events.clear();
1930
1931 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(153.0f, 195.0f),
1932 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
1933 pickBVJob.setMouseEvents(events);
1934 pickBVJob.runHelper();
1935 }
1936 }
1937
1938 void checkMultipleRayDirections_data()
1939 {
1940 QTest::addColumn<QVector3D>(name: "cameraOrigin");
1941 QTest::addColumn<QVector3D>(name: "cameraUpVector");
1942
1943 int k = 0;
1944 const int n = 10;
1945 for (int j=0; j<n; j++) {
1946 QMatrix4x4 m;
1947 m.rotate(angle: 360.f / (float)n * (float)j, x: 0.f, y: 0.f, z: 1.f);
1948 for (int i=0; i<n; i++) {
1949 const double angle = M_PI * 2. / (double)n * i;
1950 const double x = std::sin(x: angle) * 10.;
1951 const double z = std::cos(x: angle) * 10.;
1952 QVector3D pos(x, 0.f, z);
1953 QVector3D up(0.f, 1.f, 0.f);
1954 QTest::newRow(dataTag: QString::number(k++).toLatin1().data()) << m * pos << m * up;
1955 }
1956 }
1957 }
1958
1959 void checkMultipleRayDirections()
1960 {
1961 // GIVEN
1962 QmlSceneReader sceneReader(QUrl("qrc:/testscene_cameraposition.qml"));
1963 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
1964 QVERIFY(root);
1965
1966 QList<Qt3DRender::QRenderSettings *> renderSettings = root->findChildren<Qt3DRender::QRenderSettings *>();
1967 QCOMPARE(renderSettings.size(), 1);
1968 Qt3DRender::QPickingSettings *settings = renderSettings.first()->pickingSettings();
1969
1970 settings->setPickMethod(Qt3DRender::QPickingSettings::TrianglePicking);
1971
1972 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
1973 TestArbiter arbiter;
1974
1975 QList<Qt3DRender::QCamera *> cameras = root->findChildren<Qt3DRender::QCamera *>();
1976 QCOMPARE(cameras.size(), 1);
1977 Qt3DRender::QCamera *camera = cameras.first();
1978
1979 QFETCH(QVector3D, cameraUpVector);
1980 camera->setUpVector(cameraUpVector);
1981
1982 QFETCH(QVector3D, cameraOrigin);
1983 camera->setPosition(cameraOrigin);
1984
1985 // Runs Required jobs
1986 runRequiredJobs(test: test.data());
1987
1988 // THEN
1989 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
1990 QCOMPARE(pickers.size(), 1);
1991
1992 Qt3DRender::QObjectPicker *picker = pickers.front();
1993
1994 Qt3DRender::Render::ObjectPicker *backendPicker = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker->id());
1995 QVERIFY(backendPicker);
1996 Qt3DCore::QBackendNodePrivate::get(n: backendPicker)->setArbiter(&arbiter);
1997
1998 QSignalSpy mouseEntered(picker, &Qt3DRender::QObjectPicker::entered);
1999 QSignalSpy mouseExited(picker, &Qt3DRender::QObjectPicker::exited);
2000 QSignalSpy mouseButtonPressedSpy(picker, &Qt3DRender::QObjectPicker::pressed);
2001 QSignalSpy mouseMovedSpy(picker, &Qt3DRender::QObjectPicker::moved);
2002 QSignalSpy mouseButtonReleasedSpy(picker, &Qt3DRender::QObjectPicker::released);
2003 QSignalSpy mouseClickedSpy(picker, &Qt3DRender::QObjectPicker::clicked);
2004
2005 QVERIFY(mouseButtonPressedSpy.isValid());
2006 QVERIFY(mouseMovedSpy.isValid());
2007 QVERIFY(mouseButtonReleasedSpy.isValid());
2008 QVERIFY(mouseClickedSpy.isValid());
2009 QVERIFY(mouseEntered.isValid());
2010 QVERIFY(mouseExited.isValid());
2011
2012 // WHEN -> Pressed on object
2013 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
2014 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
2015
2016 QList<QPair<QObject *, QMouseEvent>> events;
2017 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(303., 303.),
2018 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
2019 pickBVJob.setMouseEvents(events);
2020 bool earlyReturn = !pickBVJob.runHelper();
2021 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
2022
2023 // THEN -> Pressed
2024 QVERIFY(!earlyReturn);
2025 QVERIFY(backendPicker->isPressed());
2026 QVERIFY(picker->isPressed());
2027 QCOMPARE(mouseButtonPressedSpy.count(), 1);
2028 QCOMPARE(mouseMovedSpy.count(), 0);
2029 QCOMPARE(mouseButtonReleasedSpy.count(), 0);
2030 QCOMPARE(mouseClickedSpy.count(), 0);
2031 QCOMPARE(mouseEntered.count(), 0);
2032 QCOMPARE(mouseExited.count(), 0);
2033 }
2034
2035 void checkPriorityPicking()
2036 {
2037 // GIVEN
2038 QmlSceneReader sceneReader(QUrl("qrc:/testscene_priorityoverlapping.qml"));
2039 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
2040 QVERIFY(root);
2041
2042 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
2043 TestArbiter arbiter1;
2044 TestArbiter arbiter2;
2045
2046 // Runs Required jobs
2047 runRequiredJobs(test: test.data());
2048
2049 // THEN
2050 QList<Qt3DRender::QObjectPicker *> pickers = root->findChildren<Qt3DRender::QObjectPicker *>();
2051 QCOMPARE(pickers.size(), 2);
2052
2053 Qt3DRender::QObjectPicker *picker1 = nullptr;
2054 Qt3DRender::QObjectPicker *picker2 = nullptr;
2055 if (pickers.first()->objectName() == QLatin1String("Picker1")) {
2056 picker1 = pickers.first();
2057 picker2 = pickers.last();
2058 } else {
2059 picker1 = pickers.last();
2060 picker2 = pickers.first();
2061 }
2062
2063 Qt3DRender::Render::ObjectPicker *backendPicker1 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker1->id());
2064 QVERIFY(backendPicker1);
2065 Qt3DCore::QBackendNodePrivate::get(n: backendPicker1)->setArbiter(&arbiter1);
2066
2067 Qt3DRender::Render::ObjectPicker *backendPicker2 = test->nodeManagers()->objectPickerManager()->lookupResource(id: picker2->id());
2068 QVERIFY(backendPicker2);
2069 Qt3DCore::QBackendNodePrivate::get(n: backendPicker2)->setArbiter(&arbiter2);
2070
2071 QSignalSpy mouseEntered1(picker1, &Qt3DRender::QObjectPicker::entered);
2072 QSignalSpy mouseExited1(picker1, &Qt3DRender::QObjectPicker::exited);
2073 QSignalSpy mouseButtonPressedSpy1(picker1, &Qt3DRender::QObjectPicker::pressed);
2074 QSignalSpy mouseMovedSpy1(picker1, &Qt3DRender::QObjectPicker::moved);
2075 QSignalSpy mouseButtonReleasedSpy1(picker1, &Qt3DRender::QObjectPicker::released);
2076 QSignalSpy mouseClickedSpy1(picker1, &Qt3DRender::QObjectPicker::clicked);
2077
2078 QVERIFY(mouseButtonPressedSpy1.isValid());
2079 QVERIFY(mouseMovedSpy1.isValid());
2080 QVERIFY(mouseButtonReleasedSpy1.isValid());
2081 QVERIFY(mouseClickedSpy1.isValid());
2082 QVERIFY(mouseEntered1.isValid());
2083 QVERIFY(mouseExited1.isValid());
2084
2085 QSignalSpy mouseEntered2(picker2, &Qt3DRender::QObjectPicker::entered);
2086 QSignalSpy mouseExited2(picker2, &Qt3DRender::QObjectPicker::exited);
2087 QSignalSpy mouseButtonPressedSpy2(picker2, &Qt3DRender::QObjectPicker::pressed);
2088 QSignalSpy mouseMovedSpy2(picker2, &Qt3DRender::QObjectPicker::moved);
2089 QSignalSpy mouseButtonReleasedSpy2(picker2, &Qt3DRender::QObjectPicker::released);
2090 QSignalSpy mouseClickedSpy2(picker2, &Qt3DRender::QObjectPicker::clicked);
2091
2092 QVERIFY(mouseButtonPressedSpy2.isValid());
2093 QVERIFY(mouseMovedSpy2.isValid());
2094 QVERIFY(mouseButtonReleasedSpy2.isValid());
2095 QVERIFY(mouseClickedSpy2.isValid());
2096 QVERIFY(mouseEntered2.isValid());
2097 QVERIFY(mouseExited2.isValid());
2098
2099 // WHEN both have priority == 0, select closest
2100 {
2101 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
2102 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
2103
2104 // WHEN -> Pressed on object
2105 QList<QPair<QObject *, QMouseEvent>> events;
2106 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(300., 300.),
2107 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
2108 pickBVJob.setMouseEvents(events);
2109 bool earlyReturn = !pickBVJob.runHelper();
2110 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
2111
2112 // THEN -> Select picker with highest priority
2113 QVERIFY(!earlyReturn);
2114 QVERIFY(backendPicker1->isPressed());
2115 QVERIFY(picker1->isPressed());
2116 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
2117 QCOMPARE(mouseMovedSpy1.count(), 0);
2118 QCOMPARE(mouseButtonReleasedSpy1.count(), 0);
2119 QCOMPARE(mouseClickedSpy1.count(), 0);
2120 QCOMPARE(mouseEntered1.count(), 0);
2121 QCOMPARE(mouseExited1.count(), 0);
2122
2123 QVERIFY(!backendPicker2->isPressed());
2124 QVERIFY(!picker2->isPressed());
2125 QCOMPARE(mouseButtonPressedSpy2.count(), 0);
2126 QCOMPARE(mouseMovedSpy2.count(), 0);
2127 QCOMPARE(mouseButtonReleasedSpy2.count(), 0);
2128 QCOMPARE(mouseClickedSpy2.count(), 0);
2129 QCOMPARE(mouseEntered2.count(), 0);
2130 QCOMPARE(mouseExited2.count(), 0);
2131
2132 events.clear();
2133 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(300., 300.),
2134 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
2135 pickBVJob.setMouseEvents(events);
2136 pickBVJob.runHelper();
2137 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
2138
2139 QVERIFY(!backendPicker1->isPressed());
2140 QVERIFY(!picker1->isPressed());
2141 QCOMPARE(mouseButtonPressedSpy1.count(), 1);
2142 QCOMPARE(mouseMovedSpy1.count(), 0);
2143 QCOMPARE(mouseButtonReleasedSpy1.count(), 1);
2144 QCOMPARE(mouseClickedSpy1.count(), 1);
2145 QCOMPARE(mouseEntered1.count(), 0);
2146 QCOMPARE(mouseExited1.count(), 0);
2147
2148 QVERIFY(!backendPicker2->isPressed());
2149 QVERIFY(!picker2->isPressed());
2150 QCOMPARE(mouseButtonPressedSpy2.count(), 0);
2151 QCOMPARE(mouseMovedSpy2.count(), 0);
2152 QCOMPARE(mouseButtonReleasedSpy2.count(), 0);
2153 QCOMPARE(mouseClickedSpy2.count(), 0);
2154 QCOMPARE(mouseEntered2.count(), 0);
2155 QCOMPARE(mouseExited2.count(), 0);
2156 }
2157
2158 mouseButtonPressedSpy1.clear();
2159 mouseButtonReleasedSpy1.clear();
2160 mouseClickedSpy1.clear();
2161
2162 // WHEN furthest one has higher priority, select furthest one
2163 {
2164 backendPicker2->setPriority(1000);
2165 QCOMPARE(backendPicker2->priority(), 1000);
2166
2167 Qt3DRender::Render::PickBoundingVolumeJob pickBVJob;
2168 initializePickBoundingVolumeJob(job: &pickBVJob, test: test.data());
2169
2170 // WHEN -> Pressed on object
2171 QList<QPair<QObject *, QMouseEvent>> events;
2172 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonPress, QPointF(300., 300.),
2173 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
2174 pickBVJob.setMouseEvents(events);
2175 bool earlyReturn = !pickBVJob.runHelper();
2176 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
2177
2178 // THEN -> Select picker with highest priority
2179 QVERIFY(!earlyReturn);
2180 QVERIFY(!backendPicker1->isPressed());
2181 QVERIFY(!picker1->isPressed());
2182 QCOMPARE(mouseButtonPressedSpy1.count(), 0);
2183 QCOMPARE(mouseMovedSpy1.count(), 0);
2184 QCOMPARE(mouseButtonReleasedSpy1.count(), 0);
2185 QCOMPARE(mouseClickedSpy1.count(), 0);
2186 QCOMPARE(mouseEntered1.count(), 0);
2187 QCOMPARE(mouseExited1.count(), 0);
2188
2189 QVERIFY(backendPicker2->isPressed());
2190 QVERIFY(picker2->isPressed());
2191 QCOMPARE(mouseButtonPressedSpy2.count(), 1);
2192 QCOMPARE(mouseMovedSpy2.count(), 0);
2193 QCOMPARE(mouseButtonReleasedSpy2.count(), 0);
2194 QCOMPARE(mouseClickedSpy2.count(), 0);
2195 QCOMPARE(mouseEntered2.count(), 0);
2196 QCOMPARE(mouseExited2.count(), 0);
2197
2198 events.clear();
2199 events.push_back(t: {nullptr, QMouseEvent(QMouseEvent::MouseButtonRelease, QPointF(300., 300.),
2200 Qt::LeftButton, Qt::LeftButton, Qt::NoModifier)});
2201 pickBVJob.setMouseEvents(events);
2202 pickBVJob.runHelper();
2203 Qt3DCore::QAspectJobPrivate::get(job: &pickBVJob)->postFrame(aspectManager: test->aspectManager());
2204
2205 QVERIFY(!backendPicker1->isPressed());
2206 QVERIFY(!picker1->isPressed());
2207 QCOMPARE(mouseButtonPressedSpy1.count(), 0);
2208 QCOMPARE(mouseMovedSpy1.count(), 0);
2209 QCOMPARE(mouseButtonReleasedSpy1.count(), 0);
2210 QCOMPARE(mouseClickedSpy1.count(), 0);
2211 QCOMPARE(mouseEntered1.count(), 0);
2212 QCOMPARE(mouseExited1.count(), 0);
2213
2214 QVERIFY(!backendPicker2->isPressed());
2215 QVERIFY(!picker2->isPressed());
2216 QCOMPARE(mouseButtonPressedSpy2.count(), 1);
2217 QCOMPARE(mouseMovedSpy2.count(), 0);
2218 QCOMPARE(mouseButtonReleasedSpy2.count(), 1);
2219 QCOMPARE(mouseClickedSpy2.count(), 1);
2220 QCOMPARE(mouseEntered2.count(), 0);
2221 QCOMPARE(mouseExited2.count(), 0);
2222 }
2223 }
2224
2225 void checkNoPickingFGPicking()
2226 {
2227 // GIVEN
2228 QmlSceneReader sceneReader(QUrl("qrc:/testscene_nopicking.qml"));
2229 QScopedPointer<Qt3DCore::QNode> root(qobject_cast<Qt3DCore::QNode *>(object: sceneReader.root()));
2230 QVERIFY(root);
2231 QScopedPointer<Qt3DRender::TestAspect> test(new Qt3DRender::TestAspect(root.data()));
2232
2233 // THEN
2234 QVERIFY(test->frameGraphRoot() != nullptr);
2235 Qt3DRender::QNoPicking *noPicking = root->findChild<Qt3DRender::QNoPicking *>();
2236 QVERIFY(noPicking != nullptr);
2237 Qt3DRender::QCamera *camera = root->findChild<Qt3DRender::QCamera *>();
2238 QVERIFY(camera != nullptr);
2239 QQuickWindow *window = root->findChild<QQuickWindow *>();
2240 QVERIFY(camera != nullptr);
2241 QCOMPARE(window->size(), QSize(600, 600));
2242
2243 // WHEN
2244 Qt3DRender::Render::PickingUtils::ViewportCameraAreaGatherer gatherer;
2245 QVector<Qt3DRender::Render::PickingUtils::ViewportCameraAreaDetails> results = gatherer.gather(root: test->frameGraphRoot());
2246
2247 // THEN
2248 QCOMPARE(results.size(), 0);
2249
2250 // WHEN
2251 Qt3DRender::Render::FrameGraphNode *backendFGNode = test->nodeManagers()->frameGraphManager()->lookupNode(id: noPicking->id());
2252 QVERIFY(backendFGNode);
2253 QCOMPARE(backendFGNode->nodeType(), Qt3DRender::Render::FrameGraphNode::NoPicking);
2254 Qt3DRender::Render::NoPicking * backendNoPicking = static_cast<Qt3DRender::Render::NoPicking *>(backendFGNode);
2255 backendNoPicking->setEnabled(false);
2256
2257 // THEN
2258 QVERIFY(!backendNoPicking->isEnabled());
2259
2260 // WHEN
2261 results = gatherer.gather(root: test->frameGraphRoot());
2262
2263 // THEN
2264 QCOMPARE(results.size(), 1);
2265 auto vca = results.first();
2266 QCOMPARE(vca.area, QSize(600, 600));
2267 QCOMPARE(vca.cameraId, camera->id());
2268 QCOMPARE(vca.viewport, QRectF(0., 0., 1., 1.));
2269 }
2270};
2271
2272QTEST_MAIN(tst_PickBoundingVolumeJob)
2273
2274#include "tst_pickboundingvolumejob.moc"
2275

source code of qt3d/tests/auto/render/pickboundingvolumejob/tst_pickboundingvolumejob.cpp