1 | // Copyright (C) 2024 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #include "qquick3dxrcontroller_p.h" |
5 | |
6 | #include "qquick3dxrinputmanager_p.h" |
7 | |
8 | #if !defined(Q_OS_VISIONOS) |
9 | # include "openxr/qopenxrinputmanager_p.h" |
10 | #endif |
11 | |
12 | #include "qquick3dxrview_p.h" |
13 | #include "qquick3dxractionmapper_p.h" |
14 | |
15 | QT_BEGIN_NAMESPACE |
16 | |
17 | /*! |
18 | \qmltype XrController |
19 | \inherits Node |
20 | \inqmlmodule QtQuick3D.Xr |
21 | \brief A tracked spatial node that tracks the position and orientation of an input controller. |
22 | |
23 | The XrController is a tracked spatial node that tracks the position and orientation of an input controller. |
24 | |
25 | Since this is a tracked node, its spatial properties should be considered read-only. |
26 | |
27 | \sa XrInputAction |
28 | */ |
29 | |
30 | QQuick3DXrController::QQuick3DXrController() |
31 | { |
32 | m_inputManager = QQuick3DXrInputManager::instance(); |
33 | } |
34 | |
35 | /*! |
36 | \qmlproperty enumeration QtQuick3D.Xr::XrController::controller |
37 | |
38 | Specifies the controller to track. |
39 | |
40 | It can be one of: |
41 | \value XrController.ControllerNone |
42 | \value XrController.ControllerLeft |
43 | \value XrController.ControllerRight |
44 | */ |
45 | |
46 | QQuick3DXrController::Controller QQuick3DXrController::controller() const |
47 | { |
48 | return m_controller; |
49 | } |
50 | |
51 | void QQuick3DXrController::setController(QQuick3DXrController::Controller newController) |
52 | { |
53 | if (m_controller == newController) |
54 | return; |
55 | m_controller = newController; |
56 | emit controllerChanged(); |
57 | |
58 | disconnect(m_isActiveConnection); |
59 | |
60 | QQuick3DXrInputManager::instance()->registerController(controller: this); |
61 | auto *input = handInput(); |
62 | if (input) { |
63 | setVisible(input->isActive()); // ### position not set yet, so might show up briefly in wrong location |
64 | |
65 | m_isActiveConnection = connect(sender: input, signal: &QQuick3DXrHandInput::isActiveChanged, context: this, slot: [this, input]{ |
66 | setVisible(input->isActive()); |
67 | }); |
68 | |
69 | connect(sender: input, signal: &QQuick3DXrHandInput::pokePositionChanged, context: this, slot: &QQuick3DXrController::pokePositionChanged); |
70 | connect(sender: input, signal: &QQuick3DXrHandInput::jointPositionsChanged, context: this, slot: &QQuick3DXrController::jointPositionsChanged); |
71 | connect(sender: input, signal: &QQuick3DXrHandInput::jointRotationsChanged, context: this, slot: &QQuick3DXrController::jointRotationsChanged); |
72 | connect(sender: input, signal: &QQuick3DXrHandInput::jointDataUpdated, context: this, slot: &QQuick3DXrController::jointDataUpdated); |
73 | } else { |
74 | setVisible(false); |
75 | } |
76 | } |
77 | |
78 | QQuick3DXrHandInput *QQuick3DXrController::handInput() const |
79 | { |
80 | if (m_inputManager && m_inputManager->isValid()) { |
81 | if (m_controller == ControllerRight) |
82 | return m_inputManager->rightHandInput(); |
83 | else if (m_controller == ControllerLeft) |
84 | return m_inputManager->leftHandInput(); |
85 | } |
86 | |
87 | return nullptr; |
88 | } |
89 | |
90 | /*! |
91 | \qmlproperty enumeration XrController::poseSpace |
92 | |
93 | Specifies the pose of the controller to track, that is, the orientation and |
94 | position relative to the physical controller. |
95 | |
96 | It can be one of: |
97 | \value XrController.AimPose Used when aiming at something, such as with \l XrVirtualMouse. |
98 | \value XrController.GripPose Used when grabbing something, such as when holding an object in the hand. |
99 | \default XrController.AimPose |
100 | */ |
101 | |
102 | QQuick3DXrController::HandPoseSpace QQuick3DXrController::poseSpace() const |
103 | { |
104 | return m_poseSpace; |
105 | } |
106 | |
107 | void QQuick3DXrController::setPoseSpace(HandPoseSpace newPoseSpace) |
108 | { |
109 | if (m_poseSpace == newPoseSpace) |
110 | return; |
111 | m_poseSpace = newPoseSpace; |
112 | QQuick3DXrInputManager::instance()->registerController(controller: this); |
113 | emit poseSpaceChanged(); |
114 | } |
115 | |
116 | /*! |
117 | \qmlproperty vector3d XrController::pokePosition |
118 | |
119 | \readonly |
120 | This property holds the position to be used for touch interactions. |
121 | Typically, it will be the tip of the index finger when tracking a hand. |
122 | |
123 | \sa XrView::processTouch, XrView::setTouchpoint |
124 | */ |
125 | |
126 | QVector3D QQuick3DXrController::pokePosition() const |
127 | { |
128 | auto *input = handInput(); |
129 | if (input) |
130 | return input->pokePosition(); |
131 | return {}; |
132 | } |
133 | |
134 | /*! |
135 | \qmlproperty list<vector3d> XrController::jointPositions |
136 | |
137 | \readonly |
138 | When using hand tracking, this property holds the positions of all the bones in the hand. |
139 | |
140 | \sa jointRotations, XrHandModel |
141 | */ |
142 | QList<QVector3D> QQuick3DXrController::jointPositions() const |
143 | { |
144 | auto *input = handInput(); |
145 | if (input) |
146 | return input->jointPositions(); |
147 | return {}; |
148 | } |
149 | |
150 | /*! |
151 | \qmlproperty list<quaternion> XrController::jointRotations |
152 | |
153 | \readonly |
154 | When using hand tracking, this property holds the orientation of all the bones in the hand. |
155 | |
156 | \sa jointPositions, XrHandModel |
157 | */ |
158 | QList<QQuaternion> QQuick3DXrController::jointRotations() const |
159 | { |
160 | auto *input = handInput(); |
161 | if (input) |
162 | return input->jointRotations(); |
163 | return {}; |
164 | } |
165 | |
166 | /*! |
167 | \qmlproperty bool XrController::isActive |
168 | \brief Indicates whether the controller is providing input. |
169 | |
170 | \readonly |
171 | This property is true if the corresponding physical controller is present |
172 | and tracking. |
173 | */ |
174 | |
175 | bool QQuick3DXrController::isActive() const |
176 | { |
177 | return m_isActive; |
178 | } |
179 | |
180 | QtQuick3DXr::Hand QtQuick3DXr::handForController(QQuick3DXrController::Controller controller) |
181 | { |
182 | QSSG_ASSERT(controller != QQuick3DXrController::ControllerNone, return QQuick3DXrInputManager::Hand::RightHand); |
183 | switch (controller) { |
184 | case QQuick3DXrController::ControllerLeft: |
185 | return QQuick3DXrInputManager::Hand::LeftHand; |
186 | case QQuick3DXrController::ControllerRight: |
187 | return QQuick3DXrInputManager::Hand::RightHand; |
188 | default: |
189 | Q_UNREACHABLE(); |
190 | } |
191 | } |
192 | |
193 | QtQuick3DXr::HandPoseSpace QtQuick3DXr::pose_cast(QQuick3DXrController::HandPoseSpace poseSpace) |
194 | { |
195 | return static_cast<QtQuick3DXr::HandPoseSpace>(poseSpace); |
196 | } |
197 | |
198 | QT_END_NAMESPACE |
199 | |
200 | |
201 | |