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