summaryrefslogtreecommitdiffstats
path: root/src/render/jobs
diff options
context:
space:
mode:
authorMike Krus <mike.krus@kdab.com>2020-06-29 16:20:32 +0100
committerMike Krus <mike.krus@kdab.com>2020-07-08 08:44:56 +0100
commit5ac891247f88a600ef6622bb8a1b3f25698ecd1c (patch)
treeaefb8bb7cac67e2877b88c06b13942d480b48351 /src/render/jobs
parent0a30bd106729fd67902c58e7366d2b6bf3e2ebf9 (diff)
Isolate picking event processing
Can then be reused for synchronous event processing and for letting individual object pickers override picking settings. Change-Id: I7d71522dabc20f35956c23ae169d9b06fb86bdb3 Reviewed-by: Paul Lemire <paul.lemire@kdab.com>
Diffstat (limited to 'src/render/jobs')
-rw-r--r--src/render/jobs/pickboundingvolumejob.cpp209
-rw-r--r--src/render/jobs/pickboundingvolumejob_p.h3
-rw-r--r--src/render/jobs/pickboundingvolumeutils.cpp28
-rw-r--r--src/render/jobs/pickboundingvolumeutils_p.h14
4 files changed, 137 insertions, 117 deletions
diff --git a/src/render/jobs/pickboundingvolumejob.cpp b/src/render/jobs/pickboundingvolumejob.cpp
index 7dab67e95..2798992a7 100644
--- a/src/render/jobs/pickboundingvolumejob.cpp
+++ b/src/render/jobs/pickboundingvolumejob.cpp
@@ -42,6 +42,7 @@
#include "qpicklineevent.h"
#include "qpickpointevent.h"
#include <Qt3DCore/private/qaspectmanager_p.h>
+#include <Qt3DCore/private/vector_helper_p.h>
#include <Qt3DRender/qobjectpicker.h>
#include <Qt3DRender/qviewport.h>
#include <Qt3DRender/qgeometryrenderer.h>
@@ -155,9 +156,9 @@ void PickBoundingVolumeJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
namespace {
-void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers)
+void setEventButtonAndModifiers(const QMouseEvent *event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers)
{
- switch (event.button()) {
+ switch (event->button()) {
case Qt::LeftButton:
eventButton = QPickEvent::LeftButton;
break;
@@ -174,23 +175,23 @@ void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &e
break;
}
- if (event.buttons() & Qt::LeftButton)
+ if (event->buttons() & Qt::LeftButton)
eventButtons |= QPickEvent::LeftButton;
- if (event.buttons() & Qt::RightButton)
+ if (event->buttons() & Qt::RightButton)
eventButtons |= QPickEvent::RightButton;
- if (event.buttons() & Qt::MiddleButton)
+ if (event->buttons() & Qt::MiddleButton)
eventButtons |= QPickEvent::MiddleButton;
- if (event.buttons() & Qt::BackButton)
+ if (event->buttons() & Qt::BackButton)
eventButtons |= QPickEvent::BackButton;
- if (event.modifiers() & Qt::ShiftModifier)
+ if (event->modifiers() & Qt::ShiftModifier)
eventModifiers |= QPickEvent::ShiftModifier;
- if (event.modifiers() & Qt::ControlModifier)
+ if (event->modifiers() & Qt::ControlModifier)
eventModifiers |= QPickEvent::ControlModifier;
- if (event.modifiers() & Qt::AltModifier)
+ if (event->modifiers() & Qt::AltModifier)
eventModifiers |= QPickEvent::AltModifier;
- if (event.modifiers() & Qt::MetaModifier)
+ if (event->modifiers() & Qt::MetaModifier)
eventModifiers |= QPickEvent::MetaModifier;
- if (event.modifiers() & Qt::KeypadModifier)
+ if (event->modifiers() & Qt::KeypadModifier)
eventModifiers |= QPickEvent::KeypadModifier;
}
@@ -279,106 +280,17 @@ bool PickBoundingVolumeJob::runHelper()
return false;
}
- PickingUtils::ViewportCameraAreaGatherer vcaGatherer;
- // TO DO: We could cache this and only gather when we know the FrameGraph tree has changed
- const std::vector<PickingUtils::ViewportCameraAreaDetails> &vcaDetails = vcaGatherer.gather(m_frameGraphRoot);
-
- // If we have no viewport / camera or area, return early
- if (vcaDetails.empty())
+ const PickingUtils::PickConfiguration pickConfiguration(m_frameGraphRoot, m_renderSettings);
+ if (pickConfiguration.vcaDetails.empty())
return false;
// TO DO:
// If we have move or hover move events that someone cares about, we try to avoid expensive computations
// by compressing them into a single one
- const bool trianglePickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::TrianglePicking);
- const bool edgePickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::LinePicking);
- const bool pointPickingRequested = (m_renderSettings->pickMethod() & QPickingSettings::PointPicking);
- const bool primitivePickingRequested = pointPickingRequested | edgePickingRequested | trianglePickingRequested;
- const bool frontFaceRequested =
- m_renderSettings->faceOrientationPickingMode() != QPickingSettings::BackFace;
- const bool backFaceRequested =
- m_renderSettings->faceOrientationPickingMode() != QPickingSettings::FrontFace;
- const float pickWorldSpaceTolerance = m_renderSettings->pickWorldSpaceTolerance();
-
// For each mouse event
- for (const auto &event : mouseEvents) {
- m_hoveredPickersToClear = m_hoveredPickers;
-
- QPickEvent::Buttons eventButton = QPickEvent::NoButton;
- int eventButtons = 0;
- int eventModifiers = QPickEvent::NoModifier;
-
- setEventButtonAndModifiers(event.second, eventButton, eventButtons, eventModifiers);
-
- // For each Viewport / Camera and Area entry
- for (const PickingUtils::ViewportCameraAreaDetails &vca : vcaDetails) {
- PickingUtils::HitList sphereHits;
- QRay3D ray = rayForViewportAndCamera(vca, event.first, event.second.pos());
- if (!ray.isValid()) {
- // An invalid rays is when we've lost our surface or the mouse
- // has moved out of the viewport In case of a button released
- // outside of the viewport, we still want to notify the
- // lastCurrent entity about this.
- dispatchPickEvents(event.second, PickingUtils::HitList(), eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode(),
- vca.viewportNodeId);
- continue;
- }
-
- PickingUtils::HierarchicalEntityPicker entityPicker(ray);
- if (entityPicker.collectHits(m_manager, m_node)) {
- if (trianglePickingRequested) {
- PickingUtils::TriangleCollisionGathererFunctor gathererFunctor;
- gathererFunctor.m_frontFaceRequested = frontFaceRequested;
- gathererFunctor.m_backFaceRequested = backFaceRequested;
- gathererFunctor.m_manager = m_manager;
- gathererFunctor.m_ray = ray;
- gathererFunctor.m_entityToPriorityTable = entityPicker.entityToPriorityTable();
- const PickingUtils::HitList &hits = gathererFunctor.computeHits(entityPicker.entities(), m_renderSettings->pickResultMode());
- sphereHits.insert(sphereHits.end(),
- std::make_move_iterator(hits.begin()),
- std::make_move_iterator(hits.end()));
- }
- if (edgePickingRequested) {
- PickingUtils::LineCollisionGathererFunctor gathererFunctor;
- gathererFunctor.m_manager = m_manager;
- gathererFunctor.m_ray = ray;
- gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
- gathererFunctor.m_entityToPriorityTable = entityPicker.entityToPriorityTable();
- const PickingUtils::HitList &hits = gathererFunctor.computeHits(entityPicker.entities(), m_renderSettings->pickResultMode());
- sphereHits.insert(sphereHits.end(),
- std::make_move_iterator(hits.begin()),
- std::make_move_iterator(hits.end()));
- PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
- }
- if (pointPickingRequested) {
- PickingUtils::PointCollisionGathererFunctor gathererFunctor;
- gathererFunctor.m_manager = m_manager;
- gathererFunctor.m_ray = ray;
- gathererFunctor.m_pickWorldSpaceTolerance = pickWorldSpaceTolerance;
- gathererFunctor.m_entityToPriorityTable = entityPicker.entityToPriorityTable();
- const PickingUtils::HitList &hits = gathererFunctor.computeHits(entityPicker.entities(), m_renderSettings->pickResultMode());
- sphereHits.insert(sphereHits.end(),
- std::make_move_iterator(hits.begin()),
- std::make_move_iterator(hits.end()));
- PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
- }
- if (!primitivePickingRequested) {
- const PickingUtils::HitList &hits = entityPicker.hits();
- sphereHits.insert(sphereHits.end(),
- std::make_move_iterator(hits.begin()),
- std::make_move_iterator(hits.end()));
- PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
- if (m_renderSettings->pickResultMode() != QPickingSettings::AllPicks)
- sphereHits = { sphereHits.front() };
- }
- }
-
- // Dispatch events based on hit results
- dispatchPickEvents(event.second, sphereHits, eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode(),
- vca.viewportNodeId);
- }
- }
+ for (const auto &event : mouseEvents)
+ processPickEvent(pickConfiguration, event.first, &event.second);
// Clear Hovered elements that needs to be cleared
// Send exit event to object pickers on which we
@@ -388,7 +300,74 @@ bool PickBoundingVolumeJob::runHelper()
return true;
}
-void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
+void PickBoundingVolumeJob::processPickEvent(const PickingUtils::PickConfiguration &pickConfiguration, QObject *object, const QMouseEvent *event)
+{
+ m_hoveredPickersToClear = m_hoveredPickers;
+
+ QPickEvent::Buttons eventButton = QPickEvent::NoButton;
+ int eventButtons = 0;
+ int eventModifiers = QPickEvent::NoModifier;
+
+ setEventButtonAndModifiers(event, eventButton, eventButtons, eventModifiers);
+
+ // For each Viewport / Camera and Area entry
+ for (const PickingUtils::ViewportCameraAreaDetails &vca : pickConfiguration.vcaDetails) {
+ PickingUtils::HitList sphereHits;
+ QRay3D ray = rayForViewportAndCamera(vca, object, event->pos());
+ if (!ray.isValid()) {
+ // An invalid rays is when we've lost our surface or the mouse
+ // has moved out of the viewport In case of a button released
+ // outside of the viewport, we still want to notify the
+ // lastCurrent entity about this.
+ dispatchPickEvents(event, PickingUtils::HitList(), eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode(),
+ vca.viewportNodeId);
+ continue;
+ }
+
+ PickingUtils::HierarchicalEntityPicker entityPicker(ray);
+ if (entityPicker.collectHits(m_manager, m_node)) {
+ if (pickConfiguration.trianglePickingRequested) {
+ PickingUtils::TriangleCollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_frontFaceRequested = pickConfiguration.frontFaceRequested;
+ gathererFunctor.m_backFaceRequested = pickConfiguration.backFaceRequested;
+ gathererFunctor.m_manager = m_manager;
+ gathererFunctor.m_ray = ray;
+ gathererFunctor.m_entityToPriorityTable = entityPicker.entityToPriorityTable();
+ Qt3DCore::moveAtEnd(sphereHits, gathererFunctor.computeHits(entityPicker.entities(), m_renderSettings->pickResultMode()));
+ }
+ if (pickConfiguration.edgePickingRequested) {
+ PickingUtils::LineCollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_manager = m_manager;
+ gathererFunctor.m_ray = ray;
+ gathererFunctor.m_pickWorldSpaceTolerance = pickConfiguration.pickWorldSpaceTolerance;
+ gathererFunctor.m_entityToPriorityTable = entityPicker.entityToPriorityTable();
+ Qt3DCore::moveAtEnd(sphereHits, gathererFunctor.computeHits(entityPicker.entities(), m_renderSettings->pickResultMode()));
+ PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
+ }
+ if (pickConfiguration.pointPickingRequested) {
+ PickingUtils::PointCollisionGathererFunctor gathererFunctor;
+ gathererFunctor.m_manager = m_manager;
+ gathererFunctor.m_ray = ray;
+ gathererFunctor.m_pickWorldSpaceTolerance = pickConfiguration.pickWorldSpaceTolerance;
+ gathererFunctor.m_entityToPriorityTable = entityPicker.entityToPriorityTable();
+ Qt3DCore::moveAtEnd(sphereHits, gathererFunctor.computeHits(entityPicker.entities(), m_renderSettings->pickResultMode()));
+ PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
+ }
+ if (!pickConfiguration.primitivePickingRequested) {
+ Qt3DCore::moveAtEnd(sphereHits, entityPicker.hits());
+ PickingUtils::AbstractCollisionGathererFunctor::sortHits(sphereHits);
+ if (m_renderSettings->pickResultMode() != QPickingSettings::AllPicks)
+ sphereHits = { sphereHits.front() };
+ }
+ }
+
+ // Dispatch events based on hit results
+ dispatchPickEvents(event, sphereHits, eventButton, eventButtons, eventModifiers, m_renderSettings->pickResultMode(),
+ vca.viewportNodeId);
+ }
+}
+
+void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent *event,
const PickingUtils::HitList &sphereHits,
QPickEvent::Buttons eventButton,
int eventButtons,
@@ -436,7 +415,7 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
QPickEventPtr pickEvent;
switch (hit.m_type) {
case QCollisionQueryResult::Hit::Triangle:
- pickEvent.reset(new QPickTriangleEvent(event.position(),
+ pickEvent.reset(new QPickTriangleEvent(event->position(),
convertToQVector3D(hit.m_intersection),
convertToQVector3D(localIntersection),
hit.m_distance,
@@ -449,7 +428,7 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
convertToQVector3D(hit.m_uvw)));
break;
case QCollisionQueryResult::Hit::Edge:
- pickEvent.reset(new QPickLineEvent(event.position(),
+ pickEvent.reset(new QPickLineEvent(event->position(),
convertToQVector3D(hit.m_intersection),
convertToQVector3D(localIntersection),
hit.m_distance,
@@ -458,7 +437,7 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
eventButton, eventButtons, eventModifiers));
break;
case QCollisionQueryResult::Hit::Point:
- pickEvent.reset(new QPickPointEvent(event.position(),
+ pickEvent.reset(new QPickPointEvent(event->position(),
convertToQVector3D(hit.m_intersection),
convertToQVector3D(localIntersection),
hit.m_distance,
@@ -466,7 +445,7 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
eventButton, eventButtons, eventModifiers));
break;
case QCollisionQueryResult::Hit::Entity:
- pickEvent.reset(new QPickEvent(event.position(),
+ pickEvent.reset(new QPickEvent(event->position(),
convertToQVector3D(hit.m_intersection),
convertToQVector3D(localIntersection),
hit.m_distance,
@@ -476,12 +455,12 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
Q_UNREACHABLE();
}
Qt3DRender::QPickEventPrivate::get(pickEvent.data())->m_entity = hit.m_entityId;
- switch (event.type()) {
+ switch (event->type()) {
case QEvent::MouseButtonPress: {
// Store pressed object handle
m_currentPicker = objectPickerHandle;
// Send pressed event to m_currentPicker
- d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId});
+ d->dispatches.push_back({objectPicker->peerId(), event->type(), pickEvent, viewportNodeId});
objectPicker->setPressed(true);
break;
}
@@ -489,7 +468,7 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
case QEvent::MouseButtonRelease: {
// Only send the release event if it was pressed
if (objectPicker->isPressed()) {
- d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId});
+ d->dispatches.push_back({objectPicker->peerId(), event->type(), pickEvent, viewportNodeId});
objectPicker->setPressed(false);
}
if (lastCurrentPicker != nullptr && m_currentPicker == objectPickerHandle) {
@@ -510,7 +489,7 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
#endif
case QEvent::MouseMove: {
if ((objectPicker->isPressed() || objectPicker->isHoverEnabled()) && objectPicker->isDragEnabled())
- d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId});
+ d->dispatches.push_back({objectPicker->peerId(), event->type(), pickEvent, viewportNodeId});
Q_FALLTHROUGH(); // fallthrough
}
case QEvent::HoverMove: {
@@ -538,14 +517,14 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
// Otherwise no hits
} else {
- switch (event.type()) {
+ switch (event->type()) {
case QEvent::MouseButtonRelease: {
// Send release event to m_currentPicker
if (lastCurrentPicker != nullptr) {
m_currentPicker = HObjectPicker();
QPickEventPtr pickEvent(new QPickEvent);
lastCurrentPicker->setPressed(false);
- d->dispatches.push_back({lastCurrentPicker->peerId(), event.type(), pickEvent, viewportNodeId});
+ d->dispatches.push_back({lastCurrentPicker->peerId(), event->type(), pickEvent, viewportNodeId});
}
break;
}
diff --git a/src/render/jobs/pickboundingvolumejob_p.h b/src/render/jobs/pickboundingvolumejob_p.h
index c56832ef4..11ea88e2c 100644
--- a/src/render/jobs/pickboundingvolumejob_p.h
+++ b/src/render/jobs/pickboundingvolumejob_p.h
@@ -95,7 +95,8 @@ public:
bool runHelper() override;
protected:
- void dispatchPickEvents(const QMouseEvent &event,
+ void processPickEvent(const PickingUtils::PickConfiguration &pickConfiguration, QObject *object, const QMouseEvent *event);
+ void dispatchPickEvents(const QMouseEvent *event,
const PickingUtils::HitList &sphereHits,
QPickEvent::Buttons eventButton,
int eventButtons,
diff --git a/src/render/jobs/pickboundingvolumeutils.cpp b/src/render/jobs/pickboundingvolumeutils.cpp
index e236c10f4..072d10b7d 100644
--- a/src/render/jobs/pickboundingvolumeutils.cpp
+++ b/src/render/jobs/pickboundingvolumeutils.cpp
@@ -52,6 +52,7 @@
#include <Qt3DRender/private/segmentsvisitor_p.h>
#include <Qt3DRender/private/pointsvisitor_p.h>
#include <Qt3DRender/private/layer_p.h>
+#include <Qt3DRender/private/rendersettings_p.h>
#include <vector>
#include <algorithm>
@@ -66,6 +67,31 @@ namespace Render {
namespace PickingUtils {
+
+PickConfiguration::PickConfiguration(FrameGraphNode *frameGraphRoot, RenderSettings *renderSettings)
+{
+ ViewportCameraAreaGatherer vcaGatherer;
+ // TO DO: We could cache this and only gather when we know the FrameGraph tree has changed
+ vcaDetails = vcaGatherer.gather(frameGraphRoot);
+
+ // If we have no viewport / camera or area, return early
+ if (vcaDetails.empty())
+ return;
+
+ // TO DO:
+ // If we have move or hover move events that someone cares about, we try to avoid expensive computations
+ // by compressing them into a single one
+
+ trianglePickingRequested = (renderSettings->pickMethod() & QPickingSettings::TrianglePicking);
+ edgePickingRequested = (renderSettings->pickMethod() & QPickingSettings::LinePicking);
+ pointPickingRequested = (renderSettings->pickMethod() & QPickingSettings::PointPicking);
+ primitivePickingRequested = pointPickingRequested | edgePickingRequested | trianglePickingRequested;
+ frontFaceRequested = renderSettings->faceOrientationPickingMode() != QPickingSettings::BackFace;
+ backFaceRequested = renderSettings->faceOrientationPickingMode() != QPickingSettings::FrontFace;
+ pickWorldSpaceTolerance = renderSettings->pickWorldSpaceTolerance();
+}
+
+
void ViewportCameraAreaGatherer::visit(FrameGraphNode *node)
{
const auto children = node->children();
@@ -78,7 +104,7 @@ void ViewportCameraAreaGatherer::visit(FrameGraphNode *node)
ViewportCameraAreaDetails ViewportCameraAreaGatherer::gatherUpViewportCameraAreas(Render::FrameGraphNode *node) const
{
ViewportCameraAreaDetails vca;
- vca.viewport = QRectF(0.0f, 0.0f, 1.0f, 1.0f);
+ vca.viewport = QRectF(0., 0., 1., 1.);
while (node) {
if (node->isEnabled()) {
diff --git a/src/render/jobs/pickboundingvolumeutils_p.h b/src/render/jobs/pickboundingvolumeutils_p.h
index 3078d1a18..bac025dca 100644
--- a/src/render/jobs/pickboundingvolumeutils_p.h
+++ b/src/render/jobs/pickboundingvolumeutils_p.h
@@ -72,6 +72,7 @@ namespace Render {
class Entity;
class Renderer;
class FrameGraphNode;
+class RenderSettings;
class NodeManagers;
namespace PickingUtils {
@@ -86,6 +87,19 @@ struct Q_AUTOTEST_EXPORT ViewportCameraAreaDetails
};
QT3D_DECLARE_TYPEINFO_3(Qt3DRender, Render, PickingUtils, ViewportCameraAreaDetails, Q_PRIMITIVE_TYPE)
+struct PickConfiguration {
+ std::vector<ViewportCameraAreaDetails> vcaDetails;
+ bool trianglePickingRequested = false;
+ bool edgePickingRequested = false;
+ bool pointPickingRequested = false;
+ bool primitivePickingRequested = false;
+ bool frontFaceRequested = false;
+ bool backFaceRequested = false;
+ float pickWorldSpaceTolerance = -1.f;
+
+ PickConfiguration(FrameGraphNode *frameGraphRoot, RenderSettings *renderSettings);
+};
+
class Q_AUTOTEST_EXPORT ViewportCameraAreaGatherer
{
public: