Commit fd85ebb1 authored by Mike Krus's avatar Mike Krus Committed by Paul Lemire
Browse files

Update PickBoundingVolumeJob to use direct sync



Change-Id: I7878294cd44872ccdc17515fbb44a6b2a99239e5
Reviewed-by: Mike Krus's avatarMike Krus <mike.krus@kdab.com>
parent da5a4af5
......@@ -41,7 +41,11 @@
#include "qpicktriangleevent.h"
#include "qpicklineevent.h"
#include "qpickpointevent.h"
#include <Qt3DCore/private/qaspectmanager_p.h>
#include <Qt3DRender/qobjectpicker.h>
#include <Qt3DRender/qviewport.h>
#include <Qt3DRender/qgeometryrenderer.h>
#include <Qt3DRender/private/qobjectpicker_p.h>
#include <Qt3DRender/private/renderer_p.h>
#include <Qt3DRender/private/nodemanagers_p.h>
#include <Qt3DRender/private/entity_p.h>
......@@ -65,6 +69,82 @@ using namespace Qt3DRender::RayCasting;
namespace Render {
class PickBoundingVolumeJobPrivate : public Qt3DCore::QAspectJobPrivate
{
public:
PickBoundingVolumeJobPrivate() = default;
~PickBoundingVolumeJobPrivate() override = default;
void postFrame(Qt3DCore::QAspectManager *manager) override;
enum CustomEventType {
MouseButtonClick = QEvent::User,
};
struct EventDetails {
Qt3DCore::QNodeId pickerId;
int sourceEventType;
QPickEventPtr resultingEvent;
Qt3DCore::QNodeId viewportNodeId;
};
QVector<EventDetails> dispatches;
};
void PickBoundingVolumeJobPrivate::postFrame(Qt3DCore::QAspectManager *manager)
{
using namespace Qt3DCore;
QNodeId previousId;
QObjectPicker *node = nullptr;
for (auto res: qAsConst(dispatches)) {
if (previousId != res.pickerId) {
node = qobject_cast<QObjectPicker *>(manager->lookupNode(res.pickerId));
previousId = res.pickerId;
}
if (!node)
continue;
QObjectPickerPrivate *dnode = static_cast<QObjectPickerPrivate *>(QObjectPickerPrivate::get(node));
// resolve front end details
QPickEvent *pickEvent = res.resultingEvent.data();
if (pickEvent) {
QPickEventPrivate *dpickEvent = QPickEventPrivate::get(pickEvent);
dpickEvent->m_viewport = static_cast<QViewport *>(manager->lookupNode(res.viewportNodeId));
dpickEvent->m_entityPtr = static_cast<QEntity *>(manager->lookupNode(dpickEvent->m_entity));
}
// dispatch event
switch (res.sourceEventType) {
case QEvent::MouseButtonPress:
dnode->pressedEvent(pickEvent);
break;
case QEvent::MouseButtonRelease:
dnode->releasedEvent(pickEvent);
break;
case MouseButtonClick:
dnode->clickedEvent(pickEvent);
break;
case QEvent::MouseMove:
dnode->movedEvent(pickEvent);
break;
case QEvent::Enter:
emit node->entered();
dnode->setContainsMouse(true);
break;
case QEvent::Leave:
dnode->setContainsMouse(false);
emit node->exited();
break;
default: Q_UNREACHABLE();
}
}
dispatches.clear();
}
namespace {
void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &eventButton, int &eventButtons, int &eventModifiers)
......@@ -109,10 +189,10 @@ void setEventButtonAndModifiers(const QMouseEvent &event, QPickEvent::Buttons &e
} // anonymous
PickBoundingVolumeJob::PickBoundingVolumeJob()
: AbstractPickingJob()
: AbstractPickingJob(*new PickBoundingVolumeJobPrivate)
, m_pickersDirty(true)
{
SET_JOB_RUN_STAT_TYPE(this, JobTypes::PickBoundingVolume, 0);
SET_JOB_RUN_STAT_TYPE(this, JobTypes::PickBoundingVolume, 0)
}
void PickBoundingVolumeJob::setRoot(Entity *root)
......@@ -300,6 +380,8 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
bool allHitsRequested,
Qt3DCore::QNodeId viewportNodeId)
{
Q_D(PickBoundingVolumeJob);
ObjectPicker *lastCurrentPicker = m_manager->objectPickerManager()->data(m_currentPicker);
// If we have hits
if (!sphereHits.isEmpty()) {
......@@ -383,37 +465,43 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
// Store pressed object handle
m_currentPicker = objectPickerHandle;
// Send pressed event to m_currentPicker
objectPicker->onPressed(pickEvent, viewportNodeId);
d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId});
objectPicker->setPressed(true);
break;
}
case QEvent::MouseButtonRelease: {
// Only send the release event if it was pressed
if (objectPicker->isPressed())
objectPicker->onReleased(pickEvent, viewportNodeId);
if (objectPicker->isPressed()) {
d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId});
objectPicker->setPressed(false);
}
if (lastCurrentPicker != nullptr && m_currentPicker == objectPickerHandle) {
objectPicker->onClicked(pickEvent, viewportNodeId);
d->dispatches.push_back({objectPicker->peerId(),
PickBoundingVolumeJobPrivate::MouseButtonClick,
pickEvent, viewportNodeId});
m_currentPicker = HObjectPicker();
}
break;
}
#if QT_CONFIG(gestures)
case QEvent::Gesture: {
objectPicker->onClicked(pickEvent, viewportNodeId);
d->dispatches.push_back({objectPicker->peerId(),
PickBoundingVolumeJobPrivate::MouseButtonClick,
pickEvent, viewportNodeId});
break;
}
#endif
case QEvent::MouseMove: {
if ((objectPicker->isPressed() || objectPicker->isHoverEnabled()) && objectPicker->isDragEnabled()) {
objectPicker->onMoved(pickEvent, viewportNodeId);
}
if ((objectPicker->isPressed() || objectPicker->isHoverEnabled()) && objectPicker->isDragEnabled())
d->dispatches.push_back({objectPicker->peerId(), event.type(), pickEvent, viewportNodeId});
Q_FALLTHROUGH(); // fallthrough
}
case QEvent::HoverMove: {
if (!m_hoveredPickers.contains(objectPickerHandle)) {
if (objectPicker->isHoverEnabled()) {
// Send entered event to objectPicker
objectPicker->onEntered();
d->dispatches.push_back({objectPicker->peerId(), QEvent::Enter, pickEvent, viewportNodeId});
// and save it in the hoveredPickers
m_hoveredPickers.push_back(objectPickerHandle);
}
......@@ -440,7 +528,8 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
if (lastCurrentPicker != nullptr) {
m_currentPicker = HObjectPicker();
QPickEventPtr pickEvent(new QPickEvent);
lastCurrentPicker->onReleased(pickEvent, viewportNodeId);
lastCurrentPicker->setPressed(false);
d->dispatches.push_back({lastCurrentPicker->peerId(), event.type(), pickEvent, viewportNodeId});
}
break;
}
......@@ -452,12 +541,15 @@ void PickBoundingVolumeJob::dispatchPickEvents(const QMouseEvent &event,
void PickBoundingVolumeJob::clearPreviouslyHoveredPickers()
{
Q_D(PickBoundingVolumeJob);
for (const HObjectPicker &pickHandle : qAsConst(m_hoveredPickersToClear)) {
ObjectPicker *pick = m_manager->objectPickerManager()->data(pickHandle);
if (pick)
pick->onExited();
d->dispatches.push_back({pick->peerId(), QEvent::Leave, {}, {}});
m_hoveredPickers.removeAll(pickHandle);
}
m_hoveredPickersToClear.clear();
}
......
......@@ -70,6 +70,7 @@ namespace Qt3DRender {
class QViewport;
namespace Render {
class PickBoundingVolumeJobPrivate;
namespace PickingUtils {
typedef QVector<RayCasting::QCollisionQueryResult::Hit> HitList;
......@@ -101,6 +102,8 @@ protected:
Qt3DCore::QNodeId viewportNodeId);
private:
Q_DECLARE_PRIVATE(PickBoundingVolumeJob)
void clearPreviouslyHoveredPickers();
QList<QPair<QObject*, QMouseEvent>> m_pendingMouseEvents;
......
......@@ -43,7 +43,6 @@
#include <Qt3DRender/private/qobjectpicker_p.h>
#include <Qt3DRender/qattribute.h>
#include <Qt3DRender/private/pickboundingvolumejob_p.h>
#include <Qt3DCore/qpropertyupdatedchange.h>
QT_BEGIN_NAMESPACE
......@@ -100,7 +99,6 @@ void ObjectPicker::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstT
markDirty(AbstractRenderer::AllDirty);
notifyJob();
}
}
void ObjectPicker::notifyJob()
......@@ -124,58 +122,9 @@ bool ObjectPicker::isDragEnabled() const
return m_dragEnabled;
}
void ObjectPicker::onClicked(QPickEventPtr event, Qt3DCore::QNodeId viewportNodeId)
{
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("clicked");
e->setValue(QVariant::fromValue(QObjectPickerEvent { event, viewportNodeId }));
notifyObservers(e);
}
void ObjectPicker::onMoved(QPickEventPtr event, Qt3DCore::QNodeId viewportNodeId)
{
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("moved");
e->setValue(QVariant::fromValue(QObjectPickerEvent { event, viewportNodeId }));
notifyObservers(e);
}
void ObjectPicker::onPressed(QPickEventPtr event, Qt3DCore::QNodeId viewportNodeId)
{
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("pressed");
e->setValue(QVariant::fromValue(QObjectPickerEvent { event, viewportNodeId }));
m_isPressed = true;
notifyObservers(e);
}
void ObjectPicker::onReleased(QPickEventPtr event, Qt3DCore::QNodeId viewportNodeId)
{
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("released");
e->setValue(QVariant::fromValue(QObjectPickerEvent { event, viewportNodeId }));
m_isPressed = false;
notifyObservers(e);
}
void ObjectPicker::onEntered()
{
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("entered");
notifyObservers(e);
}
void ObjectPicker::onExited()
void ObjectPicker::setPressed(bool pressed)
{
auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId());
e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll);
e->setPropertyName("exited");
notifyObservers(e);
m_isPressed = pressed;
}
void ObjectPicker::setPriority(int priority)
......
......@@ -74,12 +74,7 @@ public:
bool isHoverEnabled() const;
bool isDragEnabled() const;
void onClicked(QPickEventPtr event, Qt3DCore::QNodeId viewportNodeId);
void onMoved(QPickEventPtr event, Qt3DCore::QNodeId viewportNodeId);
void onPressed(QPickEventPtr event, Qt3DCore::QNodeId viewportNodeId);
void onReleased(QPickEventPtr event, Qt3DCore::QNodeId viewportNodeId);
void onEntered();
void onExited();
void setPressed(bool pressed);
// Needed for unit tests
void setPriority(int priority);
......
......@@ -352,33 +352,6 @@ int QObjectPicker::priority() const
return d->m_priority;
}
/*! \internal */
void QObjectPicker::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change)
{
Q_D(QObjectPicker);
Qt3DCore::QPropertyUpdatedChangePtr e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change);
if (e->type() == Qt3DCore::PropertyUpdated) {
// TO DO: Complete this part
// to emit the correct signals
const QByteArray propertyName = e->propertyName();
if (propertyName == QByteArrayLiteral("pressed")) {
d->pressedEvent(d->resolvePickEvent(e));
} else if (propertyName == QByteArrayLiteral("released")) {
d->releasedEvent(d->resolvePickEvent(e));
} else if (propertyName == QByteArrayLiteral("clicked")) {
d->clickedEvent(d->resolvePickEvent(e));
} else if (propertyName == QByteArrayLiteral("moved")) {
d->movedEvent(d->resolvePickEvent(e));
} else if (propertyName == QByteArrayLiteral("entered")) {
emit entered();
d->setContainsMouse(true);
} else if (propertyName == QByteArrayLiteral("exited")) {
d->setContainsMouse(false);
emit exited();
}
}
}
/*!
\internal
*/
......@@ -407,15 +380,6 @@ void QObjectPickerPrivate::setContainsMouse(bool containsMouse)
}
}
QPickEvent *QObjectPickerPrivate::resolvePickEvent(Qt3DCore::QPropertyUpdatedChangePtr e)
{
QObjectPickerEvent ev = e->value().value<QObjectPickerEvent>();
QPickEvent *pickEvent = ev.event.data();
pickEvent->d_func()->m_viewport = static_cast<QViewport *>(scene()->lookupNode(ev.viewportNodeId));
pickEvent->d_func()->m_entityPtr = static_cast<Qt3DCore::QEntity *>(scene()->lookupNode(pickEvent->d_func()->m_entity));
return pickEvent;
}
void QObjectPickerPrivate::propagateEvent(QPickEvent *event, EventType type)
{
if (!m_entities.isEmpty()) {
......
......@@ -90,9 +90,6 @@ Q_SIGNALS:
void containsMouseChanged(bool containsMouse);
Q_REVISION(13) void priorityChanged(int priority);
protected:
void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) override;
private:
Q_DECLARE_PRIVATE(QObjectPicker)
Qt3DCore::QNodeCreatedChangeBasePtr createNodeCreationChange() const override;
......
......@@ -91,7 +91,6 @@ public:
Moved
};
QPickEvent *resolvePickEvent(Qt3DCore::QPropertyUpdatedChangePtr e);
void propagateEvent(QPickEvent *event, EventType type);
void pressedEvent(QPickEvent *event);
......
......@@ -37,6 +37,9 @@
**
****************************************************************************/
#ifndef QT3DRENDER_QPICKEVENT_P_H
#define QT3DRENDER_QPICKEVENT_P_H
//
// W A R N I N G
// -------------
......@@ -95,3 +98,4 @@ public:
QT_END_NAMESPACE
#endif // QT3DRENDER_QPICKEVENT_P_H
......@@ -137,65 +137,6 @@ private Q_SLOTS:
QVERIFY(renderer.dirtyBits() != 0);
}
}
void checkBackendPropertyNotifications()
{
// GIVEN
TestArbiter arbiter;
Qt3DRender::Render::ObjectPicker objectPicker;
Qt3DCore::QBackendNodePrivate::get(&objectPicker)->setArbiter(&arbiter);
Qt3DRender::QPickEventPtr event(new Qt3DRender::QPickEvent);
// WHEN
objectPicker.onPressed(event, Qt3DCore::QNodeId());
// THEN
QCOMPARE(arbiter.events.count(), 1);
Qt3DCore::QPropertyUpdatedChangePtr change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->propertyName(), "pressed");
arbiter.events.clear();
// WHEN
objectPicker.onReleased(event, Qt3DCore::QNodeId());
// THEN
QCOMPARE(arbiter.events.count(), 1);
change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->propertyName(), "released");
arbiter.events.clear();
// WHEN
objectPicker.onClicked(event, Qt3DCore::QNodeId());
// THEN
QCOMPARE(arbiter.events.count(), 1);
change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->propertyName(), "clicked");
arbiter.events.clear();
// WHEN
objectPicker.onEntered();
// THEN
QCOMPARE(arbiter.events.count(), 1);
change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->propertyName(), "entered");
arbiter.events.clear();
// WHEN
objectPicker.onExited();
// THEN
QCOMPARE(arbiter.events.count(), 1);
change = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>();
QCOMPARE(change->propertyName(), "exited");
arbiter.events.clear();
}
};
......
......@@ -153,14 +153,13 @@ private Q_SLOTS:
QCoreApplication::processEvents();
auto dpicker = [](QObjectPicker *node) {
return static_cast<QObjectPickerPrivate *>(QObjectPickerPrivate::get(node));
};
// WHEN
Qt3DRender::QPickEventPtr event(new Qt3DRender::QPickEvent());
QVariant v;
v.setValue<Qt3DRender::QObjectPickerEvent>({event, Qt3DCore::QNodeId()});
Qt3DCore::QPropertyUpdatedChangePtr e(new Qt3DCore::QPropertyUpdatedChange(child11.id()));
e->setPropertyName("pressed");
e->setValue(v);
child11.picker->sceneChangeEvent(e);
dpicker(child11.picker)->pressedEvent(event.data());
// THEN
QCOMPARE(root.pressedCalled, 0);
......@@ -171,7 +170,7 @@ private Q_SLOTS:
// WHEN
child11.pressedCalled = 0;
child11.acceptsEvents = false;
child11.picker->sceneChangeEvent(e);
dpicker(child11.picker)->pressedEvent(event.data());
// THEN
QCOMPARE(root.pressedCalled, 0);
......@@ -184,7 +183,7 @@ private Q_SLOTS:
child1.pressedCalled = 0;
child11.acceptsEvents = false;
child11.pressedCalled = 0;
child11.picker->sceneChangeEvent(e);
dpicker(child11.picker)->pressedEvent(event.data());
// THEN
QCOMPARE(root.pressedCalled, 1);
......@@ -208,16 +207,14 @@ private Q_SLOTS:
QCoreApplication::processEvents();
auto dpicker = [](QObjectPicker *node) {
return static_cast<QObjectPickerPrivate *>(QObjectPickerPrivate::get(node));
};
// WHEN
Qt3DRender::QPickEventPtr event(new Qt3DRender::QPickEvent());
QVariant v;
v.setValue<Qt3DRender::QObjectPickerEvent>({event, Qt3DCore::QNodeId()});
Qt3DCore::QPropertyUpdatedChangePtr e(new Qt3DCore::QPropertyUpdatedChange(child11.id()));
e->setPropertyName("pressed");
e->setValue(v);
child11.picker->sceneChangeEvent(e);
e->setPropertyName("released");
child11.picker->sceneChangeEvent(e);
dpicker(child11.picker)->pressedEvent(event.data());
dpicker(child11.picker)->releasedEvent(event.data());
// THEN
QCOMPARE(root.releasedCalled, 0);
......@@ -229,10 +226,8 @@ private Q_SLOTS:
child11.releasedCalled = 0;
child11.pressedCalled = 0;
child11.acceptsEvents = false;
e->setPropertyName("pressed");
child11.picker->sceneChangeEvent(e);
e->setPropertyName("released");
child11.picker->sceneChangeEvent(e);
dpicker(child11.picker)->pressedEvent(event.data());
dpicker(child11.picker)->releasedEvent(event.data());
// THEN
QCOMPARE(child1.pressedCalled, 1);
......@@ -259,14 +254,13 @@ private Q_SLOTS:
QCoreApplication::processEvents();
auto dpicker = [](QObjectPicker *node) {
return static_cast<QObjectPickerPrivate *>(QObjectPickerPrivate::get(node));
};
// WHEN
Qt3DRender::QPickEventPtr event(new Qt3DRender::QPickEvent());
QVariant v;
v.setValue<Qt3DRender::QObjectPickerEvent>({event, Qt3DCore::QNodeId()});
Qt3DCore::QPropertyUpdatedChangePtr e(new Qt3DCore::QPropertyUpdatedChange(child11.id()));
e->setPropertyName("clicked");
e->setValue(v);
child11.picker->sceneChangeEvent(e);
dpicker(child11.picker)->clickedEvent(event.data());
// THEN
QCOMPARE(root.clickedCalled, 0);
......@@ -277,7 +271,7 @@ private Q_SLOTS:
// WHEN
child11.clickedCalled = 0;
child11.acceptsEvents = false;
child11.picker->sceneChangeEvent(e);
dpicker(child11.picker)->clickedEvent(event.data());
// THEN
QCOMPARE(root.clickedCalled, 0);
......@@ -290,7 +284,7 @@ private Q_SLOTS:
child1.clickedCalled = 0;
child11.acceptsEvents = false;
child11.clickedCalled = 0;
child11.picker->sceneChangeEvent(e);
dpicker(child11.picker)->clickedEvent(event.data());
// THEN
QCOMPARE(root.clickedCalled, 1);
......
......@@ -234,24 +234,6 @@ private Q_SLOTS:
QTest::newRow("objectPicker_all_true") << objectPicker;
}
// TODO: Avoid cloning here
// void checkCloning()
// {
// // GIVEN
// QFETCH(Qt3DRender::QObjectPicker *, objectPicker);
// // WHEN
// Qt3DRender::QObjectPicker *clone = static_cast<Qt3DRender::QObjectPicker *>(QNode::clone(objectPicker));
// QCoreApplication::processEvents();
// // THEN
// QVERIFY(clone != nullptr);
// QCOMPARE(objectPicker->id(), clone->id());
// QCOMPARE(objectPicker->isHoverEnabled(), clone->isHoverEnabled());
// QCOMPARE(objectPicker->isPressed(), clone->isPressed());
// QCOMPARE(objectPicker->containsMouse(), clone->containsMouse());
// }
void checkPropertyUpdates()
{
// GIVEN
......@@ -272,68 +254,6 @@ private Q_SLOTS:
arbiter.dirtyNodes.clear();
}
void checkBackendUpdates_data()
{
QTest::addColumn<QByteArray>("signalPrototype");
QTest::addColumn<QByteArray>("propertyName");
QTest::addColumn<bool>("requiresEvent");