diff options
author | Mike Krus <mike.krus@kdab.com> | 2020-06-29 16:20:32 +0100 |
---|---|---|
committer | Mike Krus <mike.krus@kdab.com> | 2020-07-08 08:44:56 +0100 |
commit | 5ac891247f88a600ef6622bb8a1b3f25698ecd1c (patch) | |
tree | aefb8bb7cac67e2877b88c06b13942d480b48351 | |
parent | 0a30bd106729fd67902c58e7366d2b6bf3e2ebf9 (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>
-rw-r--r-- | src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp | 3 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumejob.cpp | 209 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumejob_p.h | 3 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumeutils.cpp | 28 | ||||
-rw-r--r-- | src/render/jobs/pickboundingvolumeutils_p.h | 14 |
5 files changed, 139 insertions, 118 deletions
diff --git a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp index 2fd0c0359..59bb9b817 100644 --- a/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp +++ b/src/plugins/renderers/opengl/renderer/renderviewbuilder.cpp @@ -121,7 +121,8 @@ public: : m_renderViewJob(renderViewJob) , m_renderViewCommandUpdaterJobs(renderViewCommandUpdateJobs) , m_renderer(renderer) - {} + { + } void operator()() { 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: |