Overte C++ Documentation
ViveControllerManager.h
1 //
2 // ViveControllerManager.h
3 //
4 // Created by Sam Gondelman on 6/29/15.
5 // Copyright 2013 High Fidelity, Inc.
6 // Copyright 2020 Vircadia contributors.
7 //
8 // Distributed under the Apache License, Version 2.0.
9 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
10 //
11 
12 #ifndef hifi__ViveControllerManager
13 #define hifi__ViveControllerManager
14 
15 #include <QObject>
16 #include <unordered_set>
17 #include <vector>
18 #include <map>
19 #include <utility>
20 
21 #include <GLMHelpers.h>
22 #include <graphics/Geometry.h>
23 #include <gpu/Texture.h>
24 #include <controllers/InputDevice.h>
25 #include <plugins/InputPlugin.h>
26 #include "OpenVrHelpers.h"
27 
28 #ifdef Q_OS_WIN
29 // Disabled Vive Pro Eye support, because SRanipal isn't packaged in Conan.
30 // #define VIVE_PRO_EYE
31 #endif
32 
33 using PuckPosePair = std::pair<uint32_t, controller::Pose>;
34 
35 namespace vr {
36  class IVRSystem;
37 }
38 
39 
40 #ifdef VIVE_PRO_EYE
41 class ViveProEyeReadThread;
42 
43 class EyeDataBuffer {
44 public:
45  int getEyeDataResult { 0 };
46  bool leftDirectionValid { false };
47  bool rightDirectionValid { false };
48  bool leftOpennessValid { false };
49  bool rightOpennessValid { false };
50  glm::vec3 leftEyeGaze;
51  glm::vec3 rightEyeGaze;
52  float leftEyeOpenness { 0.0f };
53  float rightEyeOpenness { 0.0f };
54 };
55 #endif
56 
57 
58 class ViveControllerManager : public InputPlugin {
59  Q_OBJECT
60 public:
61  // Plugin functions
62  bool isSupported() const override;
63  const QString getName() const override { return NAME; }
64 
65  bool isHandController() const override { return true; }
66  bool configurable() override { return true; }
67 
68  QString configurationLayout() override;
69  void setConfigurationSettings(const QJsonObject configurationSettings) override;
70  QJsonObject configurationSettings() override;
71  void calibrate() override;
72  bool uncalibrate() override;
73  bool isHeadController() const override { return true; }
74  bool isHeadControllerMounted() const;
75 
76 #ifdef VIVE_PRO_EYE
77  void enableGestureDetection();
78  void disableGestureDetection();
79 #endif
80 
81  bool activate() override;
82  void deactivate() override;
83 
84  QString getDeviceName() override { return QString::fromStdString(_inputDevice->_headsetName); }
85 
86  void pluginFocusOutEvent() override { _inputDevice->focusOutEvent(); }
87 #ifdef VIVE_PRO_EYE
88  void invalidateEyeInputs();
89  void updateEyeTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData);
90  void updateCameraHandTracker(float deltaTime, const controller::InputCalibrationData& inputCalibrationData);
91 #endif
92  void pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
93 
94  virtual void saveSettings() const override;
95  virtual void loadSettings() override;
96 
97  enum class OutOfRangeDataStrategy {
98  None,
99  Freeze,
100  Drop,
101  DropAfterDelay
102  };
103 
104 private:
105  class InputDevice : public controller::InputDevice {
106  public:
107  InputDevice(vr::IVRSystem*& system);
108  bool isHeadControllerMounted() const { return _overrideHead; }
109  float getControllerStickHysteresisTime() { return _filteredLeftStick.getHysteresisPeriod(); };
110  // Sets hysteresis period for the filter. This is a workaround needed only for Vive wands which use value 0.2f.
111  void setControllerStickHysteresisTime(float value);
112 
113  private:
114  // Device functions
115  controller::Input::NamedVector getAvailableInputs() const override;
116  QString getDefaultMappingConfig() const override;
117  void update(float deltaTime, const controller::InputCalibrationData& inputCalibrationData) override;
118  void focusOutEvent() override;
119  bool triggerHapticPulse(float strength, float duration, uint16_t index) override;
120  void hapticsHelper(float deltaTime, bool leftHand);
121  void calibrateOrUncalibrate(const controller::InputCalibrationData& inputCalibration);
122  void calibrate(const controller::InputCalibrationData& inputCalibration);
123  void uncalibrate();
124  void sendUserActivityData(QString activity);
125  void configureCalibrationSettings(const QJsonObject configurationSettings);
126  QJsonObject configurationSettings();
127  controller::Pose addOffsetToPuckPose(const controller::InputCalibrationData& inputCalibration, int joint) const;
128  glm::mat4 calculateDefaultToReferenceForHeadPuck(const controller::InputCalibrationData& inputCalibration);
129  glm::mat4 calculateDefaultToReferenceForHmd(const controller::InputCalibrationData& inputCalibration);
130  void updateCalibratedLimbs(const controller::InputCalibrationData& inputCalibration);
131  bool checkForCalibrationEvent();
132  void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand);
133  void handleHmd(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData);
134  void handleTrackedObject(uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData);
135  void handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool touched, bool isLeftHand);
136  void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand);
137  void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
138  const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand);
139  void handleHeadPoseEvent(const controller::InputCalibrationData& inputCalibrationData, const mat4& mat, const vec3& linearVelocity,
140  const vec3& angularVelocity);
141  void partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int xPseudoButton, int yPseudoButton);
142  void printDeviceTrackingResultChange(uint32_t deviceIndex);
143  void setConfigFromString(const QString& value);
144  bool configureHead(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
145  bool configureHands(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
146  bool configureBody(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
147  void calibrateLeftHand(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair);
148  void calibrateRightHand(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& handPair);
149  void calibrateFeet(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
150  void calibrateFoot(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration, PuckPosePair& footPair, bool isLeftFoot);
151  void calibrateHips(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
152  void calibrateChest(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
153  void calibrateShoulders(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration,
154  int firstShoulderIndex, int secondShoulderIndex);
155  void calibrateHead(const glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
156  void calibrateFromHandController(const controller::InputCalibrationData& inputCalibrationData);
157  void calibrateFromUI(const controller::InputCalibrationData& inputCalibrationData);
158  void emitCalibrationStatus();
159  void calibrateNextFrame();
160 
161  class FilteredStick {
162  public:
163  float getHysteresisPeriod() { return _hysteresis_period; };
164  // Sets hysteresis period for the filter. This is a workaround needed only for Vive wands which use value 0.2f.
165  void setHysteresisPeriod(float value) { _hysteresis_period = value; };
166  glm::vec2 process(float deltaTime, const glm::vec2& stick) {
167  // Use a timer to prevent the stick going back to zero.
168  // This to work around the noisy touchpad that will flash back to zero briefly
169  if (glm::length(stick) == 0.0f) {
170  if (_timer <= 0.0f) {
171  return glm::vec2(0.0f, 0.0f);
172  } else {
173  _timer -= deltaTime;
174  return _stick;
175  }
176  } else {
177  _timer = _hysteresis_period;
178  _stick = stick;
179  return stick;
180  }
181  }
182  protected:
183  float _hysteresis_period{ 0.0f };
184  float _timer { 0.0f };
185  glm::vec2 _stick { 0.0f, 0.0f };
186  };
187  enum class Config {
188  None,
189  Feet,
190  FeetAndHips,
191  FeetHipsAndChest,
192  FeetHipsAndShoulders,
193  FeetHipsChestAndShoulders
194  };
195 
196  enum class HeadConfig {
197  HMD,
198  Puck
199  };
200 
201  enum class HandConfig {
202  HandController,
203  Pucks
204  };
205 
206  Config _config { Config::None };
207  Config _preferedConfig { Config::None };
208  HeadConfig _headConfig { HeadConfig::HMD };
209  HandConfig _handConfig { HandConfig::HandController };
210  FilteredStick _filteredLeftStick;
211  FilteredStick _filteredRightStick;
212  std::string _headsetName {""};
213  OutOfRangeDataStrategy _outOfRangeDataStrategy { OutOfRangeDataStrategy::Drop };
214 
215  std::vector<PuckPosePair> _validTrackedObjects;
216  std::map<uint32_t, glm::mat4> _pucksPostOffset;
217  std::map<uint32_t, glm::mat4> _pucksPreOffset;
218  std::map<int, uint32_t> _jointToPuckMap;
219  std::map<Config, QString> _configStringMap;
220  PoseData _lastSimPoseData;
221  // perform an action when the InputDevice mutex is acquired.
222  using Locker = std::unique_lock<std::recursive_mutex>;
223  template <typename F>
224  void withLock(F&& f) { Locker locker(_lock); f(); }
225 
226  int _trackedControllers { 0 };
227  vr::IVRSystem*& _system;
228  quint64 _timeTilCalibration { 0 };
229  float _leftHapticStrength { 0.0f };
230  float _leftHapticDuration { 0.0f };
231  float _rightHapticStrength { 0.0f };
232  float _rightHapticDuration { 0.0f };
233  float _headPuckYOffset { -0.05f };
234  float _headPuckZOffset { -0.05f };
235  float _handPuckYOffset { 0.0f };
236  float _handPuckZOffset { 0.0f };
237  float _armCircumference { 0.33f };
238  float _shoulderWidth { 0.48f };
239  bool _triggersPressedHandled { false };
240  bool _calibrated { false };
241  bool _timeTilCalibrationSet { false };
242  bool _calibrate { false };
243  bool _overrideHead { false };
244  bool _overrideHands { false };
245  mutable std::recursive_mutex _lock;
246 
247  bool _hmdTrackingEnabled { true };
248 
249  std::map<uint32_t, uint64_t> _simDataRunningOkTimestampMap;
250 
251  QString configToString(Config config);
252  friend class ViveControllerManager;
253  };
254 
255  void renderHand(const controller::Pose& pose, gpu::Batch& batch, int sign);
256  bool isDesktopMode();
257  bool _registeredWithInputMapper { false };
258  bool _modelLoaded { false };
259 
260  bool _desktopMode { false };
261  bool _hmdDesktopTracking { false };
262 
263  graphics::Geometry _modelGeometry;
264  gpu::TexturePointer _texture;
265 
266  int _leftHandRenderID { 0 };
267  int _rightHandRenderID { 0 };
268 
269  vr::IVRSystem* _system { nullptr };
270  std::shared_ptr<InputDevice> _inputDevice { std::make_shared<InputDevice>(_system) };
271 
272  bool _eyeTrackingEnabled{ false };
273 
274 #ifdef VIVE_PRO_EYE
275  bool _viveProEye { false };
276  std::shared_ptr<ViveProEyeReadThread> _viveProEyeReadThread;
277  EyeDataBuffer _prevEyeData;
278 
279  bool _viveCameraHandTracker { false };
280  int _lastHandTrackerFrameIndex { -1 };
281 
282  const static int NUMBER_OF_HAND_TRACKER_SMOOTHING_FRAMES { 6 };
283  const static int NUMBER_OF_HAND_POINTS { 21 };
284  glm::vec3 _handPoints[NUMBER_OF_HAND_TRACKER_SMOOTHING_FRAMES][2][NUMBER_OF_HAND_POINTS]; // 2 for number of hands
285  glm::vec3 getRollingAverageHandPoint(int handIndex, int pointIndex) const;
286  controller::Pose trackedHandDataToPose(int hand, const glm::vec3& palmFacing,
287  int nearHandPositionIndex, int farHandPositionIndex);
288  void trackFinger(int hand, int jointIndex1, int jointIndex2, int jointIndex3, int jointIndex4,
289  controller::StandardPoseChannel joint1, controller::StandardPoseChannel joint2,
290  controller::StandardPoseChannel joint3, controller::StandardPoseChannel joint4);
291 #endif
292 
293  static const char* NAME;
294 };
295 
296 #endif // hifi__ViveControllerManager