/**************************************************************************** ** ** 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: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 "qabstractphysicaldevicebackendnode_p.h" #include "qabstractphysicaldevicebackendnode_p_p.h" #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace { constexpr int signum(float v) { return (v > 0.0f) - (v < 0.0f); } } namespace Qt3DInput { QAbstractPhysicalDeviceBackendNodePrivate::QAbstractPhysicalDeviceBackendNodePrivate(Qt3DCore::QBackendNode::Mode mode) : Qt3DCore::QBackendNodePrivate(mode) , m_axisSettings() , m_inputAspect(nullptr) { } void QAbstractPhysicalDeviceBackendNodePrivate::addAxisSetting(int axisIdentifier, Qt3DCore::QNodeId axisSettingsId) { Input::AxisIdSetting axisIdSetting; axisIdSetting.m_axisIdentifier = axisIdentifier; axisIdSetting.m_axisSettingsId = axisSettingsId; // Replace if already present, otherwise append const auto end = m_axisSettings.end(); for (auto it = m_axisSettings.begin(); it != end; ++it) { if (it->m_axisIdentifier == axisIdentifier) { *it = axisIdSetting; return; } } m_axisSettings.push_back(axisIdSetting); } void QAbstractPhysicalDeviceBackendNodePrivate::removeAxisSetting(Qt3DCore::QNodeId axisSettingsId) { const auto end = m_axisSettings.end(); for (auto it = m_axisSettings.begin(); it != end; ++it) { if (it->m_axisSettingsId == axisSettingsId) { m_axisSettings.erase(it); return; } } } Input::MovingAverage &QAbstractPhysicalDeviceBackendNodePrivate::getOrCreateFilter(int axisIdentifier) { const auto end = m_axisFilters.end(); for (auto it = m_axisFilters.begin(); it != end; ++it) { if (it->m_axisIdentifier == axisIdentifier) return it->m_filter; } Input::AxisIdFilter axisIdFilter; axisIdFilter.m_axisIdentifier = axisIdentifier; m_axisFilters.push_back(axisIdFilter); return m_axisFilters.last().m_filter; } Input::AxisSetting *QAbstractPhysicalDeviceBackendNodePrivate::getAxisSetting(Qt3DCore::QNodeId axisSettingId) const { Q_Q(const QAbstractPhysicalDeviceBackendNode); QInputAspectPrivate *aspectPrivate = static_cast(Qt3DCore::QAbstractAspectPrivate::get(q->inputAspect())); Input::InputHandler *handler = aspectPrivate->m_inputHandler.data(); Input::AxisSetting *axisSetting = handler->axisSettingManager()->getOrCreateResource(axisSettingId); return axisSetting; } QAbstractPhysicalDeviceBackendNode::QAbstractPhysicalDeviceBackendNode(QBackendNode::Mode mode) : Input::BackendNode(*new QAbstractPhysicalDeviceBackendNodePrivate(mode)) { } QAbstractPhysicalDeviceBackendNode::QAbstractPhysicalDeviceBackendNode(QAbstractPhysicalDeviceBackendNodePrivate &dd) : Input::BackendNode(dd) { } void QAbstractPhysicalDeviceBackendNode::cleanup() { Q_D(QAbstractPhysicalDeviceBackendNode); QBackendNode::setEnabled(false); d->m_axisSettings.clear(); d->m_axisFilters.clear(); d->m_inputAspect = nullptr; } void QAbstractPhysicalDeviceBackendNode::syncFromFrontEnd(const Qt3DCore::QNode *frontEnd, bool firstTime) { Q_D(QAbstractPhysicalDeviceBackendNode); BackendNode::syncFromFrontEnd(frontEnd, firstTime); const Qt3DInput::QAbstractPhysicalDevice *node = qobject_cast(frontEnd); if (!node) return; auto settings = Qt3DCore::qIdsForNodes(node->axisSettings()); std::sort(std::begin(settings), std::end(settings)); Qt3DCore::QNodeIdVector addedSettings; Qt3DCore::QNodeIdVector removedSettings; std::set_difference(std::begin(settings), std::end(settings), std::begin(d->m_currentAxisSettingIds), std::end(d->m_currentAxisSettingIds), std::inserter(addedSettings, addedSettings.end())); std::set_difference(std::begin(d->m_currentAxisSettingIds), std::end(d->m_currentAxisSettingIds), std::begin(settings), std::end(settings), std::inserter(removedSettings, removedSettings.end())); d->m_currentAxisSettingIds = settings; for (const auto &axisSettingId: qAsConst(addedSettings)) { Input::AxisSetting *axisSetting = d->getAxisSetting(axisSettingId); const auto axisIds = axisSetting->axes(); for (int axisId : axisIds) d->addAxisSetting(axisId, axisSettingId); } for (const auto &axisSettingId: qAsConst(removedSettings)) d->removeAxisSetting(axisSettingId); } void QAbstractPhysicalDeviceBackendNode::setInputAspect(QInputAspect *aspect) { Q_D(QAbstractPhysicalDeviceBackendNode); d->m_inputAspect = aspect; } QInputAspect *QAbstractPhysicalDeviceBackendNode::inputAspect() const { Q_D(const QAbstractPhysicalDeviceBackendNode); return d->m_inputAspect; } float QAbstractPhysicalDeviceBackendNode::processedAxisValue(int axisIdentifier) { Q_D(QAbstractPhysicalDeviceBackendNode); // Find axis settings for this axis (if any) Qt3DCore::QNodeId axisSettingId; const auto end = d->m_axisSettings.cend(); for (auto it = d->m_axisSettings.cbegin(); it != end; ++it) { if (it->m_axisIdentifier == axisIdentifier) { axisSettingId = it->m_axisSettingsId; break; } } const float rawAxisValue = axisValue(axisIdentifier); if (axisSettingId.isNull()) { // No special processing. Just return the raw value return rawAxisValue; } else { // Process the raw value in accordance with the settings Input::AxisSetting *axisSetting = d->getAxisSetting(axisSettingId); Q_ASSERT(axisSetting); float val = rawAxisValue; // Low pass smoothing if (axisSetting->isSmoothEnabled()) { // Get the filter corresponding to this axis Input::MovingAverage &filter = d->getOrCreateFilter(axisIdentifier); filter.addSample(val); val = filter.average(); } // Deadzone handling const float d = axisSetting->deadZoneRadius(); if (!qFuzzyIsNull(d)) { if (std::abs(val) <= d) { val = 0.0f; } else { // Calculate value that goes from 0 to 1 linearly from the boundary of // the dead zone up to 1. That is we with a dead zone value of d, we do not // want a step change from 0 to d when the axis leaves the deadzone. Instead // we want to increase the gradient of the line so that it goes from 0 to 1 // over the range d to 1. So instead of having y = x, the equation of the // line becomes // // y = x / (1-d) - d / (1-d) = (x - d) / (1 - d) // // for positive values, and // // y = x / (1-d) + d / (1-d) = (x + d) / (1 - d) // // for negative values. val = (val - signum(val) * d) / (1.0f - d); } } return val; } } } // Qt3DInput QT_END_NAMESPACE