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
15QT_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
30QQuick3DXrController::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
46QQuick3DXrController::Controller QQuick3DXrController::controller() const
47{
48 return m_controller;
49}
50
51void 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
78QQuick3DXrHandInput *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
102QQuick3DXrController::HandPoseSpace QQuick3DXrController::poseSpace() const
103{
104 return m_poseSpace;
105}
106
107void 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
126QVector3D 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*/
142QList<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*/
158QList<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
175bool QQuick3DXrController::isActive() const
176{
177 return m_isActive;
178}
179
180QtQuick3DXr::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
193QtQuick3DXr::HandPoseSpace QtQuick3DXr::pose_cast(QQuick3DXrController::HandPoseSpace poseSpace)
194{
195 return static_cast<QtQuick3DXr::HandPoseSpace>(poseSpace);
196}
197
198QT_END_NAMESPACE
199
200
201

source code of qtquick3d/src/xr/quick3dxr/qquick3dxrcontroller.cpp