diff options
author | Sean Harmer <sean.harmer@kdab.com> | 2016-11-25 12:09:51 +0000 |
---|---|---|
committer | Jani Heikkinen <jani.heikkinen@qt.io> | 2016-12-07 05:53:54 +0000 |
commit | 22f6718ec4da3851de913d2de18dc0375574a458 (patch) | |
tree | 090c6d0c4baeabc91b16ddc2a721e1e4e8577a61 | |
parent | 073664d6d7cc5b2081c32c4a75b7a6d8030de859 (diff) |
Add plumbing and process AxisAccumulators each frame
Change-Id: I91a0f9384c7ef2ba642db1a2becdba1d2e374d87
Reviewed-by: Kevin Ottens <kevin.ottens@kdab.com>
20 files changed, 529 insertions, 5 deletions
diff --git a/src/input/backend/axisaccumulator.cpp b/src/input/backend/axisaccumulator.cpp index 4843f35f3..3b0423f47 100644 --- a/src/input/backend/axisaccumulator.cpp +++ b/src/input/backend/axisaccumulator.cpp @@ -39,6 +39,7 @@ #include "axisaccumulator_p.h" #include <Qt3DInput/private/qaxisaccumulator_p.h> +#include <Qt3DInput/private/inputmanagers_p.h> #include <Qt3DCore/qpropertyupdatedchange.h> QT_BEGIN_NAMESPACE @@ -52,6 +53,7 @@ AxisAccumulator::AxisAccumulator() , m_sourceAxisType(QAxisAccumulator::Velocity) , m_scale(1.0f) , m_value(0.0f) + , m_velocity(0.0f) { } @@ -62,6 +64,8 @@ void AxisAccumulator::initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBaseP m_sourceAxisId = data.sourceAxisId; m_sourceAxisType = data.sourceAxisType; m_scale = data.scale; + m_value = 0.0f; + m_velocity = 0.0f; } void AxisAccumulator::cleanup() @@ -87,6 +91,20 @@ void AxisAccumulator::setValue(float value) } } +void AxisAccumulator::setVelocity(float velocity) +{ + if (isEnabled() && velocity != m_velocity) { + m_velocity = velocity; + + // Send a change to the frontend + auto e = Qt3DCore::QPropertyUpdatedChangePtr::create(peerId()); + e->setDeliveryFlags(Qt3DCore::QSceneChange::DeliverToAll); + e->setPropertyName("velocity"); + e->setValue(m_velocity); + notifyObservers(e); + } +} + void AxisAccumulator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) { switch (e->type()) { @@ -107,6 +125,30 @@ void AxisAccumulator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) QBackendNode::sceneChangeEvent(e); } +void AxisAccumulator::stepIntegration(AxisManager *axisManager, float dt) +{ + Axis *sourceAxis = axisManager->lookupResource(m_sourceAxisId); + if (!sourceAxis) + return; + + const float axisValue = sourceAxis->axisValue(); + float newVelocity = 0.0f; + float newValue = 0.0f; + switch (m_sourceAxisType) { + case QAxisAccumulator::Velocity: + newVelocity = axisValue * m_scale; + newValue = m_value + newVelocity * dt; + break; + + case QAxisAccumulator::Acceleration: + newVelocity = m_velocity + axisValue * m_scale * dt; + newValue = m_value + newVelocity * dt; + break; + } + setVelocity(newVelocity); + setValue(newValue); +} + } // namespace Input } // namespace Qt3DInput diff --git a/src/input/backend/axisaccumulator_p.h b/src/input/backend/axisaccumulator_p.h index 8ddc9951b..67eb3906a 100644 --- a/src/input/backend/axisaccumulator_p.h +++ b/src/input/backend/axisaccumulator_p.h @@ -61,6 +61,8 @@ QT_BEGIN_NAMESPACE namespace Qt3DInput { namespace Input { +class AxisManager; + class Q_AUTOTEST_EXPORT AxisAccumulator : public Qt3DCore::QBackendNode { public: @@ -74,8 +76,13 @@ public: float value() const Q_DECL_NOTHROW { return m_value; } void setValue(float value); + float velocity() const Q_DECL_NOTHROW { return m_velocity; } + void setVelocity(float velocity); + void sceneChangeEvent(const Qt3DCore::QSceneChangePtr &e) Q_DECL_OVERRIDE; + void stepIntegration(AxisManager *axisManager, float dt); + private: void initializeFromPeer(const Qt3DCore::QNodeCreatedChangeBasePtr &change) Q_DECL_FINAL; @@ -83,6 +90,7 @@ private: QAxisAccumulator::SourceAxisType m_sourceAxisType; float m_scale; float m_value; + float m_velocity; }; } // namespace Input diff --git a/src/input/backend/axisaccumulatorjob.cpp b/src/input/backend/axisaccumulatorjob.cpp new file mode 100644 index 000000000..133f9713a --- /dev/null +++ b/src/input/backend/axisaccumulatorjob.cpp @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "axisaccumulatorjob_p.h" +#include <Qt3DInput/private/axisaccumulator_p.h> +#include <Qt3DInput/private/job_common_p.h> +#include <Qt3DInput/private/inputmanagers_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DInput { +namespace Input { + +AxisAccumulatorJob::AxisAccumulatorJob(AxisAccumulatorManager *axisAccumulatormanager, + AxisManager *axisManager) + : Qt3DCore::QAspectJob() + , m_axisAccumulatorManager(axisAccumulatormanager) + , m_axisManager(axisManager) + , m_dt(0.0f) +{ + SET_JOB_RUN_STAT_TYPE(this, JobTypes::AxisAccumulatorIntegration, 0); +} + +void AxisAccumulatorJob::run() +{ + // Iterate over the accumulators and ask each to step the integrations + for (auto accumulatorHandle : m_axisAccumulatorManager->activeHandles()) { + AxisAccumulator *accumulator = m_axisAccumulatorManager->data(accumulatorHandle); + if (accumulator->isEnabled()) + accumulator->stepIntegration(m_axisManager, m_dt); + } +} + +} // namespace Input +} // namespace Qt3DInput + +QT_END_NAMESPACE diff --git a/src/input/backend/axisaccumulatorjob_p.h b/src/input/backend/axisaccumulatorjob_p.h new file mode 100644 index 000000000..d8ced8a3a --- /dev/null +++ b/src/input/backend/axisaccumulatorjob_p.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2016 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QT3DINPUT_INPUT_AXISACCUMULATORJOB_H +#define QT3DINPUT_INPUT_AXISACCUMULATORJOB_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists for the convenience +// of other Qt classes. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include <Qt3DCore/qaspectjob.h> +#include <Qt3DCore/qnodeid.h> +#include <Qt3DInput/private/handle_types_p.h> + +QT_BEGIN_NAMESPACE + +namespace Qt3DInput { +namespace Input { + +class AxisAccumulatorManager; +class AxisManager; + +class Q_AUTOTEST_EXPORT AxisAccumulatorJob : public Qt3DCore::QAspectJob +{ +public: + AxisAccumulatorJob(AxisAccumulatorManager *axisAccumulatormanager, + AxisManager *axisManager); + + void setDeltaTime(float dt) { m_dt = dt; } + + void run() override; + +private: + AxisAccumulatorManager *m_axisAccumulatorManager; + AxisManager *m_axisManager; + float m_dt; +}; + +typedef QSharedPointer<AxisAccumulatorJob> AxisAccumulatorJobPtr; + +} // namespace Input +} // namespace Qt3DInput + +QT_END_NAMESPACE + +#endif // QT3DINPUT_INPUT_AXISACCUMULATORJOB_H diff --git a/src/input/backend/backend.pri b/src/input/backend/backend.pri index a0f6df9f0..71c1a9a1c 100644 --- a/src/input/backend/backend.pri +++ b/src/input/backend/backend.pri @@ -35,7 +35,8 @@ HEADERS += \ $$PWD/physicaldeviceproxy_p.h \ $$PWD/loadproxydevicejob_p.h \ $$PWD/utils_p.h \ - $$PWD/axisaccumulator_p.h + $$PWD/axisaccumulator_p.h \ + $$PWD/axisaccumulatorjob_p.h SOURCES += \ $$PWD/keyboarddevice.cpp \ @@ -68,6 +69,7 @@ SOURCES += \ $$PWD/eventsourcesetterhelper.cpp \ $$PWD/physicaldeviceproxy.cpp \ $$PWD/loadproxydevicejob.cpp \ - $$PWD/axisaccumulator.cpp + $$PWD/axisaccumulator.cpp \ + $$PWD/axisaccumulatorjob.cpp INCLUDEPATH += $$PWD diff --git a/src/input/backend/handle_types_p.h b/src/input/backend/handle_types_p.h index cc78a68ba..c132fdc99 100644 --- a/src/input/backend/handle_types_p.h +++ b/src/input/backend/handle_types_p.h @@ -73,6 +73,7 @@ class InputChord; class LogicalDevice; class GenericDeviceBackendNode; class PhysicalDeviceProxy; +class AxisAccumulator; typedef Qt3DCore::QHandle<KeyboardDevice, 8> HKeyboardDevice; typedef Qt3DCore::QHandle<KeyboardHandler, 16> HKeyboardHandler; @@ -89,6 +90,7 @@ typedef Qt3DCore::QHandle<InputChord, 16> HInputChord; typedef Qt3DCore::QHandle<LogicalDevice, 16> HLogicalDevice; typedef Qt3DCore::QHandle<GenericDeviceBackendNode, 8> HGenericDeviceBackendNode; typedef Qt3DCore::QHandle<PhysicalDeviceProxy, 16> HPhysicalDeviceProxy; +typedef Qt3DCore::QHandle<AxisAccumulator, 16> HAxisAccumulator; } // namespace Input } // namespace Qt3DInput diff --git a/src/input/backend/inputhandler.cpp b/src/input/backend/inputhandler.cpp index 82b5c7c7c..aebf2c8f1 100644 --- a/src/input/backend/inputhandler.cpp +++ b/src/input/backend/inputhandler.cpp @@ -64,6 +64,7 @@ InputHandler::InputHandler() , m_keyboardEventFilter(new KeyboardEventFilter()) , m_mouseEventFilter(new MouseEventFilter()) , m_axisManager(new AxisManager()) + , m_axisAccumulatorManager(new AxisAccumulatorManager()) , m_actionManager(new ActionManager()) , m_axisSettingManager(new AxisSettingManager()) , m_actionInputManager(new ActionInputManager()) @@ -93,6 +94,7 @@ InputHandler::~InputHandler() delete m_keyboardEventFilter; delete m_mouseEventFilter; delete m_axisManager; + delete m_axisAccumulatorManager; delete m_actionManager; delete m_axisSettingManager; delete m_analogAxisInputManager; diff --git a/src/input/backend/inputhandler_p.h b/src/input/backend/inputhandler_p.h index 1628f3975..eff0c0c24 100644 --- a/src/input/backend/inputhandler_p.h +++ b/src/input/backend/inputhandler_p.h @@ -79,6 +79,7 @@ class MouseDeviceManager; class MouseInputManager; class MouseEventFilter; class AxisManager; +class AxisAccumulatorManager; class ActionManager; class AxisSettingManager; class ActionInputManager; @@ -104,6 +105,7 @@ public: inline MouseDeviceManager *mouseDeviceManager() const { return m_mouseDeviceManager; } inline MouseInputManager *mouseInputManager() const { return m_mouseInputManager; } inline AxisManager *axisManager() const { return m_axisManager; } + inline AxisAccumulatorManager *axisAccumulatorManager() const { return m_axisAccumulatorManager; } inline ActionManager *actionManager() const { return m_actionManager; } inline AxisSettingManager *axisSettingManager() const { return m_axisSettingManager; } inline ActionInputManager *actionInputManager() const { return m_actionInputManager; } @@ -171,6 +173,7 @@ private: mutable QMutex m_mutex; AxisManager *m_axisManager; + AxisAccumulatorManager *m_axisAccumulatorManager; ActionManager *m_actionManager; AxisSettingManager *m_axisSettingManager; ActionInputManager *m_actionInputManager; diff --git a/src/input/backend/inputmanagers_p.h b/src/input/backend/inputmanagers_p.h index d162ea519..473042867 100644 --- a/src/input/backend/inputmanagers_p.h +++ b/src/input/backend/inputmanagers_p.h @@ -63,6 +63,7 @@ #include <Qt3DInput/private/inputchord_p.h> #include <Qt3DInput/private/action_p.h> #include <Qt3DInput/private/axis_p.h> +#include <Qt3DInput/private/axisaccumulator_p.h> #include <Qt3DInput/private/axissetting_p.h> #include <Qt3DInput/private/analogaxisinput_p.h> #include <Qt3DInput/private/buttonaxisinput_p.h> @@ -238,6 +239,16 @@ private: QVector<Qt3DCore::QNodeId> m_pendingProxies; }; +class AxisAccumulatorManager : public Qt3DCore::QResourceManager< + AxisAccumulator, + Qt3DCore::QNodeId, + 16, + Qt3DCore::ArrayAllocatingPolicy> +{ +public: + AxisAccumulatorManager() {} +}; + } // namespace Input } // namespace Qt3DInput diff --git a/src/input/backend/job_common_p.h b/src/input/backend/job_common_p.h index 589c75fb9..7377e4729 100644 --- a/src/input/backend/job_common_p.h +++ b/src/input/backend/job_common_p.h @@ -66,7 +66,8 @@ namespace JobTypes { KeyEventDispatcher, MouseEventDispatcher, UpdateAxisAction, - DeviceProxyLoading + DeviceProxyLoading, + AxisAccumulatorIntegration }; } // JobTypes diff --git a/src/input/frontend/qaxisaccumulator.cpp b/src/input/frontend/qaxisaccumulator.cpp index 9a14c0deb..0785ad689 100644 --- a/src/input/frontend/qaxisaccumulator.cpp +++ b/src/input/frontend/qaxisaccumulator.cpp @@ -108,6 +108,7 @@ QAxisAccumulatorPrivate::QAxisAccumulatorPrivate() , m_sourceAxisType(QAxisAccumulator::Velocity) , m_scale(1.0f) , m_value(0.0f) + , m_velocity(0.0f) { } @@ -115,8 +116,23 @@ QAxisAccumulatorPrivate::QAxisAccumulatorPrivate() void QAxisAccumulatorPrivate::setValue(float value) { if (value != m_value) { + Q_Q(QAxisAccumulator); m_value = value; - q_func()->valueChanged(m_value); + const bool wasBlocked = q->blockNotifications(true); + q->valueChanged(m_value); + q->blockNotifications(wasBlocked); + } +} + +/*! \internal */ +void QAxisAccumulatorPrivate::setVelocity(float velocity) +{ + if (velocity != m_velocity) { + Q_Q(QAxisAccumulator); + m_velocity = velocity; + const bool wasBlocked = q->blockNotifications(true); + q->velocityChanged(m_velocity); + q->blockNotifications(wasBlocked); } } @@ -180,6 +196,18 @@ float QAxisAccumulator::value() const } /*! + Returns the velocity. If the sourceAxisType is set to Velocity this is + simply the value of the source axis multiplied by the scale. If the + sourceAxisType is set to Acceleration, the velocity is integrated using + the source axis' value as an acceleration. + */ +float QAxisAccumulator::velocity() const +{ + Q_D(const QAxisAccumulator); + return d->m_velocity; +} + +/*! \qmlproperty real Qt3D.Input::AxisAccumulator::value The amount to scale the axis value by when accumulating. This can be @@ -255,6 +283,8 @@ void QAxisAccumulator::sceneChangeEvent(const Qt3DCore::QSceneChangePtr &change) auto e = qSharedPointerCast<Qt3DCore::QPropertyUpdatedChange>(change); if (e->type() == Qt3DCore::PropertyUpdated && e->propertyName() == QByteArrayLiteral("value")) d->setValue(e->value().toFloat()); + else if (e->type() == Qt3DCore::PropertyUpdated && e->propertyName() == QByteArrayLiteral("velocity")) + d->setVelocity(e->value().toFloat()); } /*! \internal */ diff --git a/src/input/frontend/qaxisaccumulator.h b/src/input/frontend/qaxisaccumulator.h index 009b2531c..b31f57a48 100644 --- a/src/input/frontend/qaxisaccumulator.h +++ b/src/input/frontend/qaxisaccumulator.h @@ -57,6 +57,7 @@ class QT3DINPUTSHARED_EXPORT QAxisAccumulator : public Qt3DCore::QComponent Q_PROPERTY(SourceAxisType sourceAxisType READ sourceAxisType WRITE setSourceAxisType NOTIFY sourceAxisTypeChanged) Q_PROPERTY(float scale READ scale WRITE setScale NOTIFY scaleChanged) Q_PROPERTY(float value READ value NOTIFY valueChanged) + Q_PROPERTY(float velocity READ velocity NOTIFY velocityChanged) public: enum SourceAxisType { @@ -71,6 +72,7 @@ public: Qt3DInput::QAxis *sourceAxis() const; SourceAxisType sourceAxisType() const; float value() const; + float velocity() const; float scale() const; public Q_SLOTS: @@ -82,6 +84,7 @@ Q_SIGNALS: void sourceAxisChanged(Qt3DInput::QAxis *sourceAxis); void sourceAxisTypeChanged(QAxisAccumulator::SourceAxisType sourceAxisType); void valueChanged(float value); + void velocityChanged(float value); void scaleChanged(float scale); protected: diff --git a/src/input/frontend/qaxisaccumulator_p.h b/src/input/frontend/qaxisaccumulator_p.h index be0410c5c..532f01b6b 100644 --- a/src/input/frontend/qaxisaccumulator_p.h +++ b/src/input/frontend/qaxisaccumulator_p.h @@ -66,11 +66,13 @@ public: Q_DECLARE_PUBLIC(QAxisAccumulator) void setValue(float value); + void setVelocity(float velocity); QAxis *m_sourceAxis; QAxisAccumulator::SourceAxisType m_sourceAxisType; float m_scale; float m_value; + float m_velocity; }; struct QAxisAccumulatorData diff --git a/src/input/frontend/qinputaspect.cpp b/src/input/frontend/qinputaspect.cpp index 5ad5c644c..066d2381a 100644 --- a/src/input/frontend/qinputaspect.cpp +++ b/src/input/frontend/qinputaspect.cpp @@ -61,6 +61,7 @@ #include <QPluginLoader> #include <Qt3DInput/qaxis.h> +#include <Qt3DInput/qaxisaccumulator.h> #include <Qt3DInput/qaction.h> #include <Qt3DInput/qaxissetting.h> #include <Qt3DInput/qactioninput.h> @@ -72,6 +73,7 @@ #include <Qt3DInput/qabstractphysicaldevice.h> #include <Qt3DInput/private/qabstractphysicaldeviceproxy_p.h> #include <Qt3DInput/private/axis_p.h> +#include <Qt3DInput/private/axisaccumulator_p.h> #include <Qt3DInput/private/action_p.h> #include <Qt3DInput/private/axissetting_p.h> #include <Qt3DInput/private/actioninput_p.h> @@ -86,6 +88,7 @@ #include <Qt3DInput/private/inputsettings_p.h> #include <Qt3DInput/private/eventsourcesetterhelper_p.h> #include <Qt3DInput/private/loadproxydevicejob_p.h> +#include <Qt3DInput/private/axisaccumulatorjob_p.h> #ifdef HAVE_QGAMEPAD # include <Qt3DInput/private/qgamepadinput_p.h> @@ -101,6 +104,7 @@ QInputAspectPrivate::QInputAspectPrivate() : QAbstractAspectPrivate() , m_inputHandler(new Input::InputHandler()) , m_keyboardMouseIntegration(new Input::KeyboardMouseGenericDeviceIntegration(m_inputHandler.data())) + , m_time(0) { } @@ -134,6 +138,7 @@ QInputAspect::QInputAspect(QInputAspectPrivate &dd, QObject *parent) registerBackendType<QMouseDevice>(QBackendNodeMapperPtr(new Input::MouseDeviceFunctor(this, d_func()->m_inputHandler.data()))); registerBackendType<QMouseHandler>(QBackendNodeMapperPtr(new Input::MouseHandlerFunctor(d_func()->m_inputHandler.data()))); registerBackendType<QAxis>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::Axis, Input::AxisManager>(d_func()->m_inputHandler->axisManager()))); + registerBackendType<QAxisAccumulator>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::AxisAccumulator, Input::AxisAccumulatorManager>(d_func()->m_inputHandler->axisAccumulatorManager()))); registerBackendType<QAnalogAxisInput>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::AnalogAxisInput, Input::AnalogAxisInputManager>(d_func()->m_inputHandler->analogAxisInputManager()))); registerBackendType<QButtonAxisInput>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::ButtonAxisInput, Input::ButtonAxisInputManager>(d_func()->m_inputHandler->buttonAxisInputManager()))); registerBackendType<QAxisSetting>(QBackendNodeMapperPtr(new Input::InputNodeFunctor<Input::AxisSetting, Input::AxisSettingManager>(d_func()->m_inputHandler->axisSettingManager()))); @@ -213,6 +218,10 @@ QStringList QInputAspect::availablePhysicalDevices() const QVector<QAspectJobPtr> QInputAspect::jobsToExecute(qint64 time) { Q_D(QInputAspect); + const qint64 deltaTime = time - d->m_time; + const float dt = static_cast<const float>(deltaTime) / 1.0e9; + d->m_time = time; + QVector<QAspectJobPtr> jobs; d->m_inputHandler->updateEventSource(); @@ -240,6 +249,8 @@ QVector<QAspectJobPtr> QInputAspect::jobsToExecute(qint64 time) // Jobs that update Axis/Action (store combined axis/action value) const auto devHandles = d->m_inputHandler->logicalDeviceManager()->activeDevices(); + QVector<QAspectJobPtr> axisActionJobs; + axisActionJobs.reserve(devHandles.size()); for (Input::HLogicalDevice devHandle : devHandles) { const auto device = d->m_inputHandler->logicalDeviceManager()->data(devHandle); if (!device->isEnabled()) @@ -247,10 +258,20 @@ QVector<QAspectJobPtr> QInputAspect::jobsToExecute(qint64 time) QAspectJobPtr updateAxisActionJob(new Input::UpdateAxisActionJob(time, d->m_inputHandler.data(), devHandle)); jobs += updateAxisActionJob; + axisActionJobs.push_back(updateAxisActionJob); for (const QAspectJobPtr &job : dependsOnJobs) updateAxisActionJob->addDependency(job); } + // Once all the axes have been updated we can step the integrations on + // the AxisAccumulators + auto accumulateJob = Input::AxisAccumulatorJobPtr::create(d->m_inputHandler->axisAccumulatorManager(), + d->m_inputHandler->axisManager()); + accumulateJob->setDeltaTime(dt); + for (const QAspectJobPtr &job : qAsConst(axisActionJobs)) + accumulateJob->addDependency(job); + jobs.push_back(accumulateJob); + return jobs; } diff --git a/src/input/frontend/qinputaspect_p.h b/src/input/frontend/qinputaspect_p.h index d123e6216..35a4ffa02 100644 --- a/src/input/frontend/qinputaspect_p.h +++ b/src/input/frontend/qinputaspect_p.h @@ -73,6 +73,7 @@ public: Q_DECLARE_PUBLIC(QInputAspect) QScopedPointer<Input::InputHandler> m_inputHandler; QScopedPointer<Input::KeyboardMouseGenericDeviceIntegration> m_keyboardMouseIntegration; + qint64 m_time; }; } // namespace Qt3DInput diff --git a/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp b/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp index a1c769aaa..94cb71030 100644 --- a/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp +++ b/tests/auto/input/axisaccumulator/tst_axisaccumulator.cpp @@ -36,6 +36,7 @@ #include <Qt3DInput/private/axis_p.h> #include <Qt3DInput/private/axisaccumulator_p.h> #include <Qt3DInput/private/qabstractaxisinput_p.h> +#include <Qt3DInput/private/inputmanagers_p.h> #include <Qt3DInput/QAnalogAxisInput> #include <Qt3DInput/QAxis> #include <Qt3DInput/QAxisAccumulator> @@ -79,6 +80,7 @@ private Q_SLOTS: QVERIFY(backendAxisAccumulator.peerId().isNull()); QCOMPARE(backendAxisAccumulator.isEnabled(), false); QCOMPARE(backendAxisAccumulator.value(), 0.0f); + QCOMPARE(backendAxisAccumulator.velocity(), 0.0f); QCOMPARE(backendAxisAccumulator.scale(), 1.0f); QCOMPARE(backendAxisAccumulator.sourceAxisId(), Qt3DCore::QNodeId()); QCOMPARE(backendAxisAccumulator.sourceAxisType(), Qt3DInput::QAxisAccumulator::Velocity); @@ -99,6 +101,7 @@ private Q_SLOTS: // THEN QCOMPARE(backendAxisAccumulator.isEnabled(), false); QCOMPARE(backendAxisAccumulator.value(), 0.0f); + QCOMPARE(backendAxisAccumulator.velocity(), 0.0f); QCOMPARE(backendAxisAccumulator.scale(), 1.0f); QCOMPARE(backendAxisAccumulator.sourceAxisId(), Qt3DCore::QNodeId()); QCOMPARE(backendAxisAccumulator.sourceAxisType(), Qt3DInput::QAxisAccumulator::Velocity); @@ -177,6 +180,28 @@ private Q_SLOTS: QCOMPARE(arbiter.events.count(), 0); arbiter.events.clear(); + + + // WHEN + backendAxisAccumulator.setVelocity(383.0f); + + // THEN + QCOMPARE(backendAxisAccumulator.velocity(), 383.0f); + QCOMPARE(arbiter.events.count(), 1); + Qt3DCore::QPropertyUpdatedChangePtr velocityChange = arbiter.events.first().staticCast<Qt3DCore::QPropertyUpdatedChange>(); + QCOMPARE(velocityChange->propertyName(), "velocity"); + QCOMPARE(velocityChange->value().toFloat(), backendAxisAccumulator.velocity()); + + arbiter.events.clear(); + + // WHEN + backendAxisAccumulator.setVelocity(383.0f); + + // THEN + QCOMPARE(backendAxisAccumulator.velocity(), 383.0f); + QCOMPARE(arbiter.events.count(), 0); + + arbiter.events.clear(); } void shouldNotChangeValueWhenDisabled() @@ -194,6 +219,91 @@ private Q_SLOTS: QCOMPARE(backendAxisAccumulator.value(), 0.0f); QCOMPARE(arbiter.events.count(), 0); } + + void checkIntegration_data() + { + QTest::addColumn<Qt3DInput::QAxisAccumulator::SourceAxisType>("sourceAxisType"); + QTest::addColumn<float>("axisValue"); + QTest::addColumn<float>("scale"); + QTest::addColumn<float>("dt"); + QTest::addColumn<float>("valueResult"); + QTest::addColumn<float>("velocityResult"); + + QTest::newRow("velocity=10, axis=1, dt=1") << Qt3DInput::QAxisAccumulator::Velocity + << 1.0f + << 10.0f + << 1.0f + << 10.0f + << 0.0f; + + QTest::newRow("velocity=10, axis=1, dt=0.2") << Qt3DInput::QAxisAccumulator::Velocity + << 1.0f + << 10.0f + << 0.2f + << 2.0f + << 0.0f; + + QTest::newRow("velocity=20, axis=1, dt=0.1") << Qt3DInput::QAxisAccumulator::Velocity + << 1.0f + << 20.0f + << 0.1f + << 2.0f + << 0.0f; + + QTest::newRow("velocity=10, axis=0.5, dt=1") << Qt3DInput::QAxisAccumulator::Velocity + << 0.5f + << 10.0f + << 1.0f + << 5.0f + << 0.0f; + + QTest::newRow("acceleration=10, axis=1, dt=1") << Qt3DInput::QAxisAccumulator::Acceleration + << 1.0f + << 10.0f + << 1.0f + << 10.0f + << 10.0f; + } + + void checkIntegration() + { + // GIVEN + QFETCH(Qt3DInput::QAxisAccumulator::SourceAxisType, sourceAxisType); + QFETCH(float, axisValue); + QFETCH(float, scale); + QFETCH(float, dt); + QFETCH(float, valueResult); + QFETCH(float, velocityResult); + + Qt3DInput::QAxis *axis = new Qt3DInput::QAxis; + Qt3DInput::Input::AxisManager axisManager; + Qt3DInput::Input::Axis *backendAxis = axisManager.getOrCreateResource(axis->id()); + Qt3DInput::QAxisAccumulator axisAccumulator; + Qt3DInput::Input::AxisAccumulator backendAxisAccumulator; + + // WHEN + backendAxis->setEnabled(true); + backendAxis->setAxisValue(axisValue); + axisAccumulator.setSourceAxis(axis); + axisAccumulator.setScale(scale); + axisAccumulator.setSourceAxisType(sourceAxisType); + axisAccumulator.setEnabled(true); + simulateInitialization(&axisAccumulator, &backendAxisAccumulator); + + backendAxisAccumulator.stepIntegration(&axisManager, dt); + + // THEN + switch (sourceAxisType) { + case Qt3DInput::QAxisAccumulator::Velocity: + QCOMPARE(backendAxisAccumulator.value(), valueResult); + break; + + case Qt3DInput::QAxisAccumulator::Acceleration: + QCOMPARE(backendAxisAccumulator.velocity(), velocityResult); + QCOMPARE(backendAxisAccumulator.value(), valueResult); + break; + } + } }; QTEST_APPLESS_MAIN(tst_AxisAccumulator) diff --git a/tests/auto/input/axisaccumulatorjob/axisaccumulatorjob.pro b/tests/auto/input/axisaccumulatorjob/axisaccumulatorjob.pro new file mode 100644 index 000000000..ad1a1a469 --- /dev/null +++ b/tests/auto/input/axisaccumulatorjob/axisaccumulatorjob.pro @@ -0,0 +1,11 @@ +TEMPLATE = app + +TARGET = tst_axisaccumulatorjob + +QT += core-private 3dcore 3dcore-private 3dinput 3dinput-private testlib + +CONFIG += testcase + +SOURCES += tst_axisaccumulatorjob.cpp + +include(../../core/common/common.pri) diff --git a/tests/auto/input/axisaccumulatorjob/tst_axisaccumulatorjob.cpp b/tests/auto/input/axisaccumulatorjob/tst_axisaccumulatorjob.cpp new file mode 100644 index 000000000..fa3bca3d2 --- /dev/null +++ b/tests/auto/input/axisaccumulatorjob/tst_axisaccumulatorjob.cpp @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the Qt3D module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL-EXCEPT$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtTest/QTest> +#include <qbackendnodetester.h> +#include <Qt3DCore/private/qnode_p.h> +#include <Qt3DCore/private/qscene_p.h> +#include <Qt3DCore/qpropertyupdatedchange.h> +#include <Qt3DCore/qpropertynodeaddedchange.h> +#include <Qt3DCore/qpropertynoderemovedchange.h> +#include <Qt3DInput/private/axis_p.h> +#include <Qt3DInput/private/axisaccumulator_p.h> +#include <Qt3DInput/private/axisaccumulatorjob_p.h> +#include <Qt3DInput/private/qabstractaxisinput_p.h> +#include <Qt3DInput/private/inputmanagers_p.h> +#include <Qt3DInput/QAnalogAxisInput> +#include <Qt3DInput/QAxis> +#include <Qt3DInput/QAxisAccumulator> +#include <Qt3DCore/private/qbackendnode_p.h> +#include "testpostmanarbiter.h" + +class tst_AxisAccumulatorJob : public Qt3DCore::QBackendNodeTester +{ + Q_OBJECT + +private Q_SLOTS: + void checkIntegration() + { + // GIVEN + const auto sourceAxisType = Qt3DInput::QAxisAccumulator::Velocity; + const float axisValue = 1.0f; + const float scale = 10.0f; + const float dt = 0.1f; + const float valueResultEnabled = 1.0f; + const float valueResultDisabled = 0.0f; + + // Set up an axis + Qt3DInput::QAxis *axis = new Qt3DInput::QAxis; + Qt3DInput::Input::AxisManager axisManager; + Qt3DInput::Input::Axis *backendAxis = axisManager.getOrCreateResource(axis->id()); + backendAxis->setEnabled(true); + backendAxis->setAxisValue(axisValue); + + // Hook up a bunch of accumulators to this axis + Qt3DInput::Input::AxisAccumulatorManager axisAccumulatorManager; + QVector<Qt3DInput::Input::AxisAccumulator *> accumulators; + for (int i = 0; i < 10; ++i) { + auto axisAccumulator = new Qt3DInput::QAxisAccumulator; + Qt3DInput::Input::AxisAccumulator *backendAxisAccumulator + = axisAccumulatorManager.getOrCreateResource(axisAccumulator->id()); + accumulators.push_back(backendAxisAccumulator); + + axisAccumulator->setEnabled(i % 2 == 0); // Enable only even accumulators + axisAccumulator->setSourceAxis(axis); + axisAccumulator->setScale(scale); + axisAccumulator->setSourceAxisType(sourceAxisType); + simulateInitialization(axisAccumulator, backendAxisAccumulator); + } + + // WHEN + Qt3DInput::Input::AxisAccumulatorJob job(&axisAccumulatorManager, &axisManager); + job.setDeltaTime(dt); + job.run(); + + + // THEN + for (const auto accumulator : accumulators) { + QCOMPARE(accumulator->value(), accumulator->isEnabled() ? valueResultEnabled + : valueResultDisabled); + } + } +}; + +QTEST_APPLESS_MAIN(tst_AxisAccumulatorJob) + +#include "tst_axisaccumulatorjob.moc" diff --git a/tests/auto/input/input.pro b/tests/auto/input/input.pro index fdd7ed2f7..6169d3f7c 100644 --- a/tests/auto/input/input.pro +++ b/tests/auto/input/input.pro @@ -28,5 +28,6 @@ qtConfig(private_tests) { qmousedevice \ mousedevice \ utils \ - axisaccumulator + axisaccumulator \ + axisaccumulatorjob } diff --git a/tests/auto/input/qaxisaccumulator/tst_qaxisaccumulator.cpp b/tests/auto/input/qaxisaccumulator/tst_qaxisaccumulator.cpp index a98cf09a9..3df09a67a 100644 --- a/tests/auto/input/qaxisaccumulator/tst_qaxisaccumulator.cpp +++ b/tests/auto/input/qaxisaccumulator/tst_qaxisaccumulator.cpp @@ -183,6 +183,17 @@ private Q_SLOTS: // THEN QCOMPARE(value(), 383.0f); + QCOMPARE(velocity(), 0.0f); + + // WHEN + valueChange.reset(new Qt3DCore::QPropertyUpdatedChange(Qt3DCore::QNodeId())); + valueChange->setPropertyName("velocity"); + valueChange->setValue(123.0f); + sceneChangeEvent(valueChange); + + // THEN + QCOMPARE(value(), 383.0f); + QCOMPARE(velocity(), 123.0f); } void checkAxisInputBookkeeping() |