Overte C++ Documentation
OpenXrInputPlugin.h
1 //
2 // Overte OpenXR Plugin
3 //
4 // Copyright 2024 Lubosz Sarnecki
5 // Copyright 2024 Overte e.V.
6 //
7 // SPDX-License-Identifier: Apache-2.0
8 //
9 
10 #pragma once
11 
12 #include "plugins/InputPlugin.h"
13 #include "controllers/InputDevice.h"
14 #include "OpenXrContext.h"
15 
16 #define HAND_COUNT 2
17 
18 // most of the time this should be less than 16, but some devices like
19 // SlimeVR report xdev trackers for the joints of a simulated skeleton
20 #define MAX_TRACKER_COUNT 64
21 
22 class OpenXrInputPlugin : public InputPlugin {
23  Q_OBJECT
24 public:
25  OpenXrInputPlugin(std::shared_ptr<OpenXrContext> c);
26  bool isSupported() const override;
27  const QString getName() const override { return "OpenXR"; }
28 
29  bool isHandController() const override { return true; }
30  bool configurable() override { return true; }
31 
32  QString configurationLayout() override;
33  void setConfigurationSettings(const QJsonObject configurationSettings) override;
34  QJsonObject configurationSettings() override;
35  void calibrate() override;
36  bool uncalibrate() override;
37  bool isHeadController() const override { return true; }
38 
39  bool activate() override;
40  void deactivate() override;
41 
42  QString getDeviceName() override { return _context.get()->_systemName; }
43 
44  void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
45 
46  void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
47 
48  virtual void saveSettings() const override;
49  virtual void loadSettings() override;
50 
51 private:
52  class Action {
53  public:
54  Action(std::shared_ptr<OpenXrContext> c, const std::string& id, const std::string &friendlyName, XrActionType type) {
55  _context = c;
56  _id = id;
57  _friendlyName = friendlyName;
58  _type = type;
59  }
60 
61  bool init(XrActionSet actionSet);
62  std::vector<XrActionSuggestedBinding> getBindings();
63  XrActionStateFloat getFloat();
64  XrActionStateVector2f getVector2f();
65  XrActionStateBoolean getBool();
66  XrSpaceLocation getPose();
67  bool isPoseActive();
68  bool applyHaptic(XrDuration duration, float frequency, float amplitude);
69 
70  XrAction _action = XR_NULL_HANDLE;
71  private:
72  bool createPoseSpaces();
73  std::shared_ptr<OpenXrContext> _context;
74  std::string _id, _friendlyName;
75  XrActionType _type;
76  XrSpace _poseSpace = XR_NULL_HANDLE;
77  };
78 
79  struct XDevTracker {
80  XrSpace space;
81  XrPosef offset_pose;
82  std::optional<controller::StandardPoseChannel> pose_channel;
83  XrXDevPropertiesMNDX properties;
84  };
85  void guessXDevRoles(std::unordered_map<XrXDevIdMNDX, XDevTracker>& trackers);
86 
87  class InputDevice : public controller::InputDevice {
88  public:
89  InputDevice(std::shared_ptr<OpenXrContext> c);
90 
91  private:
92  controller::Input::NamedVector getAvailableInputs() const override;
93  QString getDefaultMappingConfig() const override;
94  void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
95  void focusOutEvent() override;
96  bool triggerHapticPulse(float strength, float duration, uint16_t index) override;
97 
98  void setupControllerFlags();
99  void getHandTrackingInputs(int index, const mat4& sensorToAvatar);
100 
101  void updateBodyFromViveTrackers(const mat4& sensorToAvatar);
102  void updateBodyFromXDevSpaces(const mat4& sensorToAvatar);
103  void calibratePucks(const controller::InputCalibrationData& inputCalibrationData);
104 
105  mutable std::recursive_mutex _lock;
106  template <typename F>
107  void withLock(F&& f) {
108  std::unique_lock<std::recursive_mutex> locker(_lock);
109  f();
110  }
111 
112  friend class OpenXrInputPlugin;
113 
114  uint32_t _trackedControllers = 0;
115  XrActionSet _actionSet;
116  std::map<std::string, std::shared_ptr<Action>> _actions;
117  std::shared_ptr<OpenXrContext> _context;
118  bool _actionsInitialized = false;
119 
120  std::unordered_map<XrXDevIdMNDX, XDevTracker> _xdev;
121  std::unordered_map<controller::StandardPoseChannel, controller::Pose> _trackerCalibrations;
122  bool _wantsCalibrate = false;
123 
124  XrHandTrackerEXT _handTracker[2] = {XR_NULL_HANDLE, XR_NULL_HANDLE};
125 
126  bool _hapticsEnabled = true;
127 
128  bool initActions();
129  bool initBindings(const std::string& profileName, const std::map<std::string, std::string>& actionsToBind);
130  };
131 
132  bool _registeredWithInputMapper = false;
133  std::shared_ptr<OpenXrContext> _context;
134  std::shared_ptr<InputDevice> _inputDevice;
135 };