1 | // Copyright (C) 2015 Klaralvdalens Datakonsult AB (KDAB). |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #include "updateaxisactionjob_p.h" |
5 | #include <Qt3DCore/private/qaspectmanager_p.h> |
6 | #include <Qt3DInput/qaction.h> |
7 | #include <Qt3DInput/qaxis.h> |
8 | #include <Qt3DInput/private/qaction_p.h> |
9 | #include <Qt3DInput/private/qaxis_p.h> |
10 | #include <Qt3DInput/private/inputhandler_p.h> |
11 | #include <Qt3DInput/private/inputmanagers_p.h> |
12 | #include <Qt3DInput/private/job_common_p.h> |
13 | |
14 | QT_BEGIN_NAMESPACE |
15 | |
16 | namespace Qt3DInput { |
17 | |
18 | namespace Input { |
19 | |
20 | class UpdateAxisActionJobPrivate : public Qt3DCore::QAspectJobPrivate |
21 | { |
22 | public: |
23 | UpdateAxisActionJobPrivate() { } |
24 | ~UpdateAxisActionJobPrivate() override { } |
25 | |
26 | void postFrame(Qt3DCore::QAspectManager *manager) override; |
27 | |
28 | QList<QPair<Qt3DCore::QNodeId, bool>> m_triggeredActions; |
29 | QList<QPair<Qt3DCore::QNodeId, float>> m_triggeredAxis; |
30 | }; |
31 | |
32 | UpdateAxisActionJob::UpdateAxisActionJob(qint64 currentTime, InputHandler *handler, HLogicalDevice handle) |
33 | : Qt3DCore::QAspectJob(*new UpdateAxisActionJobPrivate()) |
34 | , m_currentTime(currentTime) |
35 | , m_handler(handler) |
36 | , m_handle(handle) |
37 | { |
38 | SET_JOB_RUN_STAT_TYPE(this, JobTypes::UpdateAxisAction, 0) |
39 | } |
40 | |
41 | void UpdateAxisActionJob::run() |
42 | { |
43 | // Note: we assume axis/action are not really shared: |
44 | // there's no benefit in sharing those when it comes to computing |
45 | LogicalDevice *device = m_handler->logicalDeviceManager()->data(handle: m_handle); |
46 | |
47 | if (!device->isEnabled()) |
48 | return; |
49 | |
50 | updateAction(device); |
51 | updateAxis(device); |
52 | } |
53 | |
54 | void UpdateAxisActionJob::updateAction(LogicalDevice *device) |
55 | { |
56 | Q_D(UpdateAxisActionJob); |
57 | const auto actionIds = device->actions(); |
58 | d->m_triggeredActions.reserve(asize: actionIds.size()); |
59 | |
60 | for (const Qt3DCore::QNodeId &actionId : actionIds) { |
61 | bool actionTriggered = false; |
62 | Action *action = m_handler->actionManager()->lookupResource(id: actionId); |
63 | |
64 | const auto actionInputIds = action->inputs(); |
65 | for (const Qt3DCore::QNodeId &actionInputId : actionInputIds) |
66 | actionTriggered |= processActionInput(actionInputId); |
67 | |
68 | if (action->isEnabled() && (action->actionTriggered() != actionTriggered)) { |
69 | action->setActionTriggered(actionTriggered); |
70 | d->m_triggeredActions.push_back(t: {actionId, actionTriggered}); |
71 | } |
72 | } |
73 | } |
74 | |
75 | bool UpdateAxisActionJob::processActionInput(const Qt3DCore::QNodeId actionInputId) |
76 | { |
77 | AbstractActionInput *actionInput = m_handler->lookupActionInput(id: actionInputId); |
78 | Q_ASSERT(actionInput); |
79 | return actionInput->process(inputHandler: m_handler, currentTime: m_currentTime); |
80 | } |
81 | |
82 | void UpdateAxisActionJob::updateAxis(LogicalDevice *device) |
83 | { |
84 | Q_D(UpdateAxisActionJob); |
85 | const auto axisIds = device->axes(); |
86 | d->m_triggeredAxis.reserve(asize: axisIds.size()); |
87 | |
88 | for (const Qt3DCore::QNodeId &axisId : axisIds) { |
89 | Axis *axis = m_handler->axisManager()->lookupResource(id: axisId); |
90 | float axisValue = 0.0f; |
91 | |
92 | const auto axisInputIds = axis->inputs(); |
93 | for (const Qt3DCore::QNodeId &axisInputId : axisInputIds) |
94 | axisValue += processAxisInput(axisInputId); |
95 | |
96 | // Clamp the axisValue -1/1 |
97 | axisValue = qMin(a: 1.0f, b: qMax(a: axisValue, b: -1.0f)); |
98 | |
99 | if (axis->isEnabled() && !qFuzzyCompare(p1: axisValue, p2: axis->axisValue())) { |
100 | axis->setAxisValue(axisValue); |
101 | d->m_triggeredAxis.push_back(t: {axisId, axisValue}); |
102 | } |
103 | } |
104 | } |
105 | |
106 | float UpdateAxisActionJob::processAxisInput(const Qt3DCore::QNodeId axisInputId) |
107 | { |
108 | AnalogAxisInput *analogInput = m_handler->analogAxisInputManager()->lookupResource(id: axisInputId); |
109 | if (analogInput) |
110 | return analogInput->process(inputHandler: m_handler, currentTime: m_currentTime); |
111 | |
112 | ButtonAxisInput *buttonInput = m_handler->buttonAxisInputManager()->lookupResource(id: axisInputId); |
113 | if (buttonInput) |
114 | return buttonInput->process(inputHandler: m_handler, currentTime: m_currentTime); |
115 | |
116 | Q_UNREACHABLE_RETURN(0.0f); |
117 | } |
118 | |
119 | void UpdateAxisActionJobPrivate::postFrame(Qt3DCore::QAspectManager *manager) |
120 | { |
121 | for (const auto &data: std::as_const(t&: m_triggeredActions)) { |
122 | Qt3DInput::QAction *action = qobject_cast<Qt3DInput::QAction *>(object: manager->lookupNode(id: data.first)); |
123 | if (!action) |
124 | continue; |
125 | |
126 | Qt3DInput::QActionPrivate *daction = static_cast<Qt3DInput::QActionPrivate *>(Qt3DCore::QNodePrivate::get(q: action)); |
127 | daction->setActive(data.second); |
128 | } |
129 | |
130 | for (const auto &data: std::as_const(t&: m_triggeredAxis)) { |
131 | Qt3DInput::QAxis *axis = qobject_cast<Qt3DInput::QAxis *>(object: manager->lookupNode(id: data.first)); |
132 | if (!axis) |
133 | continue; |
134 | |
135 | Qt3DInput::QAxisPrivate *daxis = static_cast<Qt3DInput::QAxisPrivate *>(Qt3DCore::QNodePrivate::get(q: axis)); |
136 | daxis->setValue(data.second); |
137 | } |
138 | |
139 | m_triggeredActions.clear(); |
140 | m_triggeredAxis.clear(); |
141 | } |
142 | |
143 | } // Input |
144 | |
145 | } // Qt3DInput |
146 | |
147 | QT_END_NAMESPACE |
148 | |