├── .github ├── FUNDING.yml ├── img_01.png ├── img_02.gif └── img_03.png ├── .gitignore ├── .gitmodules ├── LICENSE.txt ├── README.md ├── driver.vrdrivermanifest ├── driver_leap.sln ├── driver_leap ├── Core │ ├── CDriverConfig.cpp │ ├── CDriverConfig.h │ ├── CServerDriver.cpp │ ├── CServerDriver.h │ ├── CVREventsPoller.cpp │ └── CVREventsPoller.h ├── Devices │ ├── CLeapStation.cpp │ ├── CLeapStation.h │ └── Controller │ │ ├── CControllerButton.cpp │ │ ├── CControllerButton.h │ │ ├── CControllerInput.cpp │ │ ├── CControllerInput.h │ │ ├── CLeapIndexController.cpp │ │ └── CLeapIndexController.h ├── Leap │ ├── CLeapFrame.cpp │ ├── CLeapFrame.h │ ├── CLeapHand.cpp │ ├── CLeapHand.h │ ├── CLeapPoller.cpp │ └── CLeapPoller.h ├── Utils │ ├── Utils.cpp │ └── Utils.h ├── dllmain.cpp ├── driver_leap.vcxproj ├── driver_leap.vcxproj.filters ├── stdafx.cpp └── stdafx.h ├── leap_control ├── Core │ ├── CCore.cpp │ └── CCore.h ├── Leap │ ├── CLeapPoller.cpp │ └── CLeapPoller.h ├── Managers │ ├── CLeapManager.cpp │ ├── CLeapManager.h │ ├── COpenGLManager.cpp │ ├── COpenGLManager.h │ ├── COverlayManager.cpp │ ├── COverlayManager.h │ ├── CSettingsManager.cpp │ ├── CSettingsManager.h │ ├── CVRManager.cpp │ └── CVRManager.h ├── Overlay │ ├── CCursorOverlay.cpp │ ├── CCursorOverlay.h │ ├── CHandOverlay.cpp │ ├── CHandOverlay.h │ ├── CRenderTarget.cpp │ └── CRenderTarget.h ├── Resources │ ├── leap_control.ico │ ├── leap_control.qrc │ └── leap_control.rc ├── Ui │ ├── leap_control.cpp │ ├── leap_control.h │ ├── leap_control.ui │ ├── vr_overlay.cpp │ ├── vr_overlay.h │ └── vr_overlay.ui ├── Utils │ ├── CButton.cpp │ ├── CButton.h │ ├── Utils.cpp │ └── Utils.h ├── leap_control.vcxproj ├── leap_control.vcxproj.filters ├── main.cpp ├── stdafx.cpp └── stdafx.h ├── resources ├── icons │ ├── base_status_ready.png │ ├── base_status_ready@2x.png │ ├── base_status_searching.png │ └── base_status_searching@2x.png ├── rendermodels │ └── leap_motion_1_0 │ │ ├── base_diff.png │ │ ├── leap_motion_1_0.json │ │ ├── leap_motion_1_0.mtl │ │ ├── leap_motion_1_0.obj │ │ └── thumbnail_leap.png ├── settings.xml └── textures │ └── cursor.png └── vendor ├── JSL └── LeapSDK /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: sdraw_ 2 | -------------------------------------------------------------------------------- /.github/img_01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/.github/img_01.png -------------------------------------------------------------------------------- /.github/img_02.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/.github/img_02.gif -------------------------------------------------------------------------------- /.github/img_03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/.github/img_03.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Debug 2 | Release 3 | *.user 4 | ipch 5 | *.sdf 6 | .vs 7 | *.opensdf 8 | *.opendb 9 | *.VC.db 10 | bin -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "vendor/glm"] 2 | path = vendor/glm 3 | url = https://github.com/g-truc/glm.git 4 | [submodule "vendor/pugixml"] 5 | path = vendor/pugixml 6 | url = https://github.com/zeux/pugixml.git 7 | [submodule "vendor/openvr"] 8 | path = vendor/openvr 9 | url = https://github.com/ValveSoftware/openvr.git 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 SDraw 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Driver Leap [![Release](http://img.shields.io/github/release/SDraw/driver_leap.svg)](../../releases/latest) 2 | Self-sustainable fork of SteamVR driver for Leap Motion controller with updated vendor libraries 3 | 4 | [![](./.github/img_01.png)](https://www.youtube.com/watch?v=RdGnCV2g_oE) 5 | 6 | ## Installation (for users) 7 | * Install [latest Ultraleap Gemini](https://developer.leapmotion.com/tracking-software-download) 8 | * Extract [latest release archive](../../releases/latest) to `/drivers` 9 | * Add line in section `steamvr` of `/config/steamvr.vrsettings` file: 10 | ```JSON 11 | "activateMultipleDrivers": true, 12 | ``` 13 | 14 | ## Usage 15 | ### Settings 16 | Settings are configurated with Leap Control utility application that is launched upon SteamVR start. 17 | ![](./.github/img_02.gif) 18 | 19 | Alternatively, you can edit manually `resources/settings.xml` configuration file. 20 | Settings are saved upon SteamVR exit, or manually with `Save` button at top-right corner. 21 | Leap Control can be minimized to tray icon and shown again by double-clicking tray icon. 22 | 23 | ### Gestures 24 | List of hands gestures that correspond to controller original input: 25 | * **Grip:** bending of middle, ring and pinky fingers 26 | * **Trigger:** bending of index finger or pinch gesture (configurable as `Input - Trigger mode` setting in utility app) 27 | 28 | By default other buttons/inputs are available through hand overlays or connected controllers (by enabling corresponding option in `General` tab of utility app). 29 | Currenty supported controllers: 30 | * Nintendo Joy-Cons controllers: 31 | * ![](./.github/img_03.png) 32 | * Sony Playstation DualShock 4: 33 | * (TBA) 34 | 35 | ## Notes 36 | * If you see only green dots that represent tip of your index fingers, force `leap_control` to launch on dGPU through control panel of your GPU vendor. 37 | * Coordinate system used for offsets and angles is right handed (as in OpenGL). 38 | ![](https://learnopengl.com/img/getting-started/coordinate_systems_right_handed.png) 39 | -------------------------------------------------------------------------------- /driver.vrdrivermanifest: -------------------------------------------------------------------------------- 1 | { 2 | "alwaysActivate": true, 3 | "name" : "leap", 4 | "directory" : "", 5 | "resourceOnly" : false 6 | } 7 | -------------------------------------------------------------------------------- /driver_leap.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.33214.272 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver_leap", "driver_leap\driver_leap.vcxproj", "{52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}" 7 | EndProject 8 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "leap_control", "leap_control\leap_control.vcxproj", "{C3C7197E-4752-4680-9AAB-78120ED43093}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|x64 = Debug|x64 13 | Release|x64 = Release|x64 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Debug|x64.ActiveCfg = Debug|x64 17 | {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Debug|x64.Build.0 = Debug|x64 18 | {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Release|x64.ActiveCfg = Release|x64 19 | {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Release|x64.Build.0 = Release|x64 20 | {C3C7197E-4752-4680-9AAB-78120ED43093}.Debug|x64.ActiveCfg = Debug|x64 21 | {C3C7197E-4752-4680-9AAB-78120ED43093}.Debug|x64.Build.0 = Debug|x64 22 | {C3C7197E-4752-4680-9AAB-78120ED43093}.Release|x64.ActiveCfg = Release|x64 23 | {C3C7197E-4752-4680-9AAB-78120ED43093}.Release|x64.Build.0 = Release|x64 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | GlobalSection(ExtensibilityGlobals) = postSolution 29 | SolutionGuid = {5B906255-44C8-427C-8F9B-99D222337F78} 30 | EndGlobalSection 31 | EndGlobal 32 | -------------------------------------------------------------------------------- /driver_leap/Core/CDriverConfig.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Core/CDriverConfig.h" 3 | #include "Utils/Utils.h" 4 | 5 | extern std::wstring g_modulePath; 6 | 7 | const std::vector g_settingNames 8 | { 9 | "trackingLevel", 10 | "handsReset", 11 | "useVelocity", 12 | "dashboardSmooth", 13 | "useTriggerGrip", 14 | "triggerMode", 15 | "triggerThreshold", 16 | "gripThreshold", 17 | "pinchLimitMin", 18 | "pinchLimitMax", 19 | "useControllerInput", 20 | "rootOffsetX", 21 | "rootOffsetY", 22 | "rootOffsetZ", 23 | "rootAngleX", 24 | "rootAngleY", 25 | "rootAngleZ" 26 | }; 27 | 28 | int CDriverConfig::ms_trackingLevel = CDriverConfig::TL_Full; 29 | bool CDriverConfig::ms_handsReset = false; 30 | bool CDriverConfig::ms_useVelocity = false; 31 | float CDriverConfig::ms_dashboardSmooth = 1.f; 32 | bool CDriverConfig::ms_useTriggerGrip = true; 33 | int CDriverConfig::ms_triggerMode = CDriverConfig::TM_FingerBend; 34 | float CDriverConfig::ms_triggerThreshold = 0.75f; 35 | float CDriverConfig::ms_gripThreshold = 0.75f; 36 | glm::vec2 CDriverConfig::ms_pinchLimits(0.02f, 0.05f); 37 | bool CDriverConfig::ms_useControllerInput = false; 38 | glm::vec3 CDriverConfig::ms_rootOffset(0.f); 39 | glm::vec3 CDriverConfig::ms_rootAngle(0.f); 40 | 41 | void CDriverConfig::Load() 42 | { 43 | std::wstring l_path(g_modulePath); 44 | l_path.append(L"\\..\\..\\resources\\settings.xml"); 45 | 46 | pugi::xml_document l_document; 47 | if(l_document.load_file(l_path.c_str())) 48 | { 49 | const pugi::xml_node l_root = l_document.child("settings"); 50 | if(l_root) 51 | { 52 | for(pugi::xml_node l_node = l_root.child("setting"); l_node; l_node = l_node.next_sibling("setting")) 53 | { 54 | const pugi::xml_attribute l_attribName = l_node.attribute("name"); 55 | const pugi::xml_attribute l_attribValue = l_node.attribute("value"); 56 | if(l_attribName && l_attribValue) 57 | { 58 | switch(ReadEnumVector(l_attribName.as_string(), g_settingNames)) 59 | { 60 | case CS_TrackingLevel: 61 | ms_trackingLevel = glm::clamp(l_attribValue.as_int(TL_Full), TL_Partial, TL_Full); 62 | break; 63 | 64 | case CS_HandsReset: 65 | ms_handsReset = l_attribValue.as_bool(false); 66 | break; 67 | 68 | case CS_UseVelocity: 69 | ms_useVelocity = l_attribValue.as_bool(false); 70 | break; 71 | 72 | case CS_DashboardSmooth: 73 | ms_dashboardSmooth = glm::clamp(l_attribValue.as_float(1.f), 0.01f, 1.f); 74 | break; 75 | 76 | case CS_UseTriggerGrip: 77 | ms_useTriggerGrip = l_attribValue.as_bool(true); 78 | break; 79 | 80 | case CS_TriggerMode: 81 | ms_triggerMode = glm::clamp(l_attribValue.as_int(TM_FingerBend), TM_FingerBend, TM_Pinch); 82 | break; 83 | 84 | case CS_TriggerThreshold: 85 | ms_triggerThreshold = glm::clamp(l_attribValue.as_float(0.75f), 0.1f, 1.f); 86 | break; 87 | 88 | case CS_GripThreshold: 89 | ms_gripThreshold = glm::clamp(l_attribValue.as_float(0.75f), 0.1f, 1.f); 90 | break; 91 | 92 | case CS_PinchLimitMin: 93 | ms_pinchLimits.x = glm::clamp(l_attribValue.as_float(0.02f), 0.01f, 0.1f); 94 | break; 95 | 96 | case CS_PinchLimitMax: 97 | ms_pinchLimits.y = glm::clamp(l_attribValue.as_float(0.05f), 0.01f, 0.1f); 98 | break; 99 | 100 | case CS_UseControllerInput: 101 | ms_useControllerInput = l_attribValue.as_bool(false); 102 | break; 103 | 104 | case CS_RootOffsetX: 105 | ms_rootOffset.x = glm::clamp(l_attribValue.as_float(0.f), -1.f, 1.f); 106 | break; 107 | 108 | case CS_RootOffsetY: 109 | ms_rootOffset.y = glm::clamp(l_attribValue.as_float(0.f), -1.f, 1.f); 110 | break; 111 | 112 | case CS_RootOffsetZ: 113 | ms_rootOffset.z = glm::clamp(l_attribValue.as_float(0.f), -1.f, 1.f); 114 | break; 115 | 116 | case CS_RootAngleX: 117 | ms_rootAngle.x = glm::clamp(l_attribValue.as_float(0.f), -180.f, 180.f); 118 | break; 119 | 120 | case CS_RootAngleY: 121 | ms_rootAngle.y = glm::clamp(l_attribValue.as_float(0.f), -180.f, 180.f); 122 | break; 123 | 124 | case CS_RootAngleZ: 125 | ms_rootAngle.z = glm::clamp(l_attribValue.as_float(0.f), -180.f, 180.f); 126 | break; 127 | } 128 | } 129 | } 130 | } 131 | } 132 | } 133 | 134 | int CDriverConfig::GetTrackingLevel() 135 | { 136 | return ms_trackingLevel; 137 | } 138 | 139 | bool CDriverConfig::IsHandsResetEnabled() 140 | { 141 | return ms_handsReset; 142 | } 143 | 144 | bool CDriverConfig::IsVelocityUsed() 145 | { 146 | return ms_useVelocity; 147 | } 148 | 149 | float CDriverConfig::GetDashboardSmooth() 150 | { 151 | return ms_dashboardSmooth; 152 | } 153 | 154 | bool CDriverConfig::IsTriggerGripUsed() 155 | { 156 | return ms_useTriggerGrip; 157 | } 158 | 159 | int CDriverConfig::GetTriggerMode() 160 | { 161 | return ms_triggerMode; 162 | } 163 | 164 | float CDriverConfig::GetTriggerThreshold() 165 | { 166 | return ms_triggerThreshold; 167 | } 168 | 169 | float CDriverConfig::GetGripThreshold() 170 | { 171 | return ms_gripThreshold; 172 | } 173 | 174 | const glm::vec2& CDriverConfig::GetPinchLimits() 175 | { 176 | return ms_pinchLimits; 177 | } 178 | 179 | bool CDriverConfig::IsControllerInputUsed() 180 | { 181 | return ms_useControllerInput; 182 | } 183 | 184 | const glm::vec3& CDriverConfig::GetRootOffset() 185 | { 186 | return ms_rootOffset; 187 | } 188 | 189 | const glm::vec3& CDriverConfig::GetRootAngle() 190 | { 191 | return ms_rootAngle; 192 | } 193 | 194 | void CDriverConfig::ProcessExternalSetting(const char *p_message) 195 | { 196 | // Message format: "{setting} {value}" 197 | std::vector l_chunks; 198 | SplitString(p_message, ' ', l_chunks); 199 | 200 | if(l_chunks.size() >= 2U) 201 | { 202 | size_t l_index = 0U; 203 | if(ReadEnumVector(l_chunks[0U], g_settingNames, l_index)) 204 | { 205 | ParsedValue l_value; 206 | switch(l_index) 207 | { 208 | case CS_HandsReset: 209 | { 210 | if(TryParse(l_chunks[1U], l_value.m_int)) 211 | ms_handsReset = (l_value.m_int == 1); 212 | } break; 213 | 214 | case CS_UseVelocity: 215 | { 216 | if(TryParse(l_chunks[1U], l_value.m_int)) 217 | ms_useVelocity = (l_value.m_int == 1); 218 | } break; 219 | 220 | case CS_RootAngleX: 221 | { 222 | if(TryParse(l_chunks[1U], l_value.m_float)) 223 | ms_rootAngle.x = glm::clamp(l_value.m_float, -180.f, 180.f); 224 | } break; 225 | 226 | case CS_RootAngleY: 227 | { 228 | if(TryParse(l_chunks[1U], l_value.m_float)) 229 | ms_rootAngle.y = glm::clamp(l_value.m_float, -180.f, 180.f); 230 | } break; 231 | 232 | case CS_RootAngleZ: 233 | { 234 | if(TryParse(l_chunks[1U], l_value.m_float)) 235 | ms_rootAngle.z = glm::clamp(l_value.m_float, -180.f, 180.f); 236 | } break; 237 | 238 | case CS_RootOffsetX: 239 | { 240 | if(TryParse(l_chunks[1U], l_value.m_float)) 241 | ms_rootOffset.x = glm::clamp(l_value.m_float, -1.f, 1.f); 242 | } break; 243 | 244 | case CS_RootOffsetY: 245 | { 246 | if(TryParse(l_chunks[1U], l_value.m_float)) 247 | ms_rootOffset.y = glm::clamp(l_value.m_float, -1.f, 1.f); 248 | } break; 249 | 250 | case CS_RootOffsetZ: 251 | { 252 | if(TryParse(l_chunks[1U], l_value.m_float)) 253 | ms_rootOffset.z = glm::clamp(l_value.m_float, -1.f, 1.f); 254 | } break; 255 | 256 | case CS_UseControllerInput: 257 | { 258 | if(TryParse(l_chunks[1U], l_value.m_int)) 259 | ms_useControllerInput = (l_value.m_int == 1); 260 | } break; 261 | 262 | case CS_UseTriggerGrip: 263 | { 264 | if(TryParse(l_chunks[1U], l_value.m_int)) 265 | ms_useTriggerGrip = (l_value.m_int == 1); 266 | } break; 267 | 268 | case CS_TriggerMode: 269 | { 270 | if(TryParse(l_chunks[1U], l_value.m_int)) 271 | ms_triggerMode = glm::clamp(l_value.m_int, TL_Partial, TL_Full); 272 | } break; 273 | 274 | case CS_TriggerThreshold: 275 | { 276 | if(TryParse(l_chunks[1U], l_value.m_float)) 277 | ms_triggerThreshold = glm::clamp(l_value.m_float, 0.1f, 1.f); 278 | } break; 279 | 280 | case CS_GripThreshold: 281 | { 282 | if(TryParse(l_chunks[1U], l_value.m_float)) 283 | ms_triggerThreshold = glm::clamp(l_value.m_float, 0.1f, 1.f); 284 | } break; 285 | 286 | case CS_PinchLimitMin: 287 | { 288 | if(TryParse(l_chunks[1U], l_value.m_float)) 289 | ms_pinchLimits.x = glm::clamp(l_value.m_float, 0.01f, 0.1f); 290 | } break; 291 | 292 | case CS_PinchLimitMax: 293 | { 294 | if(TryParse(l_chunks[1U], l_value.m_float)) 295 | ms_pinchLimits.y = glm::clamp(l_value.m_float, 0.01f, 0.1f); 296 | } break; 297 | 298 | case CS_DashboardSmooth: 299 | { 300 | if(TryParse(l_chunks[1U], l_value.m_float)) 301 | ms_dashboardSmooth = glm::clamp(l_value.m_float, 0.01f, 1.f); 302 | } break; 303 | } 304 | } 305 | } 306 | } 307 | 308 | void CDriverConfig::ProcessExternalSetting(const std::string & p_message) 309 | { 310 | ProcessExternalSetting(p_message.c_str()); 311 | } 312 | -------------------------------------------------------------------------------- /driver_leap/Core/CDriverConfig.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CDriverConfig final 4 | { 5 | union ParsedValue 6 | { 7 | bool m_bool; 8 | int m_int; 9 | float m_float; 10 | double m_double; 11 | }; 12 | 13 | static int ms_trackingLevel; 14 | static bool ms_handsReset; 15 | static bool ms_useVelocity; 16 | static float ms_dashboardSmooth; 17 | static bool ms_useTriggerGrip; 18 | static int ms_triggerMode; 19 | static float ms_triggerThreshold; 20 | static float ms_gripThreshold; 21 | static glm::vec2 ms_pinchLimits; 22 | static bool ms_useControllerInput; 23 | static glm::vec3 ms_rootOffset; 24 | static glm::vec3 ms_rootAngle; 25 | 26 | CDriverConfig() = delete; 27 | ~CDriverConfig() = delete; 28 | CDriverConfig(const CDriverConfig &that) = delete; 29 | CDriverConfig& operator=(const CDriverConfig &that) = delete; 30 | public: 31 | enum ConfigSetting : size_t 32 | { 33 | CS_TrackingLevel = 0U, 34 | CS_HandsReset, 35 | CS_UseVelocity, 36 | CS_DashboardSmooth, 37 | CS_UseTriggerGrip, 38 | CS_TriggerMode, 39 | CS_TriggerThreshold, 40 | CS_GripThreshold, 41 | CS_PinchLimitMin, 42 | CS_PinchLimitMax, 43 | CS_UseControllerInput, 44 | CS_RootOffsetX, 45 | CS_RootOffsetY, 46 | CS_RootOffsetZ, 47 | CS_RootAngleX, 48 | CS_RootAngleY, 49 | CS_RootAngleZ 50 | }; 51 | 52 | enum TrackingLevel : int 53 | { 54 | TL_Partial = 0, 55 | TL_Full 56 | }; 57 | 58 | enum TriggerMode : int 59 | { 60 | TM_FingerBend = 0, 61 | TM_Pinch 62 | }; 63 | 64 | static void Load(); 65 | 66 | static int GetTrackingLevel(); 67 | static bool IsHandsResetEnabled(); 68 | static bool IsVelocityUsed(); 69 | static float GetDashboardSmooth(); 70 | static bool IsTriggerGripUsed(); 71 | static int GetTriggerMode(); 72 | static float GetTriggerThreshold(); 73 | static float GetGripThreshold(); 74 | static const glm::vec2& GetPinchLimits(); 75 | static bool IsControllerInputUsed(); 76 | static const glm::vec3& GetRootOffset(); 77 | static const glm::vec3& GetRootAngle(); 78 | 79 | static void ProcessExternalSetting(const char *p_message); 80 | static void ProcessExternalSetting(const std::string &p_message); 81 | }; 82 | -------------------------------------------------------------------------------- /driver_leap/Core/CServerDriver.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Core/CServerDriver.h" 3 | #include "Leap/CLeapPoller.h" 4 | #include "Leap/CLeapFrame.h" 5 | #include "Devices/Controller/CLeapIndexController.h" 6 | #include "Devices/Controller/CControllerInput.h" 7 | #include "Devices/CLeapStation.h" 8 | #include "Core/CDriverConfig.h" 9 | #include "Core/CVREventsPoller.h" 10 | #include "Utils/Utils.h" 11 | 12 | extern std::wstring g_modulePath; 13 | 14 | const char* const CServerDriver::ms_interfaces[] 15 | { 16 | vr::ITrackedDeviceServerDriver_Version, 17 | vr::IServerTrackedDeviceProvider_Version, 18 | nullptr 19 | }; 20 | 21 | CServerDriver::CServerDriver() 22 | { 23 | m_leapPoller = nullptr; 24 | m_leapFrame = nullptr; 25 | m_connectionState = false; 26 | m_leftController = nullptr; 27 | m_rightController = nullptr; 28 | m_leapStation = nullptr; 29 | m_controllerInput = nullptr; 30 | } 31 | 32 | // vr::IServerTrackedDeviceProvider 33 | vr::EVRInitError CServerDriver::Init(vr::IVRDriverContext *pDriverContext) 34 | { 35 | VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext); 36 | CDriverConfig::Load(); 37 | 38 | m_leapStation = new CLeapStation(); 39 | vr::VRServerDriverHost()->TrackedDeviceAdded(m_leapStation->GetSerialNumber().c_str(), vr::TrackedDeviceClass_TrackingReference, m_leapStation); 40 | 41 | m_leftController = new CLeapIndexController(true); 42 | m_rightController = new CLeapIndexController(false); 43 | m_controllerInput = new CControllerInput(); 44 | 45 | vr::VRServerDriverHost()->TrackedDeviceAdded(m_leftController->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, m_leftController); 46 | vr::VRServerDriverHost()->TrackedDeviceAdded(m_rightController->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, m_rightController); 47 | 48 | m_leapStation->SetControllers(m_leftController, m_rightController); 49 | 50 | m_leapFrame = new CLeapFrame(); 51 | m_leapPoller = new CLeapPoller(); 52 | m_leapPoller->Start(); 53 | #ifndef LEAP_ORION 54 | m_leapPoller->SetTrackingMode(_eLeapTrackingMode::eLeapTrackingMode_HMD); 55 | m_leapPoller->SetPolicy(eLeapPolicyFlag::eLeapPolicyFlag_OptimizeHMD, eLeapPolicyFlag::eLeapPolicyFlag_OptimizeScreenTop); 56 | #else 57 | m_leapPoller->SetPolicy(eLeapPolicyFlag::eLeapPolicyFlag_OptimizeHMD); 58 | #endif 59 | 60 | // Start leap_control 61 | std::wstring l_appPath(g_modulePath); 62 | l_appPath.append(L"\\leap_control\\leap_control.exe"); 63 | 64 | STARTUPINFOW l_infoProcess = { 0 }; 65 | PROCESS_INFORMATION l_monitorInfo = { 0 }; 66 | l_infoProcess.cb = sizeof(STARTUPINFOA); 67 | CreateProcessW(l_appPath.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, g_modulePath.c_str(), &l_infoProcess, &l_monitorInfo); 68 | 69 | return vr::VRInitError_None; 70 | } 71 | 72 | void CServerDriver::Cleanup() 73 | { 74 | delete m_leftController; 75 | m_leftController = nullptr; 76 | 77 | delete m_rightController; 78 | m_rightController = nullptr; 79 | 80 | delete m_leapStation; 81 | m_leapStation = nullptr; 82 | 83 | m_leapPoller->Stop(); 84 | delete m_leapPoller; 85 | m_leapPoller = nullptr; 86 | 87 | delete m_leapFrame; 88 | m_leapFrame = nullptr; 89 | 90 | delete m_controllerInput; 91 | m_controllerInput = nullptr; 92 | 93 | m_connectionState = false; 94 | 95 | VR_CLEANUP_SERVER_DRIVER_CONTEXT(); 96 | } 97 | 98 | const char* const* CServerDriver::GetInterfaceVersions() 99 | { 100 | return ms_interfaces; 101 | } 102 | 103 | void CServerDriver::RunFrame() 104 | { 105 | CLeapIndexController::UpdateHMDCoordinates(); 106 | CVREventsPoller::PollEvents(); 107 | 108 | if(m_connectionState != m_leapPoller->IsConnected()) 109 | { 110 | m_connectionState = m_leapPoller->IsConnected(); 111 | m_leapStation->SetTrackingState(m_connectionState ? CLeapStation::TS_Connected : CLeapStation::TS_Search); 112 | m_leftController->SetEnabled(m_connectionState); 113 | m_rightController->SetEnabled(m_connectionState); 114 | 115 | #ifndef LEAP_ORION 116 | m_leapPoller->SetTrackingMode(_eLeapTrackingMode::eLeapTrackingMode_HMD); 117 | m_leapPoller->SetPolicy(eLeapPolicyFlag::eLeapPolicyFlag_OptimizeHMD, eLeapPolicyFlag::eLeapPolicyFlag_OptimizeScreenTop); 118 | #else 119 | m_leapPoller->SetPolicy(eLeapPolicyFlag::eLeapPolicyFlag_OptimizeHMD); 120 | #endif 121 | } 122 | 123 | if(m_connectionState && m_leapPoller->GetFrame(m_leapFrame->GetEvent())) 124 | m_leapFrame->Update(); 125 | 126 | if(CDriverConfig::IsControllerInputUsed() && m_controllerInput->IsConnected()) 127 | m_controllerInput->Update(m_leftController, m_rightController); 128 | 129 | // Update devices 130 | m_leftController->RunFrame(m_leapFrame->GetLeftHand()); 131 | m_rightController->RunFrame(m_leapFrame->GetRightHand()); 132 | m_leapStation->RunFrame(); 133 | } 134 | 135 | bool CServerDriver::ShouldBlockStandbyMode() 136 | { 137 | return false; 138 | } 139 | 140 | void CServerDriver::EnterStandby() 141 | { 142 | } 143 | 144 | void CServerDriver::LeaveStandby() 145 | { 146 | } 147 | -------------------------------------------------------------------------------- /driver_leap/Core/CServerDriver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CLeapPoller; 4 | class CLeapFrame; 5 | class CLeapIndexController; 6 | class CLeapStation; 7 | class CControllerInput; 8 | 9 | class CServerDriver final : public vr::IServerTrackedDeviceProvider 10 | { 11 | static const char* const ms_interfaces[]; 12 | 13 | bool m_connectionState; 14 | CLeapPoller *m_leapPoller; 15 | CLeapFrame *m_leapFrame; 16 | CLeapIndexController *m_leftController; 17 | CLeapIndexController *m_rightController; 18 | CLeapStation *m_leapStation; 19 | CControllerInput *m_controllerInput; 20 | 21 | CServerDriver(const CServerDriver &that) = delete; 22 | CServerDriver& operator=(const CServerDriver &that) = delete; 23 | 24 | // vr::IServerTrackedDeviceProvider 25 | vr::EVRInitError Init(vr::IVRDriverContext *pDriverContext); 26 | void Cleanup(); 27 | const char* const* GetInterfaceVersions(); 28 | void RunFrame(); 29 | bool ShouldBlockStandbyMode(); 30 | void EnterStandby(); 31 | void LeaveStandby(); 32 | public: 33 | CServerDriver(); 34 | ~CServerDriver() = default; 35 | }; 36 | -------------------------------------------------------------------------------- /driver_leap/Core/CVREventsPoller.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Core/CVREventsPoller.h" 3 | 4 | bool CVREventsPoller::ms_dashboardOpened = false; 5 | 6 | bool CVREventsPoller::IsDashboardOpened() 7 | { 8 | return ms_dashboardOpened; 9 | } 10 | 11 | void CVREventsPoller::PollEvents() 12 | { 13 | vr::VREvent_t l_event{ 0 }; 14 | while(vr::VRServerDriverHost()->PollNextEvent(&l_event, sizeof(vr::VREvent_t))) 15 | { 16 | switch(l_event.eventType) 17 | { 18 | case vr::VREvent_DashboardActivated: 19 | ms_dashboardOpened = true; 20 | break; 21 | 22 | case vr::VREvent_DashboardDeactivated: 23 | ms_dashboardOpened = false; 24 | break; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /driver_leap/Core/CVREventsPoller.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CVREventsPoller 4 | { 5 | static bool ms_dashboardOpened; 6 | 7 | CVREventsPoller() = delete; 8 | ~CVREventsPoller() = delete; 9 | CVREventsPoller(const CVREventsPoller &that) = delete; 10 | CVREventsPoller& operator=(const CVREventsPoller &that) = delete; 11 | public: 12 | static bool IsDashboardOpened(); 13 | 14 | static void PollEvents(); 15 | }; 16 | -------------------------------------------------------------------------------- /driver_leap/Devices/CLeapStation.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Devices/CLeapStation.h" 3 | #include "Devices/Controller/CLeapIndexController.h" 4 | #include "Core/CDriverConfig.h" 5 | #include "Utils/Utils.h" 6 | 7 | enum MessageType : size_t 8 | { 9 | MT_Power = 0U, 10 | MT_Setting 11 | }; 12 | const std::vector g_messageTypes = 13 | { 14 | "power", 15 | "setting" 16 | }; 17 | 18 | enum ControllerHand : size_t 19 | { 20 | CH_Left = 0U, 21 | CH_Right 22 | }; 23 | const std::vector g_controllerHands = 24 | { 25 | "left", "right" 26 | }; 27 | 28 | CLeapStation::CLeapStation() 29 | { 30 | m_pose = { 0 }; 31 | m_pose.deviceIsConnected = true; 32 | m_pose.poseIsValid = true; 33 | m_pose.poseTimeOffset = 0.; 34 | m_pose.qDriverFromHeadRotation = { 1.0, .0, .0, .0 }; 35 | m_pose.qRotation = { 1.0, .0, .0, .0 }; 36 | m_pose.qWorldFromDriverRotation = { 1.0, .0, .0, .0 }; 37 | m_pose.result = vr::TrackingResult_Running_OK; 38 | m_pose.shouldApplyHeadModel = false; 39 | for(size_t i = 0U; i < 3U; i++) 40 | { 41 | m_pose.vecAcceleration[i] = 0.; 42 | m_pose.vecAngularAcceleration[i] = 0.; 43 | m_pose.vecAngularVelocity[i] = 0.; 44 | m_pose.vecDriverFromHeadTranslation[i] = 0.; 45 | m_pose.vecPosition[i] = 0.; 46 | m_pose.vecVelocity[i] = 0.; 47 | } 48 | m_pose.willDriftInYaw = false; 49 | 50 | m_propertyHandle = vr::k_ulInvalidPropertyContainer; 51 | m_trackedDevice = vr::k_unTrackedDeviceIndexInvalid; 52 | 53 | m_serialNumber.assign("leap_motion_station"); 54 | m_leftController = nullptr; 55 | m_rightController = nullptr; 56 | } 57 | 58 | // vr::ITrackedDeviceServerDriver 59 | vr::EVRInitError CLeapStation::Activate(uint32_t unObjectId) 60 | { 61 | vr::EVRInitError l_resultError = vr::VRInitError_Driver_CalibrationInvalid; 62 | 63 | if(m_trackedDevice == vr::k_unTrackedDeviceIndexInvalid) 64 | { 65 | m_trackedDevice = unObjectId; 66 | m_propertyHandle = vr::VRProperties()->TrackedDeviceToPropertyContainer(m_trackedDevice); 67 | 68 | vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_TrackingSystemName_String, "leap_motion"); 69 | vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_SerialNumber_String, m_serialNumber.c_str()); 70 | vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_ModelNumber_String, m_serialNumber.c_str()); 71 | vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_ManufacturerName_String, "Leap Motion"); 72 | vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_ModeLabel_String, "L"); 73 | 74 | vr::VRProperties()->SetInt32Property(m_propertyHandle, vr::Prop_DeviceClass_Int32, vr::TrackedDeviceClass_TrackingReference); 75 | vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_IsOnDesktop_Bool, false); 76 | vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_NeverTracked_Bool, false); 77 | vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_WillDriftInYaw_Bool, false); 78 | vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_CanWirelessIdentify_Bool, false); 79 | 80 | vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_FieldOfViewLeftDegrees_Float, 150.f); 81 | vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_FieldOfViewRightDegrees_Float, 150.f); 82 | vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_FieldOfViewTopDegrees_Float, 120.f); 83 | vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_FieldOfViewBottomDegrees_Float, 120.f); 84 | vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_TrackingRangeMinimumMeters_Float, 0.025f); 85 | vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_TrackingRangeMaximumMeters_Float, 0.6f); 86 | 87 | vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_ResourceRoot_String, "leap"); 88 | vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_RenderModelName_String, "{leap}leap_motion_1_0"); 89 | 90 | vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_NamedIconPathDeviceReady_String, "{leap}/icons/base_status_ready.png"); 91 | vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_NamedIconPathDeviceSearching_String, "{leap}/icons/base_status_searching.png"); 92 | 93 | vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_HasDisplayComponent_Bool, false); 94 | vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_HasCameraComponent_Bool, false); 95 | vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_HasDriverDirectModeComponent_Bool, false); 96 | vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_HasVirtualDisplayComponent_Bool, false); 97 | 98 | vr::VRProperties()->SetUint64Property(m_propertyHandle, vr::Prop_VendorSpecific_Reserved_Start, 0x4C4DU); // "LM", _hidden_ property for leap_monitor 99 | 100 | m_pose.vecWorldFromDriverTranslation[0U] = 0.1f; // Slightly move to avoid base stations 101 | 102 | l_resultError = vr::VRInitError_None; 103 | } 104 | 105 | return l_resultError; 106 | } 107 | 108 | void CLeapStation::Deactivate() 109 | { 110 | m_trackedDevice = vr::k_unTrackedDeviceIndexInvalid; 111 | } 112 | 113 | void CLeapStation::EnterStandby() 114 | { 115 | } 116 | 117 | void* CLeapStation::GetComponent(const char* pchComponentNameAndVersion) 118 | { 119 | void *l_result = nullptr; 120 | if(!strcmp(pchComponentNameAndVersion, vr::ITrackedDeviceServerDriver_Version)) 121 | l_result = dynamic_cast(this); 122 | return l_result; 123 | } 124 | 125 | void CLeapStation::DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) 126 | { 127 | if(m_trackedDevice != vr::k_unTrackedDeviceIndexInvalid) 128 | ProcessExternalMessage(pchRequest); 129 | } 130 | 131 | vr::DriverPose_t CLeapStation::GetPose() 132 | { 133 | return m_pose; 134 | } 135 | 136 | // CLeapStation 137 | const std::string& CLeapStation::GetSerialNumber() const 138 | { 139 | return m_serialNumber; 140 | } 141 | 142 | void CLeapStation::SetControllers(CLeapIndexController * p_left, CLeapIndexController * p_right) 143 | { 144 | m_leftController = p_left; 145 | m_rightController = p_right; 146 | } 147 | 148 | void CLeapStation::SetTrackingState(TrackingState p_state) 149 | { 150 | switch(p_state) 151 | { 152 | case TS_Connected: 153 | { 154 | m_pose.result = vr::TrackingResult_Running_OK; 155 | m_pose.poseIsValid = true; 156 | } break; 157 | case TS_Search: 158 | { 159 | m_pose.result = vr::TrackingResult_Calibrating_OutOfRange; 160 | m_pose.poseIsValid = false; 161 | } break; 162 | } 163 | } 164 | 165 | void CLeapStation::RunFrame() 166 | { 167 | if(m_trackedDevice != vr::k_unTrackedDeviceIndexInvalid) 168 | vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_trackedDevice, m_pose, sizeof(vr::DriverPose_t)); 169 | } 170 | 171 | void CLeapStation::ProcessExternalMessage(const char *p_message) 172 | { 173 | std::vector l_chunks; 174 | SplitString(p_message, ' ', l_chunks); 175 | 176 | if(l_chunks.size() > 1U) 177 | { 178 | size_t l_messageType = 0U; 179 | if(ReadEnumVector(l_chunks[0U], g_messageTypes, l_messageType)) 180 | { 181 | switch(l_messageType) 182 | { 183 | case MT_Power: 184 | { 185 | size_t l_hand = 0U; 186 | if(ReadEnumVector(l_chunks[1U], g_controllerHands, l_hand)) 187 | { 188 | switch(l_hand) 189 | { 190 | case CH_Left: 191 | { 192 | if(m_leftController) 193 | m_leftController->ToggleEnabled(); 194 | } break; 195 | case CH_Right: 196 | { 197 | if(m_rightController) 198 | m_rightController->ToggleEnabled(); 199 | } break; 200 | } 201 | } 202 | } break; 203 | 204 | case MT_Setting: 205 | { 206 | std::string l_message; 207 | for(size_t i = 1U, j = l_chunks.size(); i < j; i++) 208 | { 209 | l_message.append(l_chunks[i]); 210 | l_message.push_back(' '); 211 | } 212 | CDriverConfig::ProcessExternalSetting(l_message); 213 | } break; 214 | } 215 | } 216 | } 217 | } 218 | -------------------------------------------------------------------------------- /driver_leap/Devices/CLeapStation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CLeapIndexController; 4 | class CLeapStation final : public vr::ITrackedDeviceServerDriver 5 | { 6 | vr::DriverPose_t m_pose; 7 | vr::PropertyContainerHandle_t m_propertyHandle; 8 | uint32_t m_trackedDevice; 9 | 10 | std::string m_serialNumber; 11 | 12 | CLeapIndexController *m_leftController; 13 | CLeapIndexController *m_rightController; 14 | 15 | CLeapStation(const CLeapStation &that) = delete; 16 | CLeapStation& operator=(const CLeapStation &that) = delete; 17 | void ProcessExternalMessage(const char *p_message); 18 | 19 | // vr::ITrackedDeviceServerDriver 20 | vr::EVRInitError Activate(uint32_t unObjectId); 21 | void Deactivate(); 22 | void EnterStandby(); 23 | void* GetComponent(const char* pchComponentNameAndVersion); 24 | void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize); 25 | vr::DriverPose_t GetPose(); 26 | public: 27 | enum TrackingState : unsigned char 28 | { 29 | TS_Connected = 0U, 30 | TS_Search 31 | }; 32 | 33 | CLeapStation(); 34 | ~CLeapStation() = default; 35 | 36 | const std::string& GetSerialNumber() const; 37 | 38 | void SetControllers(CLeapIndexController *p_left, CLeapIndexController *p_right); 39 | 40 | void SetTrackingState(TrackingState p_state); 41 | 42 | void RunFrame(); 43 | }; 44 | -------------------------------------------------------------------------------- /driver_leap/Devices/Controller/CControllerButton.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Devices/Controller/CControllerButton.h" 3 | 4 | CControllerButton::CControllerButton() 5 | { 6 | m_handle = vr::k_ulInvalidInputComponentHandle; 7 | m_inputType = IT_Boolean; 8 | m_state = false; 9 | m_value = 0.f; 10 | m_updated = false; 11 | } 12 | 13 | vr::VRInputComponentHandle_t CControllerButton::GetHandle() const 14 | { 15 | return m_handle; 16 | } 17 | 18 | vr::VRInputComponentHandle_t& CControllerButton::GetHandleRef() 19 | { 20 | return m_handle; 21 | } 22 | 23 | void CControllerButton::SetInputType(unsigned char p_type) 24 | { 25 | m_inputType = p_type; 26 | } 27 | 28 | unsigned char CControllerButton::GetInputType() const 29 | { 30 | return m_inputType; 31 | } 32 | 33 | void CControllerButton::SetState(bool p_state) 34 | { 35 | if((m_inputType == IT_Boolean) && (m_state != p_state)) 36 | { 37 | m_state = p_state; 38 | m_updated = true; 39 | } 40 | } 41 | 42 | bool CControllerButton::GetState() const 43 | { 44 | return m_state; 45 | } 46 | 47 | void CControllerButton::SetValue(float p_value) 48 | { 49 | if((m_inputType == IT_Float) && (m_value != p_value)) 50 | { 51 | m_value = p_value; 52 | m_updated = true; 53 | } 54 | } 55 | 56 | float CControllerButton::GetValue() const 57 | { 58 | return m_value; 59 | } 60 | 61 | bool CControllerButton::IsUpdated() const 62 | { 63 | return m_updated; 64 | } 65 | 66 | void CControllerButton::ResetUpdate() 67 | { 68 | m_updated = false; 69 | } 70 | -------------------------------------------------------------------------------- /driver_leap/Devices/Controller/CControllerButton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CControllerButton final 4 | { 5 | vr::VRInputComponentHandle_t m_handle; 6 | unsigned char m_inputType; 7 | float m_value; 8 | bool m_state; 9 | bool m_updated; 10 | 11 | CControllerButton(const CControllerButton &that) = delete; 12 | CControllerButton& operator=(const CControllerButton &that) = delete; 13 | public: 14 | enum InputType : unsigned char 15 | { 16 | IT_None = 0U, 17 | IT_Boolean, 18 | IT_Float 19 | }; 20 | 21 | CControllerButton(); 22 | ~CControllerButton() = default; 23 | 24 | vr::VRInputComponentHandle_t GetHandle() const; 25 | vr::VRInputComponentHandle_t& GetHandleRef(); 26 | 27 | void SetInputType(unsigned char p_type); 28 | unsigned char GetInputType() const; 29 | 30 | void SetState(bool p_state); 31 | bool GetState() const; 32 | 33 | void SetValue(float p_value); 34 | float GetValue() const; 35 | 36 | bool IsUpdated() const; 37 | void ResetUpdate(); 38 | }; 39 | -------------------------------------------------------------------------------- /driver_leap/Devices/Controller/CControllerInput.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Devices/Controller/CControllerInput.h" 3 | #include "Devices/Controller/CLeapIndexController.h" 4 | 5 | CControllerInput::CControllerInput() 6 | { 7 | m_deviceCount = 0; 8 | } 9 | 10 | CControllerInput::~CControllerInput() 11 | { 12 | JslDisconnectAndDisposeAll(); 13 | } 14 | 15 | bool CControllerInput::IsConnected() 16 | { 17 | // NOTE: Joycons work as a pair, so we check if both are still alive, otherwise this check will fail. 18 | if((m_devices[JS_TYPE_JOYCON_LEFT].connected && m_devices[JS_TYPE_JOYCON_RIGHT].connected) || m_devices[JS_TYPE_DS4].connected) 19 | return true; 20 | 21 | m_deviceCount = JslConnectDevices(); 22 | 23 | std::vector l_handles(m_deviceCount); 24 | JslGetConnectedDeviceHandles(l_handles.data(), m_deviceCount); 25 | 26 | for(auto l_handle : l_handles) 27 | { 28 | int l_type = JslGetControllerType(l_handle); 29 | m_devices[l_type].connected = true; 30 | m_devices[l_type].handle = l_handle; 31 | } 32 | 33 | // For other controllers, just one of them is enough 34 | if(m_devices[JS_TYPE_DS4].connected) 35 | return true; 36 | 37 | // For joycons, we need both of them connected 38 | return (m_devices[JS_TYPE_JOYCON_LEFT].connected && m_devices[JS_TYPE_JOYCON_RIGHT].connected); 39 | } 40 | 41 | void CControllerInput::Update(CLeapIndexController *p_left, CLeapIndexController *p_right) 42 | { 43 | if(m_devices[JS_TYPE_JOYCON_LEFT].connected) 44 | { 45 | JOY_SHOCK_STATE l_state = JslGetSimpleState(m_devices[JS_TYPE_JOYCON_LEFT].handle); 46 | 47 | // Home 48 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_SystemTouch, l_state.buttons & JSMASK_CAPTURE); 49 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_SystemClick, l_state.buttons & JSMASK_CAPTURE); 50 | 51 | // A 52 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_AClick, l_state.buttons & JSMASK_DOWN); 53 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_ATouch, l_state.buttons & JSMASK_DOWN); 54 | 55 | // B 56 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_BClick, l_state.buttons & JSMASK_UP); 57 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_BTouch, l_state.buttons & JSMASK_UP); 58 | 59 | // Joystick XY 60 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_ThumbstickClick, l_state.buttons & JSMASK_LCLICK); 61 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_ThumbstickTouch, (l_state.stickLX > 0.f) && (l_state.stickLY > 0.f)); 62 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_ThumbstickX, l_state.stickLX); 63 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_ThumbstickY, l_state.stickLY); 64 | 65 | // Trigger 66 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_TriggerClick, l_state.buttons & JSMASK_ZL); 67 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_TriggerTouch, l_state.lTrigger > 0.f); 68 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_TriggerValue, l_state.lTrigger); 69 | 70 | // Grip 71 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_GripTouch, l_state.buttons & JSMASK_L); 72 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_GripValue, (l_state.buttons & JSMASK_L) ? 1.f : 0.f); 73 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_GripForce, (l_state.buttons & JSMASK_L) ? 1.f : 0.f); 74 | 75 | // Trackpad/touchpad 76 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_TrackpadTouch, l_state.buttons & JSMASK_SL); 77 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_TrackpadForce, ((l_state.buttons & JSMASK_SL) && (l_state.buttons & JSMASK_SR)) ? 1.f : 0.f); 78 | } 79 | 80 | if(m_devices[JS_TYPE_JOYCON_RIGHT].connected) 81 | { 82 | JOY_SHOCK_STATE l_state = JslGetSimpleState(m_devices[JS_TYPE_JOYCON_RIGHT].handle); 83 | 84 | // Home 85 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_SystemTouch, l_state.buttons & JSMASK_HOME); 86 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_SystemClick, l_state.buttons & JSMASK_HOME); 87 | 88 | // A 89 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_AClick, l_state.buttons & JSMASK_S); 90 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_ATouch, l_state.buttons & JSMASK_S); 91 | 92 | // B 93 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_BClick, l_state.buttons & JSMASK_N); 94 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_BTouch, l_state.buttons & JSMASK_N); 95 | 96 | // Joystick XY 97 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_ThumbstickClick, l_state.buttons & JSMASK_RCLICK); 98 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_ThumbstickTouch, (l_state.stickRX > 0.f) && (l_state.stickRY > 0.f)); 99 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_ThumbstickX, l_state.stickRX); 100 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_ThumbstickY, l_state.stickRY); 101 | 102 | // Trigger 103 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_TriggerClick, l_state.buttons & JSMASK_ZR); 104 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_TriggerTouch, l_state.rTrigger > 0.f); 105 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_TriggerValue, l_state.rTrigger); 106 | 107 | // Grip 108 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_GripTouch, l_state.buttons & JSMASK_R); 109 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_GripValue, (l_state.buttons & JSMASK_R) ? 1.0f : 0.0f); 110 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_GripForce, (l_state.buttons & JSMASK_R) ? 1.0f : 0.0f); 111 | 112 | // Trackpad/touchpad 113 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_TrackpadTouch, l_state.buttons & JSMASK_SR); 114 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_TrackpadForce, ((l_state.buttons & JSMASK_SR) && (l_state.buttons & JSMASK_SL)) ? 1.f : 0.f); 115 | } 116 | 117 | if(m_devices[JS_TYPE_DS4].connected) 118 | { 119 | JOY_SHOCK_STATE l_state = JslGetSimpleState(m_devices[JS_TYPE_DS4].handle); 120 | 121 | // Home 122 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_SystemTouch, l_state.buttons & JSMASK_HOME); 123 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_SystemClick, l_state.buttons & JSMASK_HOME); 124 | 125 | // A 126 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_AClick, l_state.buttons & JSMASK_DOWN); 127 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_ATouch, l_state.buttons & JSMASK_DOWN); 128 | 129 | // B 130 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_BClick, l_state.buttons & JSMASK_UP); 131 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_BTouch, l_state.buttons & JSMASK_UP); 132 | 133 | // Joystick XY 134 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_ThumbstickClick, l_state.buttons & JSMASK_LCLICK); 135 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_ThumbstickTouch, (l_state.stickLX > 0.f) && (l_state.stickLY > 0.f)); 136 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_ThumbstickX, l_state.stickLX); 137 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_ThumbstickY, l_state.stickLY); 138 | 139 | // Trigger 140 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_TriggerClick, l_state.buttons & JSMASK_ZL); 141 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_TriggerTouch, l_state.lTrigger > 0.f); 142 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_TriggerValue, l_state.lTrigger); 143 | 144 | // Grip 145 | p_left->SetButtonState(CLeapIndexController::IndexButton::IB_GripTouch, l_state.buttons & JSMASK_L); 146 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_GripValue, (l_state.buttons & JSMASK_L) ? 1.f : 0.f); 147 | p_left->SetButtonValue(CLeapIndexController::IndexButton::IB_GripForce, (l_state.buttons & JSMASK_L) ? 1.f : 0.f); 148 | 149 | // Home 150 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_SystemTouch, l_state.buttons & JSMASK_HOME); 151 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_SystemClick, l_state.buttons & JSMASK_HOME); 152 | 153 | // A 154 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_AClick, l_state.buttons & JSMASK_S); 155 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_ATouch, l_state.buttons & JSMASK_S); 156 | 157 | // B 158 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_BClick, l_state.buttons & JSMASK_N); 159 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_BTouch, l_state.buttons & JSMASK_N); 160 | 161 | // Joystick XY 162 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_ThumbstickClick, l_state.buttons & JSMASK_RCLICK); 163 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_ThumbstickTouch, (l_state.stickRX > 0.f) && (l_state.stickRY > 0.f)); 164 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_ThumbstickX, l_state.stickRX); 165 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_ThumbstickY, l_state.stickRY); 166 | 167 | // Trigger 168 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_TriggerClick, l_state.buttons & JSMASK_ZR); 169 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_TriggerTouch, l_state.rTrigger > 0.f); 170 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_TriggerValue, l_state.rTrigger); 171 | 172 | // Grip 173 | p_right->SetButtonState(CLeapIndexController::IndexButton::IB_GripTouch, l_state.buttons & JSMASK_R); 174 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_GripValue, (l_state.buttons & JSMASK_R) ? 1.f : 0.f); 175 | p_right->SetButtonValue(CLeapIndexController::IndexButton::IB_GripForce, (l_state.buttons & JSMASK_R) ? 1.f : 0.f); 176 | } 177 | 178 | for(int i = 0, j = static_cast(m_devices.size()); i < j; i++) 179 | m_devices[i].connected = JslStillConnected(m_devices[i].handle); 180 | } 181 | -------------------------------------------------------------------------------- /driver_leap/Devices/Controller/CControllerInput.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CLeapIndexController; 4 | class CControllerInput 5 | { 6 | struct Device 7 | { 8 | bool connected{ false }; 9 | int handle{ -1 }; 10 | }; 11 | 12 | int m_deviceCount; 13 | std::map m_devices; 14 | public: 15 | explicit CControllerInput(); 16 | ~CControllerInput(); 17 | 18 | bool IsConnected(); 19 | void Update(CLeapIndexController *p_left, CLeapIndexController *p_right); 20 | }; 21 | -------------------------------------------------------------------------------- /driver_leap/Devices/Controller/CLeapIndexController.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CControllerButton; 4 | class CLeapHand; 5 | 6 | class CLeapIndexController : public vr::ITrackedDeviceServerDriver 7 | { 8 | enum SkeletonBone : size_t 9 | { 10 | SB_Root = 0U, 11 | SB_Wrist, 12 | SB_Thumb0, 13 | SB_Thumb1, 14 | SB_Thumb2, 15 | SB_Thumb3, // Last, no effect 16 | SB_IndexFinger0, 17 | SB_IndexFinger1, 18 | SB_IndexFinger2, 19 | SB_IndexFinger3, 20 | SB_IndexFinger4, // Last, no effect 21 | SB_MiddleFinger0, 22 | SB_MiddleFinger1, 23 | SB_MiddleFinger2, 24 | SB_MiddleFinger3, 25 | SB_MiddleFinger4, // Last, no effect 26 | SB_RingFinger0, 27 | SB_RingFinger1, 28 | SB_RingFinger2, 29 | SB_RingFinger3, 30 | SB_RingFinger4, // Last, no effect 31 | SB_PinkyFinger0, 32 | SB_PinkyFinger1, 33 | SB_PinkyFinger2, 34 | SB_PinkyFinger3, 35 | SB_PinkyFinger4, // Last, no effect 36 | SB_Aux_Thumb, 37 | SB_Aux_IndexFinger, 38 | SB_Aux_MiddleFinger, 39 | SB_Aux_RingFinger, 40 | SB_Aux_PinkyFinger, 41 | 42 | SB_Count 43 | }; 44 | enum HandFinger : size_t 45 | { 46 | HF_Thumb = 0U, 47 | HF_Index, 48 | HF_Middle, 49 | HF_Ring, 50 | HF_Pinky, 51 | 52 | HF_Count 53 | }; 54 | 55 | static double ms_headPosition[3U]; 56 | static vr::HmdQuaternion_t ms_headRotation; 57 | 58 | uint32_t m_trackedDevice; 59 | vr::PropertyContainerHandle_t m_propertyContainer; 60 | vr::DriverPose_t m_pose; 61 | vr::VRInputComponentHandle_t m_haptic; 62 | vr::VRBoneTransform_t m_boneTransform[SB_Count]; 63 | vr::VRInputComponentHandle_t m_skeletonHandle; 64 | 65 | bool m_isLeft; 66 | std::string m_serialNumber; 67 | std::vector m_buttons; 68 | glm::vec3 m_position; 69 | glm::quat m_rotation; 70 | 71 | CLeapIndexController(const CLeapIndexController &that) = delete; 72 | CLeapIndexController& operator=(const CLeapIndexController &that) = delete; 73 | 74 | void UpdatePose(const CLeapHand *p_hand); 75 | void UpdateSkeletalInput(const CLeapHand *p_hand); 76 | void UpdateInput(const CLeapHand *p_hand); 77 | 78 | void ResetControls(); 79 | void ChangeBoneOrientation(glm::quat &p_rot) const; 80 | void ChangeBonePosition(glm::vec3 &p_pos) const; 81 | void FixMetacarpalBone(glm::quat &p_rot) const; 82 | 83 | void ProcessExternalMessage(const char *p_message); 84 | 85 | static void ChangeAuxTransformation(glm::vec3 &p_pos, glm::quat &p_rot); 86 | static size_t GetFingerBoneIndex(size_t p_id); 87 | 88 | // vr::ITrackedDeviceServerDriver 89 | vr::EVRInitError Activate(uint32_t unObjectId); 90 | void Deactivate(); 91 | void EnterStandby(); 92 | void* GetComponent(const char* pchComponentNameAndVersion); 93 | void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize); 94 | vr::DriverPose_t GetPose(); 95 | public: 96 | enum IndexButton : size_t 97 | { 98 | IB_SystemClick = 0U, 99 | IB_SystemTouch, 100 | IB_TriggerClick, 101 | IB_TriggerTouch, 102 | IB_TriggerValue, 103 | IB_TrackpadX, 104 | IB_TrackpadY, 105 | IB_TrackpadTouch, 106 | IB_TrackpadForce, 107 | IB_GripTouch, 108 | IB_GripForce, 109 | IB_GripValue, 110 | IB_ThumbstickClick, 111 | IB_ThumbstickTouch, 112 | IB_ThumbstickX, 113 | IB_ThumbstickY, 114 | IB_AClick, 115 | IB_ATouch, 116 | IB_BClick, 117 | IB_BTouch, 118 | IB_FingerIndex, 119 | IB_FingerMiddle, 120 | IB_FingerRing, 121 | IB_FingerPinky, 122 | 123 | IB_Count 124 | }; 125 | 126 | explicit CLeapIndexController(bool p_left); 127 | ~CLeapIndexController(); 128 | 129 | void RunFrame(const CLeapHand *p_hand); 130 | 131 | const std::string& GetSerialNumber() const; 132 | 133 | void SetEnabled(bool p_state); 134 | void ToggleEnabled(); 135 | void SetButtonState(size_t p_button, bool p_state); 136 | void SetButtonValue(size_t p_button, float p_value); 137 | 138 | static void UpdateHMDCoordinates(); 139 | }; 140 | -------------------------------------------------------------------------------- /driver_leap/Leap/CLeapFrame.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Leap/CLeapFrame.h" 3 | #include "Leap/CLeapHand.h" 4 | 5 | CLeapFrame::CLeapFrame() 6 | { 7 | m_leftHand = new CLeapHand(true); 8 | m_rightHand = new CLeapHand(false); 9 | m_lastFrameId = 0U; 10 | } 11 | 12 | CLeapFrame::~CLeapFrame() 13 | { 14 | delete m_leftHand; 15 | delete m_rightHand; 16 | } 17 | 18 | LEAP_TRACKING_EVENT* CLeapFrame::GetEvent() 19 | { 20 | return &m_event; 21 | } 22 | 23 | const CLeapHand* CLeapFrame::GetLeftHand() const 24 | { 25 | return m_leftHand; 26 | } 27 | 28 | const CLeapHand* CLeapFrame::GetRightHand() const 29 | { 30 | return m_rightHand; 31 | } 32 | 33 | void CLeapFrame::Update() 34 | { 35 | if(m_lastFrameId != m_event.tracking_frame_id) 36 | { 37 | bool l_skipLeft = false; 38 | bool l_skipRight = false; 39 | 40 | for(uint32_t i = 0U; i < m_event.nHands; i++) 41 | { 42 | switch(m_event.pHands[i].type) 43 | { 44 | case eLeapHandType_Left: 45 | { 46 | if(!l_skipLeft) 47 | { 48 | m_leftHand->Update(m_event.pHands[i]); 49 | l_skipLeft = true; 50 | } 51 | } break; 52 | case eLeapHandType_Right: 53 | { 54 | if(!l_skipRight) 55 | { 56 | m_rightHand->Update(m_event.pHands[i]); 57 | l_skipRight = true; 58 | } 59 | } break; 60 | } 61 | } 62 | 63 | if(!l_skipLeft) 64 | m_leftHand->Update(); 65 | if(!l_skipRight) 66 | m_rightHand->Update(); 67 | 68 | m_lastFrameId = m_event.tracking_frame_id; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /driver_leap/Leap/CLeapFrame.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CLeapHand; 4 | class CLeapFrame 5 | { 6 | LEAP_TRACKING_EVENT m_event; 7 | CLeapHand *m_leftHand; 8 | CLeapHand *m_rightHand; 9 | int64_t m_lastFrameId; 10 | public: 11 | CLeapFrame(); 12 | ~CLeapFrame(); 13 | 14 | LEAP_TRACKING_EVENT* GetEvent(); 15 | const CLeapHand* GetLeftHand() const; 16 | const CLeapHand* GetRightHand() const; 17 | 18 | void Update(); 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /driver_leap/Leap/CLeapHand.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Leap/CLeapHand.h" 3 | #include "Utils/Utils.h" 4 | 5 | const glm::quat g_hmdRotation(0.f, 0.f, 0.70106769f, -0.70106769f); 6 | const glm::mat4 g_identityMat4(1.f); 7 | const glm::vec3 g_emptyVec3(0.f); 8 | const glm::quat g_identityQuat(1.f, 0.f, 0.f, 0.f); 9 | const float g_pi = glm::pi(); 10 | const float g_piHalf = g_pi * 0.5f; 11 | const float g_piQuarter = g_pi * 0.25f; 12 | const glm::vec4 g_pointVec4(0.f, 0.f, 0.f, 1.f); 13 | 14 | CLeapHand::CLeapHand(bool p_left) 15 | { 16 | m_isLeft = p_left; 17 | } 18 | 19 | bool CLeapHand::IsLeft() const 20 | { 21 | return m_isLeft; 22 | } 23 | 24 | bool CLeapHand::IsVisible() const 25 | { 26 | return m_visible; 27 | } 28 | 29 | const glm::vec3& CLeapHand::GetPosition() const 30 | { 31 | return m_position; 32 | } 33 | 34 | const glm::quat& CLeapHand::GetRotation() const 35 | { 36 | return m_rotation; 37 | } 38 | 39 | const glm::vec3& CLeapHand::GetVelocity() const 40 | { 41 | return m_velocity; 42 | } 43 | 44 | const glm::vec3& CLeapHand::GetFingerBonePosition(size_t p_finger, size_t p_bone) const 45 | { 46 | if((p_finger >= 5U) || (p_bone >= 4U)) 47 | return g_emptyVec3; 48 | 49 | return m_bonesPositions[p_finger * 4U + p_bone]; 50 | } 51 | 52 | const glm::quat& CLeapHand::GetFingerBoneRotation(size_t p_finger, size_t p_bone) const 53 | { 54 | if((p_finger >= 5U) || (p_bone >= 4U)) 55 | return g_identityQuat; 56 | 57 | return m_bonesRotations[p_finger * 4U + p_bone]; 58 | } 59 | 60 | void CLeapHand::GetFingerBoneLocalPosition(size_t p_finger, size_t p_bone, glm::vec3 &l_result, bool p_ignoreMeta) const 61 | { 62 | if((p_finger >= 5U) || (p_bone >= 4U) || (p_ignoreMeta && (p_bone == 0U))) 63 | return; 64 | 65 | size_t l_index = p_finger * 4U + p_bone; 66 | glm::vec3 l_parentPos = (((p_bone == 0U) || (p_ignoreMeta && (p_bone == 1U))) ? m_position : m_bonesPositions[l_index - 1U]); 67 | glm::quat l_parentRot = (((p_bone == 0U) || (p_ignoreMeta && (p_bone == 1U))) ? m_rotation : m_bonesRotations[l_index - 1U]); 68 | glm::mat4 l_parentMat = glm::translate(g_identityMat4, l_parentPos) * glm::toMat4(l_parentRot); 69 | glm::mat4 l_childMat = glm::translate(g_identityMat4, m_bonesPositions[l_index]) * glm::toMat4(m_bonesRotations[l_index]); 70 | glm::mat4 l_childLocal = glm::inverse(l_parentMat) * l_childMat; 71 | l_result = l_childLocal * g_pointVec4; 72 | } 73 | 74 | void CLeapHand::GetFingerBoneLocalRotation(size_t p_finger, size_t p_bone, glm::quat &l_result, bool p_ignoreMeta) const 75 | { 76 | if((p_finger >= 5U) || (p_bone >= 4U) || (p_ignoreMeta && (p_bone == 0U))) 77 | return; 78 | 79 | size_t l_index = p_finger * 4U + p_bone; 80 | l_result = glm::inverse(((p_bone == 0U) || (p_ignoreMeta && p_bone == 1U)) ? m_rotation : m_bonesRotations[l_index - 1U]) * m_bonesRotations[l_index]; 81 | } 82 | 83 | float CLeapHand::GetFingerBend(size_t p_finger) const 84 | { 85 | return ((p_finger >= 5U) ? 0.f : m_fingersBends[p_finger]); 86 | } 87 | 88 | float CLeapHand::GetGrabValue() const 89 | { 90 | return m_grabValue; 91 | } 92 | 93 | float CLeapHand::GetPinchDistance() const 94 | { 95 | return m_pinchDistance; 96 | } 97 | 98 | void CLeapHand::Update(const LEAP_HAND &p_hand) 99 | { 100 | m_visible = true; 101 | 102 | ConvertPosition(p_hand.arm.next_joint, m_position); 103 | ConvertPosition(p_hand.palm.velocity, m_velocity); 104 | ConvertRotation(p_hand.palm.orientation, m_rotation); 105 | m_rotation = glm::normalize(m_rotation); 106 | 107 | // Bends 108 | for(size_t i = 0U; i < 5U; i++) 109 | { 110 | m_fingersBends[i] = 0.f; 111 | 112 | glm::vec3 l_prevDirection; 113 | size_t l_startBoneIndex = ((i == 0U) ? 1U : 0U); 114 | for(size_t j = l_startBoneIndex; j < 4U; j++) 115 | { 116 | const LEAP_BONE &l_bone = p_hand.digits[i].bones[j]; 117 | glm::vec3 l_direction(l_bone.next_joint.x - l_bone.prev_joint.x, l_bone.next_joint.y - l_bone.prev_joint.y, l_bone.next_joint.z - l_bone.prev_joint.z); 118 | l_direction = glm::normalize(l_direction); 119 | if(j > l_startBoneIndex) m_fingersBends[i] += glm::acos(glm::dot(l_direction, l_prevDirection)); 120 | l_prevDirection = l_direction; 121 | } 122 | 123 | m_fingersBends[i] = InverseLerp(m_fingersBends[i], (i == 0U) ? 0.f : g_piQuarter, (i == 0U) ? g_piQuarter : g_pi); 124 | } 125 | 126 | m_grabValue = (InverseLerp(m_fingersBends[2U], 0.5f, 1.f) + InverseLerp(m_fingersBends[3U], 0.5f, 1.f) + InverseLerp(m_fingersBends[3U], 0.5f, 1.f)) / 3.f; 127 | m_pinchDistance = p_hand.pinch_distance * 0.001f; 128 | 129 | // Convert fingers to HMD space 130 | for(size_t i = 0; i < 5U; i++) 131 | { 132 | for(size_t j = 0; j < 4U; j++) 133 | { 134 | size_t l_index = i * 4U + j; 135 | ConvertPosition(p_hand.digits[i].bones[j].prev_joint, m_bonesPositions[l_index]); 136 | ConvertRotation(p_hand.digits[i].bones[j].rotation, m_bonesRotations[l_index]); 137 | } 138 | } 139 | } 140 | 141 | void CLeapHand::Update() 142 | { 143 | m_visible = false; 144 | } 145 | 146 | void CLeapHand::ConvertPosition(const LEAP_VECTOR &p_src, glm::vec3 &p_dst) 147 | { 148 | // In desktop mode: +X - right, +Y - up, -Z - forward (as OpenGL) 149 | // In HMD mode: +X - left, +Y - forward, +Z - down (same basis, just rotated) 150 | p_dst.x = -0.001f * p_src.x; 151 | p_dst.y = -0.001f * p_src.z; 152 | p_dst.z = -0.001f * p_src.y; 153 | } 154 | 155 | void CLeapHand::ConvertRotation(const LEAP_QUATERNION &p_src, glm::quat &p_dst) 156 | { 157 | // Simple rotation is enough because Leap has same basis as SteamVR 158 | glm::quat l_rot(p_src.w, p_src.x, p_src.y, p_src.z); 159 | p_dst = g_hmdRotation * l_rot; 160 | } 161 | -------------------------------------------------------------------------------- /driver_leap/Leap/CLeapHand.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CLeapHand final 4 | { 5 | bool m_isLeft; 6 | bool m_visible; 7 | glm::vec3 m_position; 8 | glm::quat m_rotation; 9 | glm::vec3 m_velocity; 10 | std::array m_bonesPositions; 11 | std::array m_bonesRotations; 12 | std::array m_fingersBends; 13 | float m_grabValue; 14 | float m_pinchDistance; 15 | public: 16 | enum Finger : size_t 17 | { 18 | Thumb = 0U, 19 | Index, 20 | Middle, 21 | Ring, 22 | Pinky 23 | }; 24 | enum FingerBone : size_t 25 | { 26 | Metacarpal = 0U, 27 | Proximal, 28 | Intermediate, 29 | Distal 30 | }; 31 | 32 | explicit CLeapHand(bool p_left); 33 | ~CLeapHand() = default; 34 | 35 | bool IsLeft() const; 36 | bool IsVisible() const; 37 | 38 | const glm::vec3& GetPosition() const; 39 | const glm::quat& GetRotation() const; 40 | const glm::vec3& GetVelocity() const; 41 | 42 | const glm::vec3& GetFingerBonePosition(size_t p_finger, size_t p_bone) const; 43 | const glm::quat& GetFingerBoneRotation(size_t p_finger, size_t p_bone) const; 44 | 45 | void GetFingerBoneLocalPosition(size_t p_finger, size_t p_bone, glm::vec3 &l_result, bool p_ignoreMeta = false) const; 46 | void GetFingerBoneLocalRotation(size_t p_finger, size_t p_bone, glm::quat &l_result, bool p_ignoreMeta = false) const; 47 | 48 | float GetFingerBend(size_t p_finger) const; 49 | float GetGrabValue() const; 50 | float GetPinchDistance() const; 51 | 52 | void Update(const LEAP_HAND &p_hand); 53 | void Update(); 54 | 55 | static void ConvertPosition(const LEAP_VECTOR &p_src, glm::vec3 &p_dst); 56 | static void ConvertRotation(const LEAP_QUATERNION &p_src, glm::quat &p_dst); 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /driver_leap/Leap/CLeapPoller.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Leap/CLeapPoller.h" 3 | 4 | CLeapPoller::CLeapPoller() 5 | { 6 | m_isRunning = false; 7 | m_thread = nullptr; 8 | m_connection = nullptr; 9 | m_frame = new LEAP_TRACKING_EVENT(); 10 | m_devicesCount = 0; 11 | } 12 | 13 | CLeapPoller::~CLeapPoller() 14 | { 15 | delete m_frame; 16 | } 17 | 18 | void CLeapPoller::Start() 19 | { 20 | if(m_isRunning) 21 | return; 22 | if(LeapCreateConnection(nullptr, &m_connection) != eLeapRS::eLeapRS_Success) 23 | return; 24 | if(LeapOpenConnection(m_connection) != eLeapRS::eLeapRS_Success) 25 | return; 26 | 27 | m_isRunning = true; 28 | m_thread = new std::thread(&CLeapPoller::PollThread, this); 29 | } 30 | 31 | void CLeapPoller::Stop() 32 | { 33 | if(!m_isRunning) 34 | return; 35 | 36 | m_isRunning = false; 37 | LeapCloseConnection(m_connection); 38 | 39 | m_thread->join(); 40 | m_thread = nullptr; 41 | 42 | LeapDestroyConnection(m_connection); 43 | m_connection = nullptr; 44 | 45 | m_devicesCount = 0; 46 | } 47 | 48 | bool CLeapPoller::IsConnected() const 49 | { 50 | return (m_isRunning && (m_devicesCount > 0)); 51 | } 52 | 53 | bool CLeapPoller::GetFrame(LEAP_TRACKING_EVENT *p_target) 54 | { 55 | if(!m_isRunning) 56 | return false; 57 | 58 | if(!m_frameLock.try_lock()) 59 | return false; 60 | 61 | std::memcpy(p_target, m_frame, sizeof(LEAP_TRACKING_EVENT)); 62 | m_frameLock.unlock(); 63 | return true; 64 | } 65 | 66 | #ifndef LEAP_ORION 67 | void CLeapPoller::SetTrackingMode(eLeapTrackingMode p_mode) 68 | { 69 | if(m_isRunning) 70 | LeapSetTrackingMode(m_connection, p_mode); 71 | } 72 | #endif 73 | 74 | void CLeapPoller::SetPolicy(uint64_t p_set, uint64_t p_clear) 75 | { 76 | if(m_isRunning) 77 | LeapSetPolicyFlags(m_connection, p_set, p_clear); 78 | } 79 | 80 | void CLeapPoller::PollThread() 81 | { 82 | while(m_isRunning) 83 | { 84 | LEAP_CONNECTION_MESSAGE l_message{ sizeof(LEAP_CONNECTION_MESSAGE) }; 85 | if(LeapPollConnection(m_connection, 150U, &l_message) != eLeapRS::eLeapRS_Success) 86 | continue; 87 | 88 | switch(l_message.type) 89 | { 90 | case eLeapEventType_None: 91 | break; 92 | 93 | case eLeapEventType_Connection: 94 | OnConnectionEvent(); 95 | break; 96 | 97 | case eLeapEventType_ConnectionLost: 98 | OnConnectionLostEvent(); 99 | break; 100 | 101 | case eLeapEventType_Device: 102 | OnDeviceEvent(l_message.device_event); 103 | break; 104 | 105 | case eLeapEventType_DeviceLost: 106 | OnDeviceLostEvent(l_message.device_event); 107 | break; 108 | 109 | case eLeapEventType_Tracking: 110 | OnTrackingEvent(l_message.tracking_event); 111 | break; 112 | } 113 | } 114 | } 115 | 116 | void CLeapPoller::OnConnectionEvent() 117 | { 118 | } 119 | 120 | void CLeapPoller::OnConnectionLostEvent() 121 | { 122 | m_devicesCount = 0U; 123 | } 124 | 125 | void CLeapPoller::OnDeviceEvent(const LEAP_DEVICE_EVENT* p_event) 126 | { 127 | if(!p_event->device.handle) 128 | return; 129 | 130 | LEAP_DEVICE l_device; 131 | if(LeapOpenDevice(p_event->device, &l_device) != eLeapRS_Success) 132 | return; 133 | 134 | m_devicesCount++; 135 | } 136 | 137 | void CLeapPoller::OnDeviceLostEvent(const LEAP_DEVICE_EVENT *p_event) 138 | { 139 | // In LeapCSharp there is call for opening device, no idea why 140 | m_devicesCount--; 141 | } 142 | 143 | void CLeapPoller::OnTrackingEvent(const LEAP_TRACKING_EVENT *p_event) 144 | { 145 | m_frameLock.lock(); 146 | std::memcpy(m_frame, p_event, sizeof(LEAP_TRACKING_EVENT)); 147 | m_frameLock.unlock(); 148 | } 149 | -------------------------------------------------------------------------------- /driver_leap/Leap/CLeapPoller.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CLeapPoller 4 | { 5 | std::atomic m_isRunning; 6 | std::mutex m_frameLock; 7 | std::thread *m_thread; 8 | 9 | LEAP_CONNECTION m_connection; 10 | std::atomic m_devicesCount; 11 | LEAP_TRACKING_EVENT *m_frame; 12 | 13 | // Async methods 14 | void PollThread(); 15 | void OnConnectionEvent(); 16 | void OnConnectionLostEvent(); 17 | void OnDeviceEvent(const LEAP_DEVICE_EVENT* p_event); 18 | void OnDeviceLostEvent(const LEAP_DEVICE_EVENT *p_event); 19 | void OnTrackingEvent(const LEAP_TRACKING_EVENT* p_event); 20 | public: 21 | CLeapPoller(); 22 | ~CLeapPoller(); 23 | 24 | void Start(); 25 | void Stop(); 26 | 27 | bool IsConnected() const; 28 | bool GetFrame(LEAP_TRACKING_EVENT *p_target); 29 | 30 | void SetPolicy(uint64_t p_set, uint64_t p_clear = 0U); 31 | #ifndef LEAP_ORION 32 | void SetTrackingMode(eLeapTrackingMode p_mode); 33 | #endif 34 | }; 35 | 36 | 37 | -------------------------------------------------------------------------------- /driver_leap/Utils/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Utils/Utils.h" 3 | 4 | // Left hand open gesture transformation, thanks to https://github.com/spayne and his soft_knuckles repository 5 | extern const std::array g_openHandGesture = 6 | { 7 | vr::VRBoneTransform_t {{ 0.000000f, 0.000000f, 0.000000f, 1.000000f }, { 1.000000f, -0.000000f, -0.000000f, 0.000000f }}, 8 | vr::VRBoneTransform_t {{ -0.0445230342f,0.0301547553f,0.16438961f, 1.000000f}, { 1.50656376e-07f, -1.77612698e-08f,0.927827835f,-0.373008907f }}, // Wrist values from SteamVR Unity package with disabled skeleton blending 9 | vr::VRBoneTransform_t {{ -0.012083f, 0.028070f, 0.025050f, 1.000000f }, { 0.464112f, 0.567418f, 0.272106f, 0.623374f }}, 10 | vr::VRBoneTransform_t {{ 0.040406f, 0.000000f, -0.000000f, 1.000000f }, { 0.994838f, 0.082939f, 0.019454f, 0.055130f }}, 11 | vr::VRBoneTransform_t {{ 0.032517f, 0.000000f, 0.000000f, 1.000000f }, { 0.974793f, -0.003213f, 0.021867f, -0.222015f }}, 12 | vr::VRBoneTransform_t {{ 0.030464f, -0.000000f, -0.000000f, 1.000000f }, { 1.000000f, -0.000000f, -0.000000f, 0.000000f }}, 13 | vr::VRBoneTransform_t {{ 0.000632f, 0.026866f, 0.015002f, 1.000000f }, { 0.644251f, 0.421979f, -0.478202f, 0.422133f }}, 14 | vr::VRBoneTransform_t {{ 0.074204f, -0.005002f, 0.000234f, 1.000000f }, { 0.995332f, 0.007007f, -0.039124f, 0.087949f }}, 15 | vr::VRBoneTransform_t {{ 0.043930f, -0.000000f, -0.000000f, 1.000000f }, { 0.997891f, 0.045808f, 0.002142f, -0.045943f }}, 16 | vr::VRBoneTransform_t {{ 0.028695f, 0.000000f, 0.000000f, 1.000000f }, { 0.999649f, 0.001850f, -0.022782f, -0.013409f }}, 17 | vr::VRBoneTransform_t {{ 0.022821f, 0.000000f, -0.000000f, 1.000000f }, { 1.000000f, -0.000000f, 0.000000f, -0.000000f }}, 18 | vr::VRBoneTransform_t {{ 0.002177f, 0.007120f, 0.016319f, 1.000000f }, { 0.546723f, 0.541276f, -0.442520f, 0.460749f }}, 19 | vr::VRBoneTransform_t {{ 0.070953f, 0.000779f, 0.000997f, 1.000000f }, { 0.980294f, -0.167261f, -0.078959f, 0.069368f }}, 20 | vr::VRBoneTransform_t {{ 0.043108f, 0.000000f, 0.000000f, 1.000000f }, { 0.997947f, 0.018493f, 0.013192f, 0.059886f }}, 21 | vr::VRBoneTransform_t {{ 0.033266f, 0.000000f, 0.000000f, 1.000000f }, { 0.997394f, -0.003328f, -0.028225f, -0.066315f }}, 22 | vr::VRBoneTransform_t {{ 0.025892f, -0.000000f, 0.000000f, 1.000000f }, { 0.999195f, -0.000000f, 0.000000f, 0.040126f }}, 23 | vr::VRBoneTransform_t {{ 0.000513f, -0.006545f, 0.016348f, 1.000000f }, { 0.516692f, 0.550143f, -0.495548f, 0.429888f }}, 24 | vr::VRBoneTransform_t {{ 0.065876f, 0.001786f, 0.000693f, 1.000000f }, { 0.990420f, -0.058696f, -0.101820f, 0.072495f }}, 25 | vr::VRBoneTransform_t {{ 0.040697f, 0.000000f, 0.000000f, 1.000000f }, { 0.999545f, -0.002240f, 0.000004f, 0.030081f }}, 26 | vr::VRBoneTransform_t {{ 0.028747f, -0.000000f, -0.000000f, 1.000000f }, { 0.999102f, -0.000721f, -0.012693f, 0.040420f }}, 27 | vr::VRBoneTransform_t {{ 0.022430f, -0.000000f, 0.000000f, 1.000000f }, { 1.000000f, 0.000000f, 0.000000f, 0.000000f }}, 28 | vr::VRBoneTransform_t {{ -0.002478f, -0.018981f, 0.015214f, 1.000000f }, { 0.526918f, 0.523940f, -0.584025f, 0.326740f }}, 29 | vr::VRBoneTransform_t {{ 0.062878f, 0.002844f, 0.000332f, 1.000000f }, { 0.986609f, -0.059615f, -0.135163f, 0.069132f }}, 30 | vr::VRBoneTransform_t {{ 0.030220f, 0.000000f, 0.000000f, 1.000000f }, { 0.994317f, 0.001896f, -0.000132f, 0.106446f }}, 31 | vr::VRBoneTransform_t {{ 0.018187f, 0.000000f, 0.000000f, 1.000000f }, { 0.995931f, -0.002010f, -0.052079f, -0.073526f }}, 32 | vr::VRBoneTransform_t {{ 0.018018f, 0.000000f, -0.000000f, 1.000000f }, { 1.000000f, 0.000000f, 0.000000f, 0.000000f }}, 33 | vr::VRBoneTransform_t {{ -0.006059f, 0.056285f, 0.060064f, 1.000000f }, { 0.737238f, 0.202745f, 0.594267f, 0.249441f }}, 34 | vr::VRBoneTransform_t {{ -0.040416f, -0.043018f, 0.019345f, 1.000000f }, { -0.290331f, 0.623527f, -0.663809f, -0.293734f }}, 35 | vr::VRBoneTransform_t {{ -0.039354f, -0.075674f, 0.047048f, 1.000000f }, { -0.187047f, 0.678062f, -0.659285f, -0.265683f }}, 36 | vr::VRBoneTransform_t {{ -0.038340f, -0.090987f, 0.082579f, 1.000000f }, { -0.183037f, 0.736793f, -0.634757f, -0.143936f }}, 37 | vr::VRBoneTransform_t {{ -0.031806f, -0.087214f, 0.121015f, 1.000000f }, { -0.003659f, 0.758407f, -0.639342f, -0.126678f }} 38 | }; 39 | 40 | void ConvertMatrix(const vr::HmdMatrix34_t& p_matVR, glm::mat4& p_mat) 41 | { 42 | for(int i = 0; i < 4; i++) 43 | { 44 | for(int j = 0; j < 3; j++) 45 | p_mat[i][j] = p_matVR.m[j][i]; 46 | } 47 | for(int i = 0; i < 3; i++) 48 | p_mat[i][3] = 0.f; 49 | p_mat[3][3] = 1.f; 50 | } 51 | 52 | void ConvertVector3(const vr::HmdVector4_t& p_vrVec, glm::vec3& p_glmVec) 53 | { 54 | for(size_t i = 0U; i < 3U; i++) 55 | p_glmVec[i] = p_vrVec.v[i]; 56 | } 57 | 58 | void ConvertVector3(const glm::vec3& p_glmVec, vr::HmdVector4_t& p_vrVec) 59 | { 60 | for(size_t i = 0U; i < 3U; i++) 61 | p_vrVec.v[i] = p_glmVec[i]; 62 | } 63 | 64 | size_t ReadEnumVector(const std::string& p_val, const std::vector& p_vec) 65 | { 66 | size_t l_result = std::numeric_limits::max(); 67 | for(auto iter = p_vec.begin(), iterEnd = p_vec.end(); iter != iterEnd; ++iter) 68 | { 69 | if(!iter->compare(p_val)) 70 | { 71 | l_result = std::distance(p_vec.begin(), iter); 72 | break; 73 | } 74 | } 75 | return l_result; 76 | } 77 | 78 | size_t ReadEnumVector(const char* p_val, const std::vector& p_vec) 79 | { 80 | size_t l_result = std::numeric_limits::max(); 81 | for(auto iter = p_vec.begin(), iterEnd = p_vec.end(); iter != iterEnd; ++iter) 82 | { 83 | if(!iter->compare(p_val)) 84 | { 85 | l_result = std::distance(p_vec.begin(), iter); 86 | break; 87 | } 88 | } 89 | return l_result; 90 | } 91 | 92 | bool ReadEnumVector(const std::string &p_val, const std::vector &p_vec, size_t &p_index) 93 | { 94 | bool l_result = false; 95 | for(auto iter = p_vec.begin(), iterEnd = p_vec.end(); iter != iterEnd; ++iter) 96 | { 97 | if(!iter->compare(p_val)) 98 | { 99 | p_index = std::distance(p_vec.begin(), iter); 100 | l_result = true; 101 | break; 102 | } 103 | } 104 | return l_result; 105 | } 106 | bool ReadEnumVector(const char *p_val, const std::vector &p_vec, size_t &p_index) 107 | { 108 | bool l_result = false; 109 | for(auto iter = p_vec.begin(), iterEnd = p_vec.end(); iter != iterEnd; ++iter) 110 | { 111 | if(!iter->compare(p_val)) 112 | { 113 | p_index = std::distance(p_vec.begin(), iter); 114 | l_result = true; 115 | break; 116 | } 117 | } 118 | return l_result; 119 | } 120 | 121 | void SplitString(const std::string& p_text, const char p_separator, std::vector& p_result) 122 | { 123 | std::stringstream l_stream(p_text); 124 | std::string l_segment; 125 | while(std::getline(l_stream, l_segment, p_separator)) 126 | { 127 | p_result.push_back(l_segment); 128 | } 129 | } 130 | 131 | void SplitString(const char* p_text, const char p_separator, std::vector& p_result) 132 | { 133 | std::stringstream l_stream(p_text); 134 | std::string l_segment; 135 | while(std::getline(l_stream, l_segment, p_separator)) 136 | { 137 | p_result.push_back(l_segment); 138 | } 139 | } 140 | 141 | float InverseLerp(float p_val, float p_min, float p_max) 142 | { 143 | if(p_min == p_max) 144 | return 1.f; 145 | const float l_mapped = (p_val - p_min) / (p_max - p_min); 146 | return glm::clamp(l_mapped, 0.f, 1.f); 147 | } 148 | 149 | bool TryParse(const std::string &p_string, int &p_value) 150 | { 151 | bool l_result = false; 152 | try 153 | { 154 | p_value = std::stoi(p_string); 155 | l_result = true; 156 | } 157 | catch(std::exception) {} 158 | return l_result; 159 | } 160 | bool TryParse(const std::string &p_string, float &p_value) 161 | { 162 | bool l_result = false; 163 | try 164 | { 165 | p_value = std::stof(p_string); 166 | l_result = true; 167 | } 168 | catch(std::exception) {} 169 | return l_result; 170 | } 171 | -------------------------------------------------------------------------------- /driver_leap/Utils/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void ConvertMatrix(const vr::HmdMatrix34_t &p_matVR, glm::mat4 &p_mat); 4 | template void ConvertQuaternion(const T &p_src, U &p_dst) 5 | { 6 | p_dst.x = p_src.x; 7 | p_dst.y = p_src.y; 8 | p_dst.z = p_src.z; 9 | p_dst.w = p_src.w; 10 | } 11 | void ConvertVector3(const vr::HmdVector4_t &p_vrVec, glm::vec3 &p_glmVec); 12 | void ConvertVector3(const glm::vec3 &p_glmVec, vr::HmdVector4_t &p_vrVec); 13 | 14 | size_t ReadEnumVector(const std::string &p_val, const std::vector &p_vec); 15 | size_t ReadEnumVector(const char *p_val, const std::vector &p_vec); 16 | 17 | bool ReadEnumVector(const std::string &p_val, const std::vector &p_vec, size_t &p_index); 18 | bool ReadEnumVector(const char *p_val, const std::vector &p_vec, size_t &p_index); 19 | 20 | void SplitString(const std::string& p_text, const char p_separator, std::vector& p_result); 21 | void SplitString(const char *p_text, const char p_separator, std::vector& p_result); 22 | float InverseLerp(float p_val, float p_min, float p_max); 23 | 24 | bool TryParse(const std::string &p_string, int &p_value); 25 | bool TryParse(const std::string &p_string, float &p_value); 26 | -------------------------------------------------------------------------------- /driver_leap/dllmain.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Core/CServerDriver.h" 3 | 4 | std::wstring g_modulePath; 5 | 6 | BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID) 7 | { 8 | switch(ul_reason_for_call) 9 | { 10 | case DLL_PROCESS_ATTACH: 11 | { 12 | g_modulePath.resize(2048U); 13 | unsigned long l_length = GetModuleFileNameW(hModule, &g_modulePath[0], 2048U); 14 | g_modulePath.resize(l_length); 15 | g_modulePath.erase(g_modulePath.begin() + g_modulePath.rfind(L'\\'), g_modulePath.end()); 16 | } break; 17 | case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: 18 | break; 19 | } 20 | return TRUE; 21 | } 22 | 23 | CServerDriver g_serverDriver; 24 | 25 | extern "C" __declspec(dllexport) void* HmdDriverFactory(const char *pInterfaceName, int *pReturnCode) 26 | { 27 | void *l_result = nullptr; 28 | if(!strcmp(vr::IServerTrackedDeviceProvider_Version, pInterfaceName)) l_result = dynamic_cast(&g_serverDriver); 29 | else 30 | { 31 | if(pReturnCode) *pReturnCode = vr::VRInitError_Init_InterfaceNotFound; 32 | } 33 | return l_result; 34 | } 35 | -------------------------------------------------------------------------------- /driver_leap/driver_leap.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {52d3f16d-a7a5-4d6f-8f17-5e4b459a1440} 15 | DynamicLibrary 16 | driver_leap 17 | driver_leap 18 | en-US 19 | 10.0.19041.0 20 | 21 | 22 | 23 | DynamicLibrary 24 | true 25 | v141 26 | 27 | 28 | DynamicLibrary 29 | false 30 | true 31 | v141 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | false 42 | false 43 | true 44 | $(SolutionDir)bin\win64\ 45 | $(SolutionDir)objs\$(ProjectName)\$(PlatformName)\$(Configuration)\ 46 | 47 | 48 | false 49 | false 50 | true 51 | $(SolutionDir)bin\win64\ 52 | $(SolutionDir)objs\$(ProjectName)\$(PlatformName)\$(Configuration)\ 53 | 54 | 55 | 56 | Use 57 | false 58 | 59 | 60 | Console 61 | false 62 | false 63 | 64 | 65 | 66 | 67 | Use 68 | false 69 | 70 | 71 | Console 72 | false 73 | false 74 | 75 | 76 | 77 | 78 | Use 79 | false 80 | 81 | 82 | Console 83 | false 84 | false 85 | 86 | 87 | 88 | 89 | Use 90 | false 91 | ./;../vendor/LeapSDK/include;../vendor/openvr/headers;../vendor/pugixml/src;../vendor/glm;../vendor/JSL;%(AdditionalIncludeDirectories) 92 | stdafx.h 93 | %(PreprocessorDefinitions) 94 | 95 | 96 | Windows 97 | false 98 | false 99 | ../vendor/LeapSDK/lib/x64;../vendor/openvr/lib/win64;../vendor/JSL/x64;%(AdditionalLibraryDirectories) 100 | openvr_api.lib;LeapC.lib;JoyShockLibrary.lib;%(AdditionalDependencies) 101 | true 102 | 103 | 104 | 105 | 106 | 107 | copy /y "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\leap\bin\win64\$(TargetFileName)" 108 | Install Binary 109 | 110 | 111 | 112 | 113 | Use 114 | false 115 | ./;../vendor/LeapSDK/include;../vendor/openvr/headers;../vendor/pugixml/src;../vendor/glm;../vendor/JSL;%(AdditionalIncludeDirectories) 116 | stdafx.h 117 | true 118 | %(PreprocessorDefinitions) 119 | 120 | 121 | Windows 122 | false 123 | false 124 | ../vendor/LeapSDK/lib/x64;../vendor/openvr/lib/win64;../vendor/JSL/x64;%(AdditionalLibraryDirectories) 125 | openvr_api.lib;LeapC.lib;JoyShockLibrary.lib;%(AdditionalDependencies) 126 | false 127 | 128 | 129 | 130 | 131 | 132 | copy /y "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\leap\bin\win64\$(TargetFileName)" 133 | Install Binary 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | NotUsing 153 | NotUsing 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | Create 168 | Create 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /driver_leap/driver_leap.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | vendor\pugixml 8 | 9 | 10 | Utils 11 | 12 | 13 | Devices 14 | 15 | 16 | Core 17 | 18 | 19 | Core 20 | 21 | 22 | Leap 23 | 24 | 25 | Leap 26 | 27 | 28 | Leap 29 | 30 | 31 | Devices\Controller 32 | 33 | 34 | Devices\Controller 35 | 36 | 37 | Devices\Controller 38 | 39 | 40 | Core 41 | 42 | 43 | 44 | 45 | 46 | Utils 47 | 48 | 49 | Devices 50 | 51 | 52 | Core 53 | 54 | 55 | Core 56 | 57 | 58 | Leap 59 | 60 | 61 | Leap 62 | 63 | 64 | Leap 65 | 66 | 67 | Devices\Controller 68 | 69 | 70 | Devices\Controller 71 | 72 | 73 | Devices\Controller 74 | 75 | 76 | Core 77 | 78 | 79 | 80 | 81 | {4dd100d6-5318-4ebc-a9eb-9ef27f1ae76b} 82 | 83 | 84 | {21c081d3-867d-441e-90d0-ef26e9d05cae} 85 | 86 | 87 | {839b3e7e-6f9e-49a2-b8e7-c8c40d0cd982} 88 | 89 | 90 | {b03c9f12-ff59-41c2-addf-e0d1c366d73a} 91 | 92 | 93 | {5709dbc5-cf75-4243-a691-22f7d553f0da} 94 | 95 | 96 | {32d26d56-e07f-41de-aa44-3e0d88c9f835} 97 | 98 | 99 | {82e3a6c5-9886-457e-8308-b6c62ec7ce03} 100 | 101 | 102 | -------------------------------------------------------------------------------- /driver_leap/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /driver_leap/stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define WIN32_LEAN_AND_MEAN 4 | #define NOMINMAX 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "openvr_driver.h" 20 | #include "LeapC.h" 21 | 22 | #define GLM_ENABLE_EXPERIMENTAL 23 | #include "glm/glm.hpp" 24 | #include "glm/gtc/matrix_transform.hpp" 25 | #include "glm/gtc/quaternion.hpp" 26 | #include "glm/gtx/norm.hpp" 27 | #include "glm/gtx/intersect.hpp" 28 | 29 | #include "pugixml.hpp" 30 | #include "JoyShockLibrary.h" 31 | -------------------------------------------------------------------------------- /leap_control/Core/CCore.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Core/CCore.h" 3 | #include "Managers/COpenGLManager.h" 4 | #include "Managers/CVRManager.h" 5 | #include "Managers/COverlayManager.h" 6 | #include "Managers/CLeapManager.h" 7 | #include "Managers/CSettingsManager.h" 8 | #include "Ui/leap_control.h" 9 | 10 | CCore::CCore(int &argc, char **argv) : QApplication(argc, argv) 11 | { 12 | m_window = nullptr; 13 | m_timer = nullptr; 14 | } 15 | 16 | void CCore::Launch() 17 | { 18 | CSettingsManager::GetInstance()->Load(); 19 | 20 | if(!CLeapManager::GetInstance()->Init()) 21 | return; 22 | if(!COpenGLManager::GetInstance()->Init()) 23 | return; 24 | if(!CVRManager::GetInstance()->Init()) 25 | return; 26 | 27 | COverlayManager::GetInstance()->CreateOverlays(); 28 | 29 | m_window = new leap_control(); 30 | if(!CSettingsManager::GetInstance()->GetStartMinimized()) 31 | m_window->show(); 32 | 33 | m_timer = new QTimer(this); 34 | connect(m_timer, &QTimer::timeout, this, &CCore::UpdateLoop); 35 | m_timer->start(16); // 60 FPS lesgo! 36 | 37 | QApplication::exec(); 38 | 39 | m_timer->stop(); 40 | delete m_timer; 41 | m_timer = nullptr; 42 | 43 | delete m_window; 44 | m_window = nullptr; 45 | 46 | COverlayManager::GetInstance()->DestroyOverlays(); 47 | CVRManager::GetInstance()->Terminate(); 48 | COpenGLManager::GetInstance()->Terminate(); 49 | CLeapManager::GetInstance()->Terminate(); 50 | CSettingsManager::GetInstance()->Save(); 51 | } 52 | 53 | void CCore::UpdateLoop() 54 | { 55 | CVRManager::GetInstance()->Update(); 56 | if(CVRManager::GetInstance()->IsExitPolled()) 57 | m_window->close(); 58 | CLeapManager::GetInstance()->Update(); 59 | COverlayManager::GetInstance()->Update(); 60 | } 61 | -------------------------------------------------------------------------------- /leap_control/Core/CCore.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class leap_control; 4 | 5 | class CCore : public QApplication 6 | { 7 | leap_control *m_window; 8 | QTimer *m_timer; 9 | 10 | CCore(const CCore &that) = delete; 11 | CCore& operator=(const CCore &that) = delete; 12 | 13 | void UpdateLoop(); 14 | public: 15 | CCore(int &argc, char **argv); 16 | ~CCore() = default; 17 | 18 | void Launch(); 19 | }; 20 | 21 | -------------------------------------------------------------------------------- /leap_control/Leap/CLeapPoller.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Leap/CLeapPoller.h" 3 | 4 | CLeapPoller::CLeapPoller() 5 | { 6 | m_isRunning = false; 7 | m_thread = nullptr; 8 | m_connection = nullptr; 9 | m_frame = new LEAP_TRACKING_EVENT(); 10 | m_devicesCount = 0; 11 | } 12 | 13 | CLeapPoller::~CLeapPoller() 14 | { 15 | delete m_frame; 16 | } 17 | 18 | void CLeapPoller::Start() 19 | { 20 | if(m_isRunning) 21 | return; 22 | if(LeapCreateConnection(nullptr, &m_connection) != eLeapRS::eLeapRS_Success) 23 | return; 24 | if(LeapOpenConnection(m_connection) != eLeapRS::eLeapRS_Success) 25 | return; 26 | 27 | m_isRunning = true; 28 | m_thread = new std::thread(&CLeapPoller::PollThread, this); 29 | } 30 | 31 | void CLeapPoller::Stop() 32 | { 33 | if(!m_isRunning) 34 | return; 35 | 36 | m_isRunning = false; 37 | LeapCloseConnection(m_connection); 38 | 39 | m_thread->join(); 40 | m_thread = nullptr; 41 | 42 | LeapDestroyConnection(m_connection); 43 | m_connection = nullptr; 44 | 45 | m_devicesCount = 0; 46 | } 47 | 48 | bool CLeapPoller::IsConnected() const 49 | { 50 | return (m_isRunning && (m_devicesCount > 0)); 51 | } 52 | 53 | bool CLeapPoller::GetFrame(LEAP_TRACKING_EVENT *p_target) 54 | { 55 | if(!m_isRunning) 56 | return false; 57 | 58 | if(!m_frameLock.try_lock()) 59 | return false; 60 | 61 | std::memcpy(p_target, m_frame, sizeof(LEAP_TRACKING_EVENT)); 62 | m_frameLock.unlock(); 63 | return true; 64 | } 65 | 66 | #ifndef LEAP_ORION 67 | void CLeapPoller::SetTrackingMode(eLeapTrackingMode p_mode) 68 | { 69 | if(m_isRunning) 70 | LeapSetTrackingMode(m_connection, p_mode); 71 | } 72 | #endif 73 | 74 | void CLeapPoller::SetPolicy(uint64_t p_set, uint64_t p_clear) 75 | { 76 | if(m_isRunning) 77 | LeapSetPolicyFlags(m_connection, p_set, p_clear); 78 | } 79 | 80 | void CLeapPoller::PollThread() 81 | { 82 | while(m_isRunning) 83 | { 84 | LEAP_CONNECTION_MESSAGE l_message{ sizeof(LEAP_CONNECTION_MESSAGE) }; 85 | if(LeapPollConnection(m_connection, 150U, &l_message) != eLeapRS::eLeapRS_Success) 86 | continue; 87 | 88 | switch(l_message.type) 89 | { 90 | case eLeapEventType_None: 91 | break; 92 | 93 | case eLeapEventType_Connection: 94 | OnConnectionEvent(); 95 | break; 96 | 97 | case eLeapEventType_ConnectionLost: 98 | OnConnectionLostEvent(); 99 | break; 100 | 101 | case eLeapEventType_Device: 102 | OnDeviceEvent(l_message.device_event); 103 | break; 104 | 105 | case eLeapEventType_DeviceLost: 106 | OnDeviceLostEvent(l_message.device_event); 107 | break; 108 | 109 | case eLeapEventType_Tracking: 110 | OnTrackingEvent(l_message.tracking_event); 111 | break; 112 | } 113 | } 114 | } 115 | 116 | void CLeapPoller::OnConnectionEvent() 117 | { 118 | } 119 | 120 | void CLeapPoller::OnConnectionLostEvent() 121 | { 122 | m_devicesCount = 0U; 123 | } 124 | 125 | void CLeapPoller::OnDeviceEvent(const LEAP_DEVICE_EVENT* p_event) 126 | { 127 | if(!p_event->device.handle) 128 | return; 129 | 130 | LEAP_DEVICE l_device; 131 | if(LeapOpenDevice(p_event->device, &l_device) != eLeapRS_Success) 132 | return; 133 | 134 | m_devicesCount++; 135 | } 136 | 137 | void CLeapPoller::OnDeviceLostEvent(const LEAP_DEVICE_EVENT *p_event) 138 | { 139 | m_devicesCount--; 140 | } 141 | 142 | void CLeapPoller::OnTrackingEvent(const LEAP_TRACKING_EVENT *p_event) 143 | { 144 | m_frameLock.lock(); 145 | std::memcpy(m_frame, p_event, sizeof(LEAP_TRACKING_EVENT)); 146 | m_frameLock.unlock(); 147 | } 148 | -------------------------------------------------------------------------------- /leap_control/Leap/CLeapPoller.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CLeapPoller 4 | { 5 | std::atomic m_isRunning; 6 | std::mutex m_frameLock; 7 | std::thread *m_thread; 8 | 9 | LEAP_CONNECTION m_connection; 10 | std::atomic m_devicesCount; 11 | LEAP_TRACKING_EVENT *m_frame; 12 | 13 | // Async methods 14 | void PollThread(); 15 | void OnConnectionEvent(); 16 | void OnConnectionLostEvent(); 17 | void OnDeviceEvent(const LEAP_DEVICE_EVENT* p_event); 18 | void OnDeviceLostEvent(const LEAP_DEVICE_EVENT *p_event); 19 | void OnTrackingEvent(const LEAP_TRACKING_EVENT* p_event); 20 | public: 21 | CLeapPoller(); 22 | ~CLeapPoller(); 23 | 24 | void Start(); 25 | void Stop(); 26 | 27 | bool IsConnected() const; 28 | bool GetFrame(LEAP_TRACKING_EVENT *p_target); 29 | 30 | void SetPolicy(uint64_t p_set, uint64_t p_clear = 0U); 31 | #ifndef LEAP_ORION 32 | void SetTrackingMode(eLeapTrackingMode p_mode); 33 | #endif 34 | }; 35 | 36 | 37 | -------------------------------------------------------------------------------- /leap_control/Managers/CLeapManager.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Managers/CLeapManager.h" 3 | #include "Managers/CSettingsManager.h" 4 | #include "Managers/CVRManager.h" 5 | #include "Leap/CLeapPoller.h" 6 | 7 | const glm::mat4 g_identityMat4(1.f); 8 | const glm::vec4 g_pointVec4(0.f, 0.f, 0.f, 1.f); 9 | 10 | CLeapManager* CLeapManager::ms_instance = nullptr; 11 | 12 | CLeapManager* CLeapManager::GetInstance() 13 | { 14 | if(!ms_instance) 15 | ms_instance = new CLeapManager(); 16 | 17 | return ms_instance; 18 | } 19 | 20 | CLeapManager::CLeapManager() 21 | { 22 | m_leapPoller = nullptr; 23 | m_trackingEvent = new LEAP_TRACKING_EVENT(); 24 | m_leftIndexTipPosition = glm::vec3(0.f); 25 | m_rightIndexTipPosition = glm::vec3(0.f); 26 | m_leftHandVisible = false; 27 | m_rightHandVisible = false; 28 | } 29 | CLeapManager::~CLeapManager() 30 | { 31 | delete m_trackingEvent; 32 | } 33 | 34 | bool CLeapManager::Init() 35 | { 36 | if(!m_leapPoller) 37 | { 38 | m_leapPoller = new CLeapPoller(); 39 | m_leapPoller->Start(); 40 | } 41 | return (m_leapPoller != nullptr); 42 | } 43 | 44 | void CLeapManager::Terminate() 45 | { 46 | if(m_leapPoller) 47 | { 48 | m_leapPoller->Stop(); 49 | delete m_leapPoller; 50 | m_leapPoller = nullptr; 51 | } 52 | } 53 | 54 | void CLeapManager::Update() 55 | { 56 | if(m_leapPoller && m_leapPoller->GetFrame(m_trackingEvent)) 57 | { 58 | m_leftHandVisible = false; 59 | m_rightHandVisible = false; 60 | 61 | for(uint32_t i = 0U; i < m_trackingEvent->nHands; i++) 62 | { 63 | switch(m_trackingEvent->pHands[i].type) 64 | { 65 | case eLeapHandType_Left: 66 | { 67 | if(!m_leftHandVisible) 68 | { 69 | ConvertPosition(m_trackingEvent->pHands[i].index.distal.next_joint, m_leftIndexTipPosition); 70 | m_leftHandVisible = true; 71 | } 72 | } break; 73 | case eLeapHandType_Right: 74 | { 75 | if(!m_rightHandVisible) 76 | { 77 | ConvertPosition(m_trackingEvent->pHands[i].index.distal.next_joint, m_rightIndexTipPosition); 78 | m_rightHandVisible = true; 79 | } 80 | } break; 81 | } 82 | } 83 | 84 | if(m_leftHandVisible || m_rightHandVisible) 85 | { 86 | glm::mat4 l_rootMat = glm::translate(g_identityMat4, CSettingsManager::GetInstance()->GetRootOffset()); 87 | l_rootMat *= glm::toMat4(glm::quat(glm::radians(CSettingsManager::GetInstance()->GetRootAngle()))); 88 | l_rootMat = CVRManager::GetInstance()->GetHmdMatrix() * l_rootMat; 89 | 90 | if(m_leftHandVisible) 91 | { 92 | glm::mat4 l_tipMat = l_rootMat * glm::translate(g_identityMat4, m_leftIndexTipPosition); 93 | m_leftIndexTipPosition = l_tipMat * g_pointVec4; 94 | } 95 | if(m_rightHandVisible) 96 | { 97 | glm::mat4 l_tipMat = l_rootMat * glm::translate(g_identityMat4, m_rightIndexTipPosition); 98 | m_rightIndexTipPosition = l_tipMat * g_pointVec4; 99 | } 100 | } 101 | } 102 | } 103 | 104 | const glm::vec3 & CLeapManager::GetLeftIndexTipPosition() const 105 | { 106 | return m_leftIndexTipPosition; 107 | } 108 | const glm::vec3 & CLeapManager::GetRightIndexTipPosition() const 109 | { 110 | return m_rightIndexTipPosition; 111 | } 112 | 113 | bool CLeapManager::IsLeftHandVisible() const 114 | { 115 | return m_leftHandVisible; 116 | } 117 | 118 | bool CLeapManager::IsRightHandVisible() const 119 | { 120 | return m_rightHandVisible; 121 | } 122 | 123 | void CLeapManager::ConvertPosition(const LEAP_VECTOR & p_src, glm::vec3 & p_dst) 124 | { 125 | // In desktop mode: +X - right, +Y - up, -Z - forward (as OpenGL) 126 | // In HMD mode: -X - right, +Y - forward, -Z - up (same basis, just rotated) 127 | p_dst.x = -0.001f * p_src.x; 128 | p_dst.y = -0.001f * p_src.z; 129 | p_dst.z = -0.001f * p_src.y; 130 | } 131 | -------------------------------------------------------------------------------- /leap_control/Managers/CLeapManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CLeapPoller; 4 | class CLeapManager 5 | { 6 | static CLeapManager* ms_instance; 7 | 8 | CLeapPoller *m_leapPoller; 9 | LEAP_TRACKING_EVENT *m_trackingEvent; 10 | 11 | glm::vec3 m_leftIndexTipPosition; 12 | glm::vec3 m_rightIndexTipPosition; 13 | 14 | bool m_leftHandVisible; 15 | bool m_rightHandVisible; 16 | 17 | CLeapManager(); 18 | CLeapManager(const CLeapManager &that) = delete; 19 | CLeapManager& operator=(const CLeapManager &that) = delete; 20 | ~CLeapManager(); 21 | public: 22 | static CLeapManager* GetInstance(); 23 | 24 | bool Init(); 25 | void Terminate(); 26 | 27 | void Update(); 28 | 29 | const glm::vec3& GetLeftIndexTipPosition() const; 30 | const glm::vec3& GetRightIndexTipPosition() const; 31 | 32 | bool IsLeftHandVisible() const; 33 | bool IsRightHandVisible() const; 34 | 35 | static void ConvertPosition(const LEAP_VECTOR & p_src, glm::vec3 & p_dst); 36 | }; 37 | -------------------------------------------------------------------------------- /leap_control/Managers/COpenGLManager.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Managers/COpenGLManager.h" 3 | 4 | COpenGLManager* COpenGLManager::ms_instance = nullptr; 5 | 6 | COpenGLManager* COpenGLManager::GetInstance() 7 | { 8 | if(!ms_instance) 9 | ms_instance = new COpenGLManager(); 10 | 11 | return ms_instance; 12 | } 13 | 14 | COpenGLManager::COpenGLManager() 15 | { 16 | m_glContext = nullptr; 17 | } 18 | 19 | bool COpenGLManager::Init() 20 | { 21 | if(!m_glContext) 22 | { 23 | QSurfaceFormat l_format; 24 | l_format.setMajorVersion(4); 25 | l_format.setMinorVersion(1); 26 | l_format.setProfile(QSurfaceFormat::CoreProfile); 27 | l_format.setRenderableType(QSurfaceFormat::RenderableType::OpenGL); 28 | l_format.setAlphaBufferSize(8); 29 | 30 | m_glContext = new QOpenGLContext(); 31 | m_glContext->setFormat(l_format); 32 | if(!m_glContext->create()) 33 | { 34 | delete m_glContext; 35 | m_glContext = nullptr; 36 | 37 | QMessageBox::critical(nullptr, "Leap Control", "Unable to create OpenGL 4.1 Core context"); 38 | } 39 | } 40 | 41 | return (m_glContext != nullptr); 42 | } 43 | 44 | void COpenGLManager::Terminate() 45 | { 46 | if(m_glContext) 47 | { 48 | delete m_glContext; 49 | m_glContext = nullptr; 50 | } 51 | } 52 | 53 | QOpenGLContext* COpenGLManager::GetContext() const 54 | { 55 | return m_glContext; 56 | } 57 | -------------------------------------------------------------------------------- /leap_control/Managers/COpenGLManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class COpenGLManager 4 | { 5 | static COpenGLManager* ms_instance; 6 | 7 | QOpenGLContext *m_glContext; 8 | 9 | COpenGLManager(); 10 | COpenGLManager(const COpenGLManager &that) = delete; 11 | COpenGLManager& operator=(const COpenGLManager &that) = delete; 12 | ~COpenGLManager() = default; 13 | public: 14 | static COpenGLManager* GetInstance(); 15 | 16 | QOpenGLContext* GetContext() const; 17 | 18 | bool Init(); 19 | void Terminate(); 20 | }; 21 | 22 | -------------------------------------------------------------------------------- /leap_control/Managers/COverlayManager.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Managers/COverlayManager.h" 3 | #include "Managers/CVRManager.h" 4 | #include "Managers/CLeapManager.h" 5 | #include "Managers/CSettingsManager.h" 6 | #include "Overlay/CHandOverlay.h" 7 | #include "Overlay/CCursorOverlay.h" 8 | #include "Utils/CButton.h" 9 | #include "Utils/Utils.h" 10 | 11 | const glm::mat4 g_identityMat4(1.f); 12 | const glm::vec4 g_pointVec4(0.f, 0.f, 0.f, 1.f); 13 | 14 | COverlayManager* COverlayManager::ms_instance = nullptr; 15 | 16 | COverlayManager* COverlayManager::GetInstance() 17 | { 18 | if(!ms_instance) 19 | ms_instance = new COverlayManager(); 20 | 21 | return ms_instance; 22 | } 23 | 24 | COverlayManager::COverlayManager() 25 | { 26 | m_leftHandOverlay = nullptr; 27 | m_rightHandOverlay = nullptr; 28 | m_leftCursorOverlay = nullptr; 29 | m_rightCursorOverlay = nullptr; 30 | } 31 | 32 | void COverlayManager::CreateOverlays() 33 | { 34 | if(!m_leftHandOverlay) 35 | { 36 | m_leftHandOverlay = new CHandOverlay(true); 37 | m_leftHandOverlay->Create(); 38 | m_leftHandOverlay->SetWidth(CSettingsManager::GetInstance()->GetOverlaySize()); 39 | m_leftHandOverlay->SetVisible(CSettingsManager::GetInstance()->GetShowOverlays()); 40 | } 41 | if(!m_rightHandOverlay) 42 | { 43 | m_rightHandOverlay = new CHandOverlay(false); 44 | m_rightHandOverlay->Create(); 45 | m_rightHandOverlay->SetWidth(CSettingsManager::GetInstance()->GetOverlaySize()); 46 | m_rightHandOverlay->SetVisible(CSettingsManager::GetInstance()->GetShowOverlays()); 47 | } 48 | 49 | if(!m_leftCursorOverlay) 50 | { 51 | m_leftCursorOverlay = new CCursorOverlay(true); 52 | m_leftCursorOverlay->Create(); 53 | } 54 | if(!m_rightCursorOverlay) 55 | { 56 | m_rightCursorOverlay = new CCursorOverlay(false); 57 | m_rightCursorOverlay->Create(); 58 | } 59 | } 60 | 61 | void COverlayManager::DestroyOverlays() 62 | { 63 | if(m_leftHandOverlay) 64 | { 65 | m_leftHandOverlay->Destroy(); 66 | delete m_leftHandOverlay; 67 | m_leftHandOverlay = nullptr; 68 | } 69 | if(m_rightHandOverlay) 70 | { 71 | m_rightHandOverlay->Destroy(); 72 | delete m_rightHandOverlay; 73 | m_rightHandOverlay = nullptr; 74 | } 75 | 76 | if(m_leftCursorOverlay) 77 | { 78 | m_leftCursorOverlay->Destroy(); 79 | delete m_leftCursorOverlay; 80 | m_leftCursorOverlay = nullptr; 81 | } 82 | if(m_rightCursorOverlay) 83 | { 84 | m_rightCursorOverlay->Destroy(); 85 | delete m_rightCursorOverlay; 86 | m_rightCursorOverlay = nullptr; 87 | } 88 | } 89 | 90 | void COverlayManager::Update() 91 | { 92 | glm::quat l_hmdRot = CVRManager::GetInstance()->GetHmdRotation(); 93 | 94 | if(m_leftCursorOverlay) 95 | { 96 | m_leftCursorOverlay->SetPosition(CLeapManager::GetInstance()->GetLeftIndexTipPosition()); 97 | m_leftCursorOverlay->SetRotation(l_hmdRot); 98 | m_leftCursorOverlay->Update(); 99 | } 100 | if(m_rightCursorOverlay) 101 | { 102 | m_rightCursorOverlay->SetPosition(CLeapManager::GetInstance()->GetRightIndexTipPosition()); 103 | m_rightCursorOverlay->SetRotation(l_hmdRot); 104 | m_rightCursorOverlay->Update(); 105 | } 106 | 107 | if(m_leftHandOverlay) 108 | { 109 | if(m_rightHandOverlay) 110 | m_leftHandOverlay->SetLocked(m_rightHandOverlay->IsInteracted()); 111 | 112 | glm::mat4 l_overlayMat = glm::translate(g_identityMat4, CSettingsManager::GetInstance()->GetOverlayOffset()); 113 | glm::vec3 l_pos = CSettingsManager::GetInstance()->GetOverlayAngle(); 114 | l_overlayMat *= glm::toMat4(glm::quat(glm::radians(l_pos))); 115 | l_overlayMat = CVRManager::GetInstance()->GetLeftHandMatrix() * l_overlayMat; 116 | l_pos = l_overlayMat * g_pointVec4; 117 | glm::quat l_rot = glm::toQuat(l_overlayMat); 118 | m_leftHandOverlay->SetPosition(l_pos); 119 | m_leftHandOverlay->SetRotation(l_rot); 120 | m_leftHandOverlay->Update(CLeapManager::GetInstance()->GetRightIndexTipPosition()); 121 | 122 | ProcessButtons(m_leftHandOverlay->GetButtons(), m_leftHandOverlay->GetPressure(), true); 123 | } 124 | if(m_rightHandOverlay) 125 | { 126 | if(m_leftHandOverlay) 127 | m_rightHandOverlay->SetLocked(m_leftHandOverlay->IsInteracted()); 128 | 129 | glm::vec3 l_pos = CSettingsManager::GetInstance()->GetOverlayOffset(); 130 | l_pos.x *= -1.f; 131 | glm::mat4 l_overlayMat = glm::translate(g_identityMat4, l_pos); 132 | l_pos = CSettingsManager::GetInstance()->GetOverlayAngle(); 133 | l_pos.y *= -1.f; 134 | l_pos.z *= -1.f; 135 | l_overlayMat *= glm::toMat4(glm::quat(glm::radians(l_pos))); 136 | l_overlayMat = CVRManager::GetInstance()->GetRightHandMatrix() * l_overlayMat; 137 | l_pos = l_overlayMat * g_pointVec4; 138 | glm::quat l_rot = glm::toQuat(l_overlayMat); 139 | m_rightHandOverlay->SetPosition(l_pos); 140 | m_rightHandOverlay->SetRotation(l_rot); 141 | m_rightHandOverlay->Update(CLeapManager::GetInstance()->GetLeftIndexTipPosition()); 142 | 143 | ProcessButtons(m_rightHandOverlay->GetButtons(), m_leftHandOverlay->GetPressure(), false); 144 | } 145 | } 146 | 147 | void COverlayManager::SetOverlaysWidth(float p_width) 148 | { 149 | if(m_leftHandOverlay) 150 | m_leftHandOverlay->SetWidth(p_width); 151 | if(m_rightHandOverlay) 152 | m_rightHandOverlay->SetWidth(p_width); 153 | } 154 | 155 | void COverlayManager::SetOverlaysActive(bool p_state) 156 | { 157 | if(m_leftHandOverlay) 158 | { 159 | m_leftHandOverlay->SetVisible(p_state); 160 | if(!p_state) 161 | m_leftHandOverlay->ResetInput(); 162 | } 163 | if(m_rightHandOverlay) 164 | { 165 | m_rightHandOverlay->SetVisible(p_state); 166 | if(!p_state) 167 | m_rightHandOverlay->ResetInput(); 168 | } 169 | } 170 | 171 | void COverlayManager::ProcessButtons(const std::vector &p_buttons, float p_pressure, bool p_left) const 172 | { 173 | for(auto l_button : p_buttons) 174 | { 175 | if(l_button->IsUpdated()) 176 | { 177 | std::string l_message("input "); 178 | switch(l_button->GetType()) 179 | { 180 | case CButton::BT_Button: 181 | l_message.append("button "); 182 | break; 183 | case CButton::BT_Axis: 184 | l_message.append("axis "); 185 | break; 186 | } 187 | 188 | l_message.append(l_button->GetName()); 189 | l_message.push_back(' '); 190 | 191 | switch(l_button->GetState()) 192 | { 193 | case CButton::BS_None: 194 | l_message.append("none "); 195 | break; 196 | case CButton::BS_Touched: 197 | l_message.append("touched "); 198 | break; 199 | case CButton::BS_Clicked: 200 | l_message.append("clicked "); 201 | break; 202 | } 203 | 204 | if(l_button->GetType() == CButton::BT_Axis) 205 | { 206 | const glm::vec2 &l_axis = l_button->GetAxis(); 207 | l_message.append(std::to_string(l_axis.x)); 208 | l_message.push_back(' '); 209 | l_message.append(std::to_string(l_axis.y)); 210 | l_message.push_back(' '); 211 | l_message.append(std::to_string(p_pressure)); 212 | } 213 | 214 | if(p_left) 215 | CVRManager::GetInstance()->SendLeftControllerMessage(l_message); 216 | else 217 | CVRManager::GetInstance()->SendRightControllerMessage(l_message); 218 | } 219 | } 220 | } 221 | -------------------------------------------------------------------------------- /leap_control/Managers/COverlayManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CHandOverlay; 4 | class CCursorOverlay; 5 | class CButton; 6 | class COverlayManager 7 | { 8 | static COverlayManager* ms_instance; 9 | 10 | CHandOverlay *m_leftHandOverlay; 11 | CHandOverlay *m_rightHandOverlay; 12 | 13 | CCursorOverlay *m_leftCursorOverlay; 14 | CCursorOverlay *m_rightCursorOverlay; 15 | 16 | COverlayManager(); 17 | COverlayManager(const COverlayManager &that) = delete; 18 | COverlayManager& operator=(const COverlayManager &that) = delete; 19 | ~COverlayManager() = default; 20 | 21 | void ProcessButtons(const std::vector &p_buttons, float p_pressure, bool p_left) const; 22 | public: 23 | static COverlayManager* GetInstance(); 24 | 25 | void CreateOverlays(); 26 | void DestroyOverlays(); 27 | 28 | void Update(); 29 | 30 | void SetOverlaysWidth(float p_width); 31 | void SetOverlaysActive(bool p_state); 32 | }; 33 | 34 | -------------------------------------------------------------------------------- /leap_control/Managers/CSettingsManager.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Managers/CSettingsManager.h" 3 | #include "Utils/Utils.h" 4 | 5 | const std::vector g_settingNames 6 | { 7 | "trackingLevel", 8 | "handsReset", 9 | "useVelocity", 10 | "dashboardSmooth", 11 | "startMinimized", 12 | "useTriggerGrip", 13 | "triggerMode", 14 | "triggerThreshold", 15 | "gripThreshold", 16 | "pinchLimitMin", 17 | "pinchLimitMax", 18 | "useControllerInput", 19 | "rootOffsetX", 20 | "rootOffsetY", 21 | "rootOffsetZ", 22 | "rootAngleX", 23 | "rootAngleY", 24 | "rootAngleZ", 25 | "showOverlays", 26 | "overlaySize", 27 | "overlayOffsetX", 28 | "overlayOffsetY", 29 | "overlayOffsetZ", 30 | "overlayAngleX", 31 | "overlayAngleY", 32 | "overlayAngleZ" 33 | }; 34 | 35 | CSettingsManager* CSettingsManager::ms_instance = nullptr; 36 | 37 | CSettingsManager::CSettingsManager() 38 | { 39 | m_trackingLevel = TL_Full; 40 | m_handsReset = false; 41 | m_useVelocity = false; 42 | m_dashboardSmooth = 1.f; 43 | m_startMinimized = false; 44 | m_useTriggerGrip = true; 45 | m_triggerMode = TM_FingerBend; 46 | m_triggerThreshold = 0.75f; 47 | m_gripThreshold = 0.75f; 48 | m_pinchLimits = glm::vec2(0.02f, 0.05f); 49 | m_useControllerInput = false; 50 | m_rootOffset = glm::vec3(0.f); 51 | m_rootAngle = glm::vec3(0.f); 52 | m_showOverlays = true; 53 | m_overlaySize = 0.128f; 54 | m_overlayOffset = glm::vec3(0.f); 55 | m_overlayAngle = glm::vec3(0.f); 56 | } 57 | 58 | CSettingsManager* CSettingsManager::GetInstance() 59 | { 60 | if(!ms_instance) 61 | ms_instance = new CSettingsManager(); 62 | 63 | return ms_instance; 64 | } 65 | 66 | void CSettingsManager::Load() 67 | { 68 | std::wstring l_path(QApplication::applicationDirPath().toStdWString()); 69 | l_path.append(L"/../../../resources/settings.xml"); 70 | 71 | pugi::xml_document l_document; 72 | if(l_document.load_file(l_path.c_str())) 73 | { 74 | const pugi::xml_node l_root = l_document.child("settings"); 75 | if(l_root) 76 | { 77 | for(pugi::xml_node l_node = l_root.child("setting"); l_node; l_node = l_node.next_sibling("setting")) 78 | { 79 | const pugi::xml_attribute l_attribName = l_node.attribute("name"); 80 | const pugi::xml_attribute l_attribValue = l_node.attribute("value"); 81 | if(l_attribName && l_attribValue) 82 | { 83 | switch(ReadEnumVector(l_attribName.as_string(), g_settingNames)) 84 | { 85 | case ST_TrackingLevel: 86 | m_trackingLevel = glm::clamp(l_attribValue.as_int(TL_Full), TL_Partial, TL_Full); 87 | break; 88 | 89 | case ST_HandsReset: 90 | m_handsReset = l_attribValue.as_bool(false); 91 | break; 92 | 93 | case ST_UseVelocity: 94 | m_useVelocity = l_attribValue.as_bool(false); 95 | break; 96 | 97 | case ST_DashboardSmooth: 98 | m_dashboardSmooth = l_attribValue.as_float(1.f); 99 | break; 100 | 101 | case ST_StartMinimized: 102 | m_startMinimized = l_attribValue.as_bool(false); 103 | break; 104 | 105 | case ST_UseTriggerGrip: 106 | m_useTriggerGrip = l_attribValue.as_bool(true); 107 | break; 108 | 109 | case ST_TriggerMode: 110 | m_triggerMode = glm::clamp(l_attribValue.as_int(TM_FingerBend), TM_FingerBend, TM_Pinch); 111 | break; 112 | 113 | case ST_TriggerThreshold: 114 | m_triggerThreshold = glm::clamp(l_attribValue.as_float(0.75f), 0.1f, 1.f); 115 | break; 116 | 117 | case ST_GripThreshold: 118 | m_gripThreshold = glm::clamp(l_attribValue.as_float(0.75f), 0.1f, 1.f); 119 | break; 120 | 121 | case ST_PinchLimitMin: 122 | m_pinchLimits.x = glm::clamp(l_attribValue.as_float(0.02f), 0.01f, 0.1f); 123 | break; 124 | 125 | case ST_PinchLimitMax: 126 | m_pinchLimits.y = glm::clamp(l_attribValue.as_float(0.02f), 0.01f, 0.1f); 127 | break; 128 | 129 | case ST_UseControllerInput: 130 | m_useControllerInput = l_attribValue.as_bool(false); 131 | break; 132 | 133 | case ST_RootOffsetX: 134 | m_rootOffset.x = glm::clamp(l_attribValue.as_float(0.f), -1.f, 1.f); 135 | break; 136 | 137 | case ST_RootOffsetY: 138 | m_rootOffset.y = glm::clamp(l_attribValue.as_float(0.f), -1.f, 1.f); 139 | break; 140 | 141 | case ST_RootOffsetZ: 142 | m_rootOffset.z = glm::clamp(l_attribValue.as_float(0.f), -1.f, 1.f); 143 | break; 144 | 145 | case ST_RootAngleX: 146 | m_rootAngle.x = glm::clamp(l_attribValue.as_float(0.f), -180.f, 180.f); 147 | break; 148 | 149 | case ST_RootAngleY: 150 | m_rootAngle.y = glm::clamp(l_attribValue.as_float(0.f), -180.f, 180.f); 151 | break; 152 | 153 | case ST_RootAngleZ: 154 | m_rootAngle.z = glm::clamp(l_attribValue.as_float(0.f), -180.f, 180.f); 155 | break; 156 | 157 | case ST_ShowOverlays: 158 | m_showOverlays = l_attribValue.as_bool(true); 159 | break; 160 | 161 | case ST_OverlaySize: 162 | m_overlaySize = glm::clamp(l_attribValue.as_float(0.128f), 0.1f, 0.5f); 163 | break; 164 | 165 | case ST_OverlayOffsetX: 166 | m_overlayOffset.x = glm::clamp(l_attribValue.as_float(0.f), -0.5f, 0.5f); 167 | break; 168 | 169 | case ST_OverlayOffsetY: 170 | m_overlayOffset.y = glm::clamp(l_attribValue.as_float(0.f), -0.5f, 0.5f); 171 | break; 172 | 173 | case ST_OverlayOffsetZ: 174 | m_overlayOffset.z = glm::clamp(l_attribValue.as_float(0.f), -0.5f, 0.5f); 175 | break; 176 | 177 | case ST_OverlayAngleX: 178 | m_overlayAngle.x = glm::clamp(l_attribValue.as_float(0.f), -180.f, 180.f); 179 | break; 180 | 181 | case ST_OverlayAngleY: 182 | m_overlayAngle.y = glm::clamp(l_attribValue.as_float(0.f), -180.f, 180.f); 183 | break; 184 | 185 | case ST_OverlayAngleZ: 186 | m_overlayAngle.z = glm::clamp(l_attribValue.as_float(0.f), -180.f, 180.f); 187 | break; 188 | } 189 | } 190 | } 191 | } 192 | } 193 | } 194 | 195 | void CSettingsManager::Save() 196 | { 197 | std::wstring l_path(QApplication::applicationDirPath().toStdWString()); 198 | l_path.append(L"/../../../resources/settings.xml"); 199 | 200 | pugi::xml_document l_document; 201 | auto l_root = l_document.append_child("settings"); 202 | for(size_t i = 0U; i < SettingType::Count; i++) 203 | { 204 | auto l_node = l_root.append_child("setting"); 205 | auto l_nameAttrib = l_node.append_attribute("name"); 206 | l_nameAttrib.set_value(g_settingNames[i].c_str()); 207 | 208 | auto l_valueAttrib = l_node.append_attribute("value"); 209 | switch(i) 210 | { 211 | case ST_TrackingLevel: 212 | l_valueAttrib.set_value(m_trackingLevel); 213 | break; 214 | 215 | case ST_HandsReset: 216 | l_valueAttrib.set_value(m_handsReset); 217 | break; 218 | 219 | case ST_UseVelocity: 220 | l_valueAttrib.set_value(m_useVelocity); 221 | break; 222 | 223 | case ST_DashboardSmooth: 224 | l_valueAttrib.set_value(m_dashboardSmooth); 225 | break; 226 | 227 | case ST_StartMinimized: 228 | l_valueAttrib.set_value(m_startMinimized); 229 | break; 230 | 231 | case ST_UseTriggerGrip: 232 | l_valueAttrib.set_value(m_useTriggerGrip); 233 | break; 234 | 235 | case ST_TriggerMode: 236 | l_valueAttrib.set_value(m_triggerMode); 237 | break; 238 | 239 | case ST_TriggerThreshold: 240 | l_valueAttrib.set_value(m_triggerThreshold); 241 | break; 242 | 243 | case ST_GripThreshold: 244 | l_valueAttrib.set_value(m_gripThreshold); 245 | break; 246 | 247 | case ST_PinchLimitMin: 248 | l_valueAttrib.set_value(m_pinchLimits.x); 249 | break; 250 | 251 | case ST_PinchLimitMax: 252 | l_valueAttrib.set_value(m_pinchLimits.y); 253 | break; 254 | 255 | case ST_UseControllerInput: 256 | l_valueAttrib.set_value(m_useControllerInput); 257 | break; 258 | 259 | case ST_RootOffsetX: 260 | l_valueAttrib.set_value(m_rootOffset.x); 261 | break; 262 | 263 | case ST_RootOffsetY: 264 | l_valueAttrib.set_value(m_rootOffset.y); 265 | break; 266 | 267 | case ST_RootOffsetZ: 268 | l_valueAttrib.set_value(m_rootOffset.z); 269 | break; 270 | 271 | case ST_RootAngleX: 272 | l_valueAttrib.set_value(m_rootAngle.x); 273 | break; 274 | 275 | case ST_RootAngleY: 276 | l_valueAttrib.set_value(m_rootAngle.y); 277 | break; 278 | 279 | case ST_RootAngleZ: 280 | l_valueAttrib.set_value(m_rootAngle.z); 281 | break; 282 | 283 | case ST_ShowOverlays: 284 | l_valueAttrib.set_value(m_showOverlays); 285 | break; 286 | 287 | case ST_OverlaySize: 288 | l_valueAttrib.set_value(m_overlaySize); 289 | break; 290 | 291 | case ST_OverlayOffsetX: 292 | l_valueAttrib.set_value(m_overlayOffset.x); 293 | break; 294 | 295 | case ST_OverlayOffsetY: 296 | l_valueAttrib.set_value(m_overlayOffset.y); 297 | break; 298 | 299 | case ST_OverlayOffsetZ: 300 | l_valueAttrib.set_value(m_overlayOffset.z); 301 | break; 302 | 303 | case ST_OverlayAngleX: 304 | l_valueAttrib.set_value(m_overlayAngle.x); 305 | break; 306 | 307 | case ST_OverlayAngleY: 308 | l_valueAttrib.set_value(m_overlayAngle.y); 309 | break; 310 | 311 | case ST_OverlayAngleZ: 312 | l_valueAttrib.set_value(m_overlayAngle.z); 313 | break; 314 | } 315 | } 316 | 317 | l_document.save_file(l_path.c_str()); 318 | } 319 | 320 | int CSettingsManager::GetTrackingLevel() const 321 | { 322 | return m_trackingLevel; 323 | } 324 | 325 | bool CSettingsManager::GetHandsReset() const 326 | { 327 | return m_handsReset; 328 | } 329 | 330 | bool CSettingsManager::GetUseVelocity() const 331 | { 332 | return m_useVelocity; 333 | } 334 | 335 | float CSettingsManager::GetDashboardSmooth() const 336 | { 337 | return m_dashboardSmooth; 338 | } 339 | 340 | bool CSettingsManager::GetStartMinimized() const 341 | { 342 | return m_startMinimized; 343 | } 344 | 345 | bool CSettingsManager::GetUseTriggerGrip() const 346 | { 347 | return m_useTriggerGrip; 348 | } 349 | 350 | int CSettingsManager::GetTriggerMode() const 351 | { 352 | return m_triggerMode; 353 | } 354 | 355 | float CSettingsManager::GetTriggerThreshold() const 356 | { 357 | return m_triggerThreshold; 358 | } 359 | 360 | float CSettingsManager::GetGripThreshold() const 361 | { 362 | return m_gripThreshold; 363 | } 364 | 365 | const glm::vec2& CSettingsManager::GetPinchLimits() const 366 | { 367 | return m_pinchLimits; 368 | } 369 | 370 | bool CSettingsManager::GetUseControllerInput() const 371 | { 372 | return m_useControllerInput; 373 | } 374 | 375 | const glm::vec3 & CSettingsManager::GetRootOffset() const 376 | { 377 | return m_rootOffset; 378 | } 379 | 380 | const glm::vec3& CSettingsManager::GetRootAngle() const 381 | { 382 | return m_rootAngle; 383 | } 384 | 385 | bool CSettingsManager::GetShowOverlays() const 386 | { 387 | return m_showOverlays; 388 | } 389 | 390 | float CSettingsManager::GetOverlaySize() const 391 | { 392 | return m_overlaySize; 393 | } 394 | 395 | const glm::vec3 & CSettingsManager::GetOverlayOffset() const 396 | { 397 | return m_overlayOffset; 398 | } 399 | 400 | const glm::vec3 & CSettingsManager::GetOverlayAngle() const 401 | { 402 | return m_overlayAngle; 403 | } 404 | 405 | void CSettingsManager::SetSetting(SettingType p_setting, int p_value) 406 | { 407 | switch(p_setting) 408 | { 409 | case ST_TrackingLevel: 410 | m_trackingLevel = glm::clamp(p_value, TL_Partial, TL_Full); 411 | break; 412 | 413 | case ST_TriggerMode: 414 | m_triggerMode = glm::clamp(p_value, TM_FingerBend, TM_Pinch); 415 | break; 416 | } 417 | } 418 | void CSettingsManager::SetSetting(SettingType p_setting, bool p_value) 419 | { 420 | switch(p_setting) 421 | { 422 | case ST_HandsReset: 423 | m_handsReset = p_value; 424 | break; 425 | 426 | case ST_UseVelocity: 427 | m_useVelocity = p_value; 428 | break; 429 | 430 | case ST_StartMinimized: 431 | m_startMinimized = p_value; 432 | break; 433 | 434 | case ST_UseTriggerGrip: 435 | m_useTriggerGrip = p_value; 436 | break; 437 | 438 | case ST_UseControllerInput: 439 | m_useControllerInput = p_value; 440 | break; 441 | 442 | case ST_ShowOverlays: 443 | m_showOverlays = p_value; 444 | break; 445 | } 446 | } 447 | void CSettingsManager::SetSetting(SettingType p_setting, float p_value) 448 | { 449 | switch(p_setting) 450 | { 451 | case ST_DashboardSmooth: 452 | m_dashboardSmooth = glm::clamp(p_value, 0.01f, 1.f); 453 | break; 454 | 455 | case ST_TriggerThreshold: 456 | m_triggerThreshold = glm::clamp(p_value, 0.1f, 1.f); 457 | break; 458 | 459 | case ST_GripThreshold: 460 | m_gripThreshold = glm::clamp(p_value, 0.1f, 1.f); 461 | break; 462 | 463 | case ST_PinchLimitMin: 464 | m_pinchLimits.x = glm::clamp(p_value, 0.01f, 0.1f); 465 | break; 466 | 467 | case ST_PinchLimitMax: 468 | m_pinchLimits.y = glm::clamp(p_value, 0.01f, 0.1f); 469 | break; 470 | 471 | case ST_RootOffsetX: 472 | m_rootOffset.x = glm::clamp(p_value, -1.f, 1.f); 473 | break; 474 | 475 | case ST_RootOffsetY: 476 | m_rootOffset.y = glm::clamp(p_value, -1.f, 1.f); 477 | break; 478 | 479 | case ST_RootOffsetZ: 480 | m_rootOffset.z = glm::clamp(p_value, -1.f, 1.f); 481 | break; 482 | 483 | case ST_RootAngleX: 484 | m_rootAngle.x = glm::clamp(p_value, -180.f, 180.f); 485 | break; 486 | 487 | case ST_RootAngleY: 488 | m_rootAngle.y = glm::clamp(p_value, -180.f, 180.f); 489 | break; 490 | 491 | case ST_RootAngleZ: 492 | m_rootAngle.z = glm::clamp(p_value, -180.f, 180.f); 493 | break; 494 | 495 | case ST_OverlayOffsetX: 496 | m_overlayOffset.x = glm::clamp(p_value, -0.5f, 0.5f); 497 | break; 498 | 499 | case ST_OverlayOffsetY: 500 | m_overlayOffset.y = glm::clamp(p_value, -0.5f, 0.5f); 501 | break; 502 | 503 | case ST_OverlayOffsetZ: 504 | m_overlayOffset.z = glm::clamp(p_value, -0.5f, 0.5f); 505 | break; 506 | 507 | case ST_OverlayAngleX: 508 | m_overlayAngle.x = glm::clamp(p_value, -180.f, 180.f); 509 | break; 510 | 511 | case ST_OverlayAngleY: 512 | m_overlayAngle.y = glm::clamp(p_value, -180.f, 180.f); 513 | break; 514 | 515 | case ST_OverlayAngleZ: 516 | m_overlayAngle.z = glm::clamp(p_value, -180.f, 180.f); 517 | break; 518 | 519 | case ST_OverlaySize: 520 | m_overlaySize = glm::clamp(p_value, 0.1f, 0.5f); 521 | break; 522 | } 523 | } 524 | 525 | 526 | -------------------------------------------------------------------------------- /leap_control/Managers/CSettingsManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CSettingsManager 4 | { 5 | static CSettingsManager* ms_instance; 6 | 7 | int m_trackingLevel; 8 | bool m_handsReset; 9 | bool m_useVelocity; 10 | float m_dashboardSmooth; 11 | bool m_startMinimized; 12 | bool m_useTriggerGrip; 13 | int m_triggerMode; 14 | float m_triggerThreshold; 15 | float m_gripThreshold; 16 | glm::vec2 m_pinchLimits; 17 | bool m_useControllerInput; 18 | glm::vec3 m_rootOffset; 19 | glm::vec3 m_rootAngle; 20 | bool m_showOverlays; 21 | glm::vec3 m_overlayOffset; 22 | glm::vec3 m_overlayAngle; 23 | float m_overlaySize; 24 | 25 | CSettingsManager(); 26 | CSettingsManager(const CSettingsManager &that) = delete; 27 | CSettingsManager& operator=(const CSettingsManager &that) = delete; 28 | ~CSettingsManager() = default; 29 | public: 30 | enum SettingType : size_t 31 | { 32 | ST_TrackingLevel = 0U, 33 | ST_HandsReset, 34 | ST_UseVelocity, 35 | ST_DashboardSmooth, 36 | ST_StartMinimized, 37 | ST_UseTriggerGrip, 38 | ST_TriggerMode, 39 | ST_TriggerThreshold, 40 | ST_GripThreshold, 41 | ST_PinchLimitMin, 42 | ST_PinchLimitMax, 43 | ST_UseControllerInput, 44 | ST_RootOffsetX, 45 | ST_RootOffsetY, 46 | ST_RootOffsetZ, 47 | ST_RootAngleX, 48 | ST_RootAngleY, 49 | ST_RootAngleZ, 50 | ST_ShowOverlays, 51 | ST_OverlaySize, 52 | ST_OverlayOffsetX, 53 | ST_OverlayOffsetY, 54 | ST_OverlayOffsetZ, 55 | ST_OverlayAngleX, 56 | ST_OverlayAngleY, 57 | ST_OverlayAngleZ, 58 | 59 | Count 60 | }; 61 | 62 | enum TrackingLevel : int 63 | { 64 | TL_Partial = 0, 65 | TL_Full 66 | }; 67 | 68 | enum TriggerMode : int 69 | { 70 | TM_FingerBend = 0, 71 | TM_Pinch 72 | }; 73 | 74 | static CSettingsManager* GetInstance(); 75 | 76 | void Load(); 77 | void Save(); 78 | 79 | int GetTrackingLevel() const; 80 | bool GetHandsReset() const; 81 | bool GetUseVelocity() const; 82 | float GetDashboardSmooth() const; 83 | bool GetUseTriggerGrip() const; 84 | int GetTriggerMode() const; 85 | float GetTriggerThreshold() const; 86 | float GetGripThreshold() const; 87 | const glm::vec2& GetPinchLimits() const; 88 | bool GetUseControllerInput() const; 89 | bool GetStartMinimized() const; 90 | const glm::vec3& GetRootOffset() const; 91 | const glm::vec3& GetRootAngle() const; 92 | bool GetShowOverlays() const; 93 | float GetOverlaySize() const; 94 | const glm::vec3& GetOverlayOffset() const; 95 | const glm::vec3& GetOverlayAngle() const; 96 | 97 | void SetSetting(SettingType p_setting, int p_value); 98 | void SetSetting(SettingType p_setting, bool p_value); 99 | void SetSetting(SettingType p_setting, float p_value); 100 | }; 101 | 102 | -------------------------------------------------------------------------------- /leap_control/Managers/CVRManager.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Managers/CVRManager.h" 3 | #include "Utils/Utils.h" 4 | 5 | const glm::vec4 g_pointVec4(0.f, 0.f, 0.f, 1.f); 6 | 7 | CVRManager* CVRManager::ms_instance = nullptr; 8 | 9 | CVRManager* CVRManager::GetInstance() 10 | { 11 | if(!ms_instance) 12 | ms_instance = new CVRManager(); 13 | 14 | return ms_instance; 15 | } 16 | 17 | CVRManager::CVRManager() 18 | { 19 | m_vrSystem = nullptr; 20 | m_leapDevice = vr::k_unTrackedDeviceIndexInvalid; 21 | m_leftController = vr::k_unTrackedDeviceIndexInvalid; 22 | m_rightController = vr::k_unTrackedDeviceIndexInvalid; 23 | m_exitPolled = false; 24 | 25 | m_hmdMatrix = glm::mat4(1.f); 26 | m_hmdPosition = glm::vec3(0.f); 27 | m_hmdRotation = glm::quat(1.f, 0.f, 0.f, 0.f); 28 | 29 | m_leftHandMatrix = glm::mat4(1.f); 30 | m_leftHandPosition = glm::vec3(0.f); 31 | m_leftHandRotation = glm::quat(1.f, 0.f, 0.f, 0.f); 32 | 33 | m_rightHandMatrix = glm::mat4(1.f); 34 | m_rightHandPosition = glm::vec3(0.f); 35 | m_rightHandRotation = glm::quat(1.f, 0.f, 0.f, 0.f); 36 | } 37 | 38 | bool CVRManager::Init() 39 | { 40 | if(!m_vrSystem) 41 | { 42 | vr::EVRInitError l_initError; 43 | m_vrSystem = vr::VR_Init(&l_initError, vr::VRApplication_Overlay); 44 | if(l_initError != vr::VRInitError_None) 45 | { 46 | QString l_errorString("Unable to initialize OpenVR: "); 47 | l_errorString.append(vr::VR_GetVRInitErrorAsEnglishDescription(l_initError)); 48 | QMessageBox::critical(nullptr, "Leap Control", l_errorString); 49 | } 50 | else 51 | { 52 | for(uint32_t i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) 53 | { 54 | vr::ETrackedPropertyError l_propertyError = vr::TrackedProp_Success; 55 | uint64_t l_property = m_vrSystem->GetUint64TrackedDeviceProperty(i, vr::Prop_VendorSpecific_Reserved_Start, &l_propertyError); 56 | if((l_propertyError == vr::TrackedProp_Success) && (l_property == 0x4C4DU)) // "LM" 57 | { 58 | m_leapDevice = i; 59 | break; 60 | } 61 | } 62 | } 63 | } 64 | 65 | return (m_vrSystem != nullptr); 66 | } 67 | 68 | void CVRManager::Terminate() 69 | { 70 | if(m_vrSystem) 71 | { 72 | vr::VR_Shutdown(); 73 | m_vrSystem = nullptr; 74 | } 75 | } 76 | 77 | void CVRManager::Update() 78 | { 79 | if(m_vrSystem) 80 | { 81 | m_vrSystem->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseRawAndUncalibrated, 0.f, m_trackedPoses, vr::k_unMaxTrackedDeviceCount); 82 | 83 | vr::VREvent_t l_event{ 0 }; 84 | while(m_vrSystem->PollNextEvent(&l_event, sizeof(vr::VREvent_t))) 85 | { 86 | switch(l_event.eventType) 87 | { 88 | case vr::VREvent_Quit: 89 | case vr::VREvent_RestartRequested: 90 | m_exitPolled = true; 91 | break; 92 | 93 | case vr::VREvent_TrackedDeviceDeactivated: 94 | { 95 | if(m_leftController == l_event.trackedDeviceIndex) 96 | m_leftController = vr::k_unTrackedDeviceIndexInvalid; 97 | if(m_rightController == l_event.trackedDeviceIndex) 98 | m_rightController = vr::k_unTrackedDeviceIndexInvalid; 99 | } 100 | break; 101 | } 102 | } 103 | 104 | if(m_trackedPoses[vr::k_unTrackedDeviceIndex_Hmd].bPoseIsValid) 105 | { 106 | ConvertMatrix(m_trackedPoses[vr::k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking, m_hmdMatrix); 107 | m_hmdPosition = m_hmdMatrix * g_pointVec4; 108 | m_hmdRotation = glm::toQuat(m_hmdMatrix); 109 | } 110 | 111 | if(m_leftController != vr::k_unTrackedDeviceIndexInvalid) 112 | { 113 | if(m_trackedPoses[m_leftController].bPoseIsValid) 114 | { 115 | ConvertMatrix(m_trackedPoses[m_leftController].mDeviceToAbsoluteTracking, m_leftHandMatrix); 116 | m_leftHandPosition = m_leftHandMatrix * g_pointVec4; 117 | m_leftHandRotation = glm::toQuat(m_leftHandMatrix); 118 | } 119 | } 120 | else 121 | m_leftController = m_vrSystem->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_LeftHand); 122 | 123 | if(m_rightController != vr::k_unTrackedDeviceIndexInvalid) 124 | { 125 | if(m_trackedPoses[m_rightController].bPoseIsValid) 126 | { 127 | ConvertMatrix(m_trackedPoses[m_rightController].mDeviceToAbsoluteTracking, m_rightHandMatrix); 128 | m_rightHandPosition = m_rightHandMatrix * g_pointVec4; 129 | m_rightHandRotation = glm::toQuat(m_rightHandMatrix); 130 | } 131 | } 132 | else 133 | m_rightController = m_vrSystem->GetTrackedDeviceIndexForControllerRole(vr::TrackedControllerRole_RightHand); 134 | } 135 | } 136 | 137 | bool CVRManager::IsExitPolled() const 138 | { 139 | return m_exitPolled; 140 | } 141 | 142 | const glm::vec3 & CVRManager::GetHmdPosition() const 143 | { 144 | return m_hmdPosition; 145 | } 146 | const glm::quat & CVRManager::GetHmdRotation() const 147 | { 148 | return m_hmdRotation; 149 | } 150 | const glm::mat4 & CVRManager::GetHmdMatrix() const 151 | { 152 | return m_hmdMatrix; 153 | } 154 | 155 | const glm::vec3 & CVRManager::GetLeftHandPosition() const 156 | { 157 | return m_leftHandPosition; 158 | } 159 | const glm::quat & CVRManager::GetLeftHandRotation() const 160 | { 161 | return m_leftHandRotation; 162 | } 163 | const glm::mat4 & CVRManager::GetLeftHandMatrix() const 164 | { 165 | return m_leftHandMatrix; 166 | } 167 | 168 | const glm::vec3 & CVRManager::GetRightHandPosition() const 169 | { 170 | return m_rightHandPosition; 171 | } 172 | const glm::quat & CVRManager::GetRightHandRotation() const 173 | { 174 | return m_rightHandRotation; 175 | } 176 | const glm::mat4 & CVRManager::GetRightHandMatrix() const 177 | { 178 | return m_rightHandMatrix; 179 | } 180 | 181 | void CVRManager::SendStationMessage(const std::string &p_message) 182 | { 183 | if(m_vrSystem && (m_leapDevice != vr::k_unTrackedDeviceIndexInvalid)) 184 | { 185 | char l_response[32U] = { 0 }; 186 | vr::VRDebug()->DriverDebugRequest(m_leapDevice, p_message.c_str(), l_response, 32U); 187 | } 188 | } 189 | 190 | void CVRManager::SendLeftControllerMessage(const std::string &p_message) 191 | { 192 | if(m_vrSystem && (m_leftController != vr::k_unTrackedDeviceIndexInvalid)) 193 | { 194 | char l_response[32U] = { 0 }; 195 | vr::VRDebug()->DriverDebugRequest(m_leftController, p_message.c_str(), l_response, 32U); 196 | } 197 | } 198 | 199 | void CVRManager::SendRightControllerMessage(const std::string &p_message) 200 | { 201 | if(m_vrSystem && (m_rightController != vr::k_unTrackedDeviceIndexInvalid)) 202 | { 203 | char l_response[32U] = { 0 }; 204 | vr::VRDebug()->DriverDebugRequest(m_rightController, p_message.c_str(), l_response, 32U); 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /leap_control/Managers/CVRManager.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CVRManager 4 | { 5 | static CVRManager* ms_instance; 6 | 7 | vr::IVRSystem *m_vrSystem; 8 | 9 | uint32_t m_leapDevice; 10 | uint32_t m_leftController; 11 | uint32_t m_rightController; 12 | vr::TrackedDevicePose_t m_trackedPoses[vr::k_unMaxTrackedDeviceCount]; 13 | 14 | glm::vec3 m_hmdPosition; 15 | glm::quat m_hmdRotation; 16 | glm::mat4 m_hmdMatrix; 17 | 18 | glm::vec3 m_leftHandPosition; 19 | glm::quat m_leftHandRotation; 20 | glm::mat4 m_leftHandMatrix; 21 | 22 | glm::vec3 m_rightHandPosition; 23 | glm::quat m_rightHandRotation; 24 | glm::mat4 m_rightHandMatrix; 25 | 26 | bool m_exitPolled; 27 | 28 | CVRManager(); 29 | CVRManager(const CVRManager &that) = delete; 30 | CVRManager& operator=(const CVRManager &that) = delete; 31 | ~CVRManager() = default; 32 | public: 33 | static CVRManager* GetInstance(); 34 | 35 | bool Init(); 36 | void Terminate(); 37 | 38 | void Update(); 39 | bool IsExitPolled() const; 40 | 41 | const glm::vec3& GetHmdPosition() const; 42 | const glm::quat& GetHmdRotation() const; 43 | const glm::mat4& GetHmdMatrix() const; 44 | 45 | const glm::vec3& GetLeftHandPosition() const; 46 | const glm::quat& GetLeftHandRotation() const; 47 | const glm::mat4& GetLeftHandMatrix() const; 48 | 49 | const glm::vec3& GetRightHandPosition() const; 50 | const glm::quat& GetRightHandRotation() const; 51 | const glm::mat4& GetRightHandMatrix() const; 52 | 53 | void SendStationMessage(const std::string &p_message); 54 | void SendLeftControllerMessage(const std::string &p_message); 55 | void SendRightControllerMessage(const std::string &p_message); 56 | }; 57 | -------------------------------------------------------------------------------- /leap_control/Overlay/CCursorOverlay.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Overlay/CCursorOverlay.h" 3 | #include "Utils/Utils.h" 4 | 5 | const glm::mat4 g_identityMat4(1.f); 6 | 7 | CCursorOverlay::CCursorOverlay(bool p_left) 8 | { 9 | m_overlayHandle = vr::k_ulOverlayHandleInvalid; 10 | m_isLeft = p_left; 11 | m_position = glm::vec3(0.f); 12 | m_rotation = glm::quat(1.f, 0.f, 0.f, 0.f); 13 | m_transformUpdate = false; 14 | } 15 | 16 | bool CCursorOverlay::Create() 17 | { 18 | if(m_overlayHandle == vr::k_ulOverlayHandleInvalid) 19 | { 20 | std::string l_name("leap_control.cursor."); 21 | l_name.append(m_isLeft ? "left" : "right"); 22 | if(vr::VROverlay()->CreateOverlay(l_name.c_str(), "Finger overlay", &m_overlayHandle) == vr::EVROverlayError::VROverlayError_None) 23 | { 24 | std::string l_path(QApplication::applicationDirPath().toStdString()); 25 | l_path.append("/../../../resources/textures/cursor.png"); 26 | 27 | vr::VROverlay()->SetOverlayFromFile(m_overlayHandle, l_path.c_str()); 28 | vr::VROverlay()->SetOverlayColor(m_overlayHandle, 0.f, 1.f, 0.f); 29 | vr::VROverlay()->SetOverlayWidthInMeters(m_overlayHandle, 0.006625f); 30 | vr::VROverlay()->SetOverlaySortOrder(m_overlayHandle, 1); 31 | vr::VROverlay()->ShowOverlay(m_overlayHandle); 32 | } 33 | } 34 | 35 | return (m_overlayHandle != vr::k_ulOverlayHandleInvalid); 36 | } 37 | 38 | void CCursorOverlay::Destroy() 39 | { 40 | if(m_overlayHandle != vr::k_ulOverlayHandleInvalid) 41 | { 42 | vr::VROverlay()->DestroyOverlay(m_overlayHandle); 43 | m_overlayHandle = vr::k_ulOverlayHandleInvalid; 44 | } 45 | } 46 | 47 | void CCursorOverlay::SetPosition(const glm::vec3 & p_pos) 48 | { 49 | m_position = p_pos; 50 | m_transformUpdate = true; 51 | } 52 | 53 | void CCursorOverlay::SetRotation(const glm::quat &p_rot) 54 | { 55 | m_rotation = p_rot; 56 | m_transformUpdate = true; 57 | } 58 | 59 | void CCursorOverlay::Update() 60 | { 61 | if(m_overlayHandle != vr::k_ulOverlayHandleInvalid) 62 | { 63 | if(m_transformUpdate) 64 | { 65 | glm::mat4 l_matrix = glm::translate(g_identityMat4, m_position) * glm::toMat4(m_rotation); 66 | ConvertMatrix(l_matrix, m_matrix); 67 | vr::VROverlay()->SetOverlayTransformAbsolute(m_overlayHandle, vr::TrackingUniverseRawAndUncalibrated, &m_matrix); 68 | m_transformUpdate = false; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /leap_control/Overlay/CCursorOverlay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CCursorOverlay 4 | { 5 | vr::VROverlayHandle_t m_overlayHandle; 6 | 7 | bool m_isLeft; 8 | 9 | glm::vec3 m_position; 10 | glm::quat m_rotation; 11 | vr::HmdMatrix34_t m_matrix; 12 | bool m_transformUpdate; 13 | 14 | CCursorOverlay(const CCursorOverlay &that) = delete; 15 | CCursorOverlay& operator=(const CCursorOverlay &that) = delete; 16 | public: 17 | explicit CCursorOverlay(bool p_left); 18 | ~CCursorOverlay() = default; 19 | 20 | bool Create(); 21 | void Destroy(); 22 | 23 | void SetPosition(const glm::vec3 &p_pos); 24 | void SetRotation(const glm::quat &p_rot); 25 | 26 | void Update(); 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /leap_control/Overlay/CHandOverlay.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Overlay/CHandOverlay.h" 3 | #include "Overlay/CRenderTarget.h" 4 | #include "Managers/COpenGLManager.h" 5 | #include "Ui/vr_overlay.h" 6 | #include "Utils/CButton.h" 7 | #include "Utils/Utils.h" 8 | 9 | enum ButtonType 10 | { 11 | BT_A, 12 | BT_B, 13 | BT_System, 14 | BT_Thumbstick, 15 | BT_Touchpad 16 | }; 17 | 18 | const glm::mat4 g_identityMat4(1.f); 19 | const glm::vec2 g_zeroVec2(0.f); 20 | 21 | const float g_touchPressure = 0.5f; 22 | const float g_clickPressure = 0.75f; 23 | 24 | CHandOverlay::CHandOverlay(bool p_left) 25 | { 26 | m_renderTarget = nullptr; 27 | m_ui = nullptr; 28 | m_overlayHandle = vr::k_ulOverlayHandleInvalid; 29 | m_texture.eColorSpace = vr::EColorSpace::ColorSpace_Auto; 30 | m_texture.eType = vr::ETextureType::TextureType_OpenGL; 31 | m_texture.handle = nullptr; 32 | m_isLeft = p_left; 33 | m_width = 0.125f; 34 | m_alpha = 0.5f; 35 | m_position = glm::vec3(0.f); 36 | m_rotation = glm::quat(1.f, 0.f, 0.f, 0.f); 37 | m_matrix = g_identityMat4; 38 | m_transformUpdate = false; 39 | m_pressure = 0.f; 40 | m_interacted = false; 41 | m_locked = false; 42 | m_visible = true; 43 | } 44 | 45 | bool CHandOverlay::Create() 46 | { 47 | if(m_overlayHandle == vr::k_ulOverlayHandleInvalid) 48 | { 49 | m_ui = new vr_overlay(); 50 | if(!m_isLeft) 51 | m_ui->Mirror(); 52 | 53 | std::string l_name("leap_control.handOverlay."); 54 | l_name.append(m_isLeft ? "left" : "right"); 55 | if(vr::VROverlay()->CreateOverlay(l_name.c_str(), "Hand overlay", &m_overlayHandle) == vr::EVROverlayError::VROverlayError_None) 56 | { 57 | vr::VROverlay()->SetOverlayWidthInMeters(m_overlayHandle, m_width); 58 | vr::VROverlay()->SetOverlayInputMethod(m_overlayHandle, vr::VROverlayInputMethod_None); 59 | vr::VROverlay()->SetOverlayAlpha(m_overlayHandle, m_alpha); 60 | vr::VROverlay()->ShowOverlay(m_overlayHandle); 61 | 62 | m_renderTarget = new CRenderTarget(); 63 | m_renderTarget->Create(m_ui->size().width(), m_ui->size().height()); 64 | m_renderTarget->AddWidget(m_ui); 65 | m_texture.handle = reinterpret_cast(static_cast(m_renderTarget->GetTextureID())); 66 | } 67 | 68 | m_buttons.push_back(new CButton(CButton::BT_Button, "a")); 69 | m_buttons.push_back(new CButton(CButton::BT_Button, "b")); 70 | m_buttons.push_back(new CButton(CButton::BT_Button, "system")); 71 | m_buttons.push_back(new CButton(CButton::BT_Axis, "thumbstick")); 72 | m_buttons.push_back(new CButton(CButton::BT_Axis, "touchpad")); 73 | } 74 | 75 | return (m_overlayHandle != vr::k_ulOverlayHandleInvalid); 76 | } 77 | 78 | void CHandOverlay::Destroy() 79 | { 80 | if(m_overlayHandle != vr::k_ulOverlayHandleInvalid) 81 | { 82 | vr::VROverlay()->DestroyOverlay(m_overlayHandle); 83 | m_overlayHandle = vr::k_ulOverlayHandleInvalid; 84 | } 85 | 86 | if(m_renderTarget) 87 | { 88 | m_renderTarget->Destroy(); 89 | m_renderTarget = nullptr; 90 | } 91 | 92 | //delete m_ui; 93 | m_ui = nullptr; 94 | 95 | m_texture.handle = nullptr; 96 | 97 | for(auto l_button : m_buttons) 98 | delete l_button; 99 | m_buttons.clear(); 100 | } 101 | 102 | void CHandOverlay::SetPosition(const glm::vec3 & p_pos) 103 | { 104 | m_position = p_pos; 105 | m_transformUpdate = true; 106 | } 107 | 108 | void CHandOverlay::SetRotation(const glm::quat &p_rot) 109 | { 110 | m_rotation = p_rot; 111 | m_transformUpdate = true; 112 | } 113 | 114 | bool CHandOverlay::IsLocked() const 115 | { 116 | return m_locked; 117 | } 118 | 119 | void CHandOverlay::SetLocked(bool p_state) 120 | { 121 | m_locked = p_state; 122 | } 123 | 124 | bool CHandOverlay::IsInteracted() const 125 | { 126 | return m_interacted; 127 | } 128 | 129 | void CHandOverlay::SetVisible(bool p_state) 130 | { 131 | m_visible = p_state; 132 | } 133 | 134 | void CHandOverlay::SetWidth(float p_width) 135 | { 136 | m_width = glm::clamp(p_width, 0.1f, 0.5f); 137 | 138 | if(m_overlayHandle != vr::k_ulOverlayHandleInvalid) 139 | vr::VROverlay()->SetOverlayWidthInMeters(m_overlayHandle, m_width); 140 | } 141 | 142 | void CHandOverlay::ResetInput() 143 | { 144 | if(!m_buttons.empty()) 145 | { 146 | m_buttons[ButtonType::BT_A]->SetState(CButton::BS_None); 147 | m_buttons[ButtonType::BT_B]->SetState(CButton::BS_None); 148 | m_buttons[ButtonType::BT_System]->SetState(CButton::BS_None); 149 | m_buttons[ButtonType::BT_Thumbstick]->SetState(CButton::BS_None); 150 | m_buttons[ButtonType::BT_Thumbstick]->SetAxis(g_zeroVec2); 151 | m_buttons[ButtonType::BT_Touchpad]->SetState(CButton::BS_None); 152 | m_buttons[ButtonType::BT_Touchpad]->SetAxis(g_zeroVec2); 153 | } 154 | } 155 | 156 | const std::vector& CHandOverlay::GetButtons() const 157 | { 158 | return m_buttons; 159 | } 160 | 161 | float CHandOverlay::GetPressure() const 162 | { 163 | return m_pressure; 164 | } 165 | 166 | void CHandOverlay::Update(const glm::vec3 &p_cursor) 167 | { 168 | if(m_overlayHandle != vr::k_ulOverlayHandleInvalid) 169 | { 170 | if(m_transformUpdate) 171 | { 172 | m_matrix = glm::translate(g_identityMat4, m_position) * glm::toMat4(m_rotation); 173 | ConvertMatrix(m_matrix, m_vrMatrix); 174 | vr::VROverlay()->SetOverlayTransformAbsolute(m_overlayHandle, vr::TrackingUniverseRawAndUncalibrated, &m_vrMatrix); 175 | m_transformUpdate = false; 176 | } 177 | 178 | if(!m_locked && m_visible) 179 | { 180 | for(auto l_button : m_buttons) 181 | l_button->ResetUpdate(); 182 | 183 | glm::vec3 l_localPos = glm::inverse(m_matrix) * glm::vec4(p_cursor, 1.f); 184 | float l_halfWidth = m_width * 0.5f; 185 | if(IsInRange(l_localPos.x, -l_halfWidth, l_halfWidth) && IsInRange(l_localPos.y, -l_halfWidth, l_halfWidth) && IsInRange(l_localPos.z, -0.025f, l_halfWidth)) 186 | { 187 | m_interacted = true; 188 | glm::vec2 l_cursorPos; 189 | l_cursorPos.x = (l_localPos.x + l_halfWidth) / m_width * static_cast(m_ui->size().width()); 190 | l_cursorPos.y = (-l_localPos.y + l_halfWidth) / m_width * static_cast(m_ui->size().height()); 191 | 192 | if(l_localPos.z < 0.f) 193 | l_localPos.z = 0.f; 194 | m_pressure = 1.f - glm::clamp(l_localPos.z / (m_width * 0.25f), 0.f, 1.f); 195 | 196 | m_ui->Update(l_cursorPos, m_pressure); 197 | } 198 | else 199 | ResetInteraction(); 200 | } 201 | else 202 | ResetInteraction(); 203 | 204 | m_alpha = glm::mix(m_alpha, ((m_locked || !m_visible) ? 0.f : (((m_pressure > 0.f) ? 1.f : 0.5f))), 0.25f); 205 | 206 | if(m_alpha > 0.f) 207 | { 208 | m_renderTarget->Update(); 209 | vr::VROverlay()->SetOverlayTexture(m_overlayHandle, &m_texture); 210 | } 211 | vr::VROverlay()->SetOverlayAlpha(m_overlayHandle, m_alpha); 212 | 213 | // Buttons 214 | if(m_ui->IsOnButtonA()) 215 | m_buttons[ButtonType::BT_A]->SetState((m_pressure > g_clickPressure) ? CButton::BS_Clicked : ((m_pressure > g_touchPressure) ? CButton::BS_Touched : CButton::BS_None)); 216 | else 217 | m_buttons[ButtonType::BT_A]->SetState(CButton::BS_None); 218 | 219 | if(m_ui->IsOnButtonB()) 220 | m_buttons[ButtonType::BT_B]->SetState((m_pressure > g_clickPressure) ? CButton::BS_Clicked : ((m_pressure > g_touchPressure) ? CButton::BS_Touched : CButton::BS_None)); 221 | else 222 | m_buttons[ButtonType::BT_B]->SetState(CButton::BS_None); 223 | 224 | if(m_ui->IsOnButtonSys()) 225 | m_buttons[ButtonType::BT_System]->SetState((m_pressure > g_clickPressure) ? CButton::BS_Clicked : ((m_pressure > g_touchPressure) ? CButton::BS_Touched : CButton::BS_None)); 226 | else 227 | m_buttons[ButtonType::BT_System]->SetState(CButton::BS_None); 228 | 229 | if(m_ui->IsOnThumbstick() && (m_pressure > g_touchPressure)) 230 | { 231 | m_buttons[ButtonType::BT_Thumbstick]->SetState((m_pressure > g_clickPressure) ? CButton::BS_Clicked : CButton::BS_Touched); 232 | m_buttons[ButtonType::BT_Thumbstick]->SetAxis(m_ui->GetThumbstickAxis()); 233 | } 234 | else 235 | { 236 | m_buttons[ButtonType::BT_Thumbstick]->SetState(CButton::BS_None); 237 | m_buttons[ButtonType::BT_Thumbstick]->SetAxis(g_zeroVec2); 238 | } 239 | 240 | if(m_ui->IsOnTouchpad() && (m_pressure > g_touchPressure)) 241 | { 242 | m_buttons[ButtonType::BT_Touchpad]->SetState((m_pressure > g_clickPressure) ? CButton::BS_Clicked : CButton::BS_Touched); 243 | m_buttons[ButtonType::BT_Touchpad]->SetAxis(m_ui->GetTouchpadAxis()); 244 | } 245 | else 246 | { 247 | m_buttons[ButtonType::BT_Touchpad]->SetState(CButton::BS_None); 248 | m_buttons[ButtonType::BT_Touchpad]->SetAxis(g_zeroVec2); 249 | } 250 | } 251 | } 252 | 253 | void CHandOverlay::ResetInteraction() 254 | { 255 | m_pressure = 0.f; 256 | m_interacted = false; 257 | } 258 | -------------------------------------------------------------------------------- /leap_control/Overlay/CHandOverlay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CRenderTarget; 4 | class vr_overlay; 5 | class CButton; 6 | class CHandOverlay 7 | { 8 | vr::VROverlayHandle_t m_overlayHandle; 9 | vr::Texture_t m_texture; 10 | 11 | bool m_isLeft; 12 | CRenderTarget *m_renderTarget; 13 | vr_overlay *m_ui; 14 | 15 | float m_width; 16 | float m_alpha; 17 | glm::vec3 m_position; 18 | glm::quat m_rotation; 19 | glm::mat4 m_matrix; 20 | vr::HmdMatrix34_t m_vrMatrix; 21 | bool m_transformUpdate; 22 | 23 | float m_pressure; 24 | bool m_interacted; 25 | bool m_locked; 26 | bool m_visible; 27 | 28 | std::vector m_buttons; 29 | 30 | CHandOverlay(const CHandOverlay &that) = delete; 31 | CHandOverlay& operator=(const CHandOverlay &that) = delete; 32 | 33 | void ResetInteraction(); 34 | public: 35 | explicit CHandOverlay(bool p_left); 36 | ~CHandOverlay() = default; 37 | 38 | bool Create(); 39 | void Destroy(); 40 | 41 | void SetPosition(const glm::vec3 &p_pos); 42 | void SetRotation(const glm::quat &p_rot); 43 | 44 | bool IsLocked() const; 45 | void SetLocked(bool p_state); 46 | 47 | bool IsInteracted() const; 48 | void SetVisible(bool p_state); 49 | 50 | void SetWidth(float p_width); 51 | void ResetInput(); 52 | 53 | const std::vector& GetButtons() const; 54 | float GetPressure() const; 55 | 56 | void Update(const glm::vec3 &p_cursor); 57 | }; 58 | 59 | -------------------------------------------------------------------------------- /leap_control/Overlay/CRenderTarget.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Overlay/CRenderTarget.h" 3 | #include "Managers/COpenGLManager.h" 4 | 5 | CRenderTarget::CRenderTarget() 6 | { 7 | m_surface = nullptr; 8 | m_scene = nullptr; 9 | m_fbo = nullptr; 10 | m_paintDevice = nullptr; 11 | m_painter = nullptr; 12 | } 13 | 14 | bool CRenderTarget::Create(int p_width, int p_height) 15 | { 16 | if(!m_surface) 17 | { 18 | m_surface = new QOffscreenSurface(); 19 | m_surface->create(); 20 | COpenGLManager::GetInstance()->GetContext()->makeCurrent(m_surface); 21 | 22 | QOpenGLFramebufferObjectFormat l_format; 23 | l_format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil); 24 | m_fbo = new QOpenGLFramebufferObject(p_width, p_height, l_format); 25 | 26 | m_paintDevice = new QOpenGLPaintDevice(m_fbo->size()); 27 | m_painter = new QPainter(m_paintDevice); 28 | m_painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); 29 | 30 | m_scene = new QGraphicsScene(); 31 | } 32 | return (m_surface != nullptr); 33 | } 34 | 35 | void CRenderTarget::Destroy() 36 | { 37 | if(m_surface) 38 | { 39 | m_widgets.clear(); 40 | 41 | delete m_scene; 42 | m_scene = nullptr; 43 | 44 | delete m_painter; 45 | m_painter = nullptr; 46 | 47 | delete m_paintDevice; 48 | m_paintDevice = nullptr; 49 | 50 | delete m_fbo; 51 | m_fbo = nullptr; 52 | 53 | m_surface->destroy(); 54 | delete m_surface; 55 | m_surface = nullptr; 56 | } 57 | } 58 | 59 | GLuint CRenderTarget::GetTextureID() const 60 | { 61 | return (m_fbo ? m_fbo->texture() : 0U); 62 | } 63 | 64 | void CRenderTarget::AddWidget(QWidget * p_widget) 65 | { 66 | m_widgets.push_back(p_widget); 67 | if(m_scene) 68 | m_scene->addWidget(p_widget); 69 | } 70 | 71 | void CRenderTarget::Update() 72 | { 73 | if(m_surface) 74 | COpenGLManager::GetInstance()->GetContext()->makeCurrent(m_surface); 75 | if(m_fbo) 76 | m_fbo->bind(); 77 | if(m_painter && m_fbo) 78 | m_painter->fillRect(0, 0, m_fbo->size().width(), m_fbo->height(), Qt::transparent); 79 | if(m_scene) 80 | m_scene->render(m_painter); 81 | if(m_fbo) 82 | m_fbo->release(); 83 | } 84 | -------------------------------------------------------------------------------- /leap_control/Overlay/CRenderTarget.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class CRenderTarget 4 | { 5 | QOffscreenSurface *m_surface; 6 | QGraphicsScene *m_scene; 7 | QOpenGLFramebufferObject *m_fbo; 8 | QOpenGLPaintDevice *m_paintDevice; 9 | QPainter *m_painter; 10 | 11 | std::vector m_widgets; 12 | 13 | CRenderTarget(const CRenderTarget &that) = delete; 14 | CRenderTarget& operator=(const CRenderTarget &that) = delete; 15 | public: 16 | CRenderTarget(); 17 | ~CRenderTarget() = default; 18 | 19 | bool Create(int p_width, int p_height); 20 | void Destroy(); 21 | 22 | GLuint GetTextureID() const; 23 | 24 | void AddWidget(QWidget *p_widget); 25 | 26 | void Update(); 27 | }; 28 | 29 | -------------------------------------------------------------------------------- /leap_control/Resources/leap_control.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/leap_control/Resources/leap_control.ico -------------------------------------------------------------------------------- /leap_control/Resources/leap_control.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | leap_control.ico 4 | 5 | 6 | -------------------------------------------------------------------------------- /leap_control/Resources/leap_control.rc: -------------------------------------------------------------------------------- 1 | IDI_ICON1 ICON DISCARDABLE "leap_control.ico" -------------------------------------------------------------------------------- /leap_control/Ui/leap_control.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ui_leap_control.h" 5 | 6 | class leap_control : public QWidget 7 | { 8 | Q_OBJECT 9 | public: 10 | leap_control(QWidget *parent = nullptr); 11 | ~leap_control() = default; 12 | private: 13 | Ui::leap_controlClass ui; 14 | QSystemTrayIcon m_trayIcon; 15 | 16 | // General 17 | void OnTrackingLevelChange(int p_item); 18 | void OnHandsResetChange(int p_state); 19 | void OnUseVelocityChange(int p_state); 20 | void OnLeftControllerToggle(bool p_checked); 21 | void OnRightControllerToggle(bool p_checked); 22 | void OnDashboardSmoothChanged(int p_value); 23 | void OnDashboardSmoothReset(bool p_checked); 24 | void OnStartMinimizedChanged(int p_state); 25 | 26 | // Input 27 | void OnUseTriggerGripChange(int p_state); 28 | void OnTriggerModeChange(int p_item); 29 | void OnTriggerThresholdChange(int p_value); 30 | void OnTriggerThresholdReset(bool p_checked); 31 | void OnGripThresholdChange(int p_value); 32 | void OnGripThresholdReset(bool p_checked); 33 | void OnPinchRangeMinChange(int p_value); 34 | void OnPinchRangeMaxChange(int p_value); 35 | void OnPinchRangeReset(bool p_checked); 36 | void OnUseControllerInputChange(int p_state); 37 | 38 | // Root 39 | void OnRootOffsetXChanged(int p_value); 40 | void OnRootOffsetYChanged(int p_value); 41 | void OnRootOffsetZChanged(int p_value); 42 | void OnRootOffsetReset(bool p_checked); 43 | 44 | void OnRootAngleXChanged(int p_value); 45 | void OnRootAngleYChanged(int p_value); 46 | void OnRootAngleZChanged(int p_value); 47 | void OnRootAngleReset(bool p_checked); 48 | 49 | // Overlays 50 | void OnShowOverlaysChange(int p_state); 51 | 52 | void OnOverlaySizeChange(int p_value); 53 | void OnOverlaySizeReset(bool p_checked); 54 | 55 | void OnOverlayOffsetXChanged(int p_value); 56 | void OnOverlayOffsetYChanged(int p_value); 57 | void OnOverlayOffsetZChanged(int p_value); 58 | void OnOverlayOffsetReset(bool p_checked); 59 | 60 | void OnOverlayAngleXChanged(int p_value); 61 | void OnOverlayAngleYChanged(int p_value); 62 | void OnOverlayAngleZChanged(int p_value); 63 | void OnOverlayAngleReset(bool p_checked); 64 | 65 | // Utils 66 | void OnSave(bool p_checked); 67 | 68 | void hideEvent(QHideEvent *p_event); 69 | void OnTrayClick(QSystemTrayIcon::ActivationReason p_reason); 70 | }; 71 | -------------------------------------------------------------------------------- /leap_control/Ui/vr_overlay.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Ui/vr_overlay.h" 3 | 4 | vr_overlay::vr_overlay(QWidget *parent) : QWidget(parent) 5 | { 6 | ui.setupUi(this); 7 | 8 | m_onThumbstick = false; 9 | m_onTouchpad = false; 10 | m_onButtonA = false; 11 | m_onButtonB = false; 12 | m_onButtonS = false; 13 | } 14 | 15 | void vr_overlay::Mirror() 16 | { 17 | int l_mainWidth = this->width(); 18 | Mirror(ui.m_thumbstickArea, l_mainWidth); 19 | Mirror(ui.m_touchpadArea, l_mainWidth); 20 | Mirror(ui.m_buttonA, l_mainWidth); 21 | Mirror(ui.m_buttonB, l_mainWidth); 22 | Mirror(ui.m_buttonSys, l_mainWidth); 23 | Mirror(ui.m_pressureArea, l_mainWidth); 24 | } 25 | 26 | void vr_overlay::Update(const glm::vec2 & p_pos, float p_pressure) 27 | { 28 | auto l_cursorSize = ui.m_cursor->size(); 29 | ui.m_cursor->move(p_pos.x - l_cursorSize.width() / 2, p_pos.y - l_cursorSize.height() / 2); 30 | 31 | // Check for areas with axes 32 | m_onThumbstick = false; 33 | QRect l_rect(ui.m_thumbstickArea->pos(), ui.m_thumbstickArea->size()); // ui.m_thumbstickArea->rect() returns only size with zero position, no bueno 34 | m_onThumbstick = l_rect.contains(p_pos.x, p_pos.y); 35 | if(m_onThumbstick) 36 | { 37 | auto l_pos = ui.m_thumbstickArea->pos(); 38 | auto l_size = ui.m_thumbstickArea->size(); 39 | l_pos.setX(p_pos.x - l_pos.x()); 40 | l_pos.setY(p_pos.y - l_pos.y()); 41 | m_thumbstickAxis.x = ((static_cast(l_pos.x()) / static_cast(l_size.width())) *2.f) - 1.0f; 42 | m_thumbstickAxis.y = -(((static_cast(l_pos.y()) / static_cast(l_size.height())) *2.f) - 1.0f); 43 | 44 | l_size = ui.m_thumbstickCursor->size(); 45 | l_pos.setX(l_pos.x() - l_size.width() / 2); 46 | l_pos.setY(l_pos.y() - l_size.height() / 2); 47 | ui.m_thumbstickCursor->move(l_pos); 48 | } 49 | 50 | l_rect.moveTo(ui.m_touchpadArea->pos()); 51 | l_rect.setSize(ui.m_touchpadArea->size()); 52 | m_onTouchpad = l_rect.contains(p_pos.x, p_pos.y); 53 | if(m_onTouchpad) 54 | { 55 | auto l_pos = ui.m_touchpadArea->pos(); 56 | auto l_size = ui.m_touchpadArea->size(); 57 | l_pos.setX(p_pos.x - l_pos.x()); 58 | l_pos.setY(p_pos.y - l_pos.y()); 59 | m_touchpadAxis.x = ((static_cast(l_pos.x()) / static_cast(l_size.width())) *2.f) - 1.0f; 60 | m_touchpadAxis.y = -(((static_cast(l_pos.y()) / static_cast(l_size.height())) *2.f) - 1.0f); 61 | 62 | l_size = ui.m_touchpadCursor->size(); 63 | l_pos.setX(l_pos.x() - l_size.width() / 2); 64 | l_pos.setY(l_pos.y() - l_size.height() / 2); 65 | ui.m_touchpadCursor->move(l_pos); 66 | } 67 | 68 | l_rect.moveTo(ui.m_buttonA->pos()); 69 | l_rect.setSize(ui.m_buttonA->size()); 70 | m_onButtonA = l_rect.contains(p_pos.x, p_pos.y); 71 | if(m_onButtonA) 72 | ui.m_buttonA->setStyleSheet(QString("QFrame{background-color:#%1;border-radius:10px;}").arg((p_pressure > 0.75f) ? "ffa500" : ((p_pressure > 0.5f) ? "00ff00" : "23262e"))); 73 | else 74 | ui.m_buttonA->setStyleSheet("QFrame{background-color:#23262e;border-radius:10px;}"); 75 | 76 | l_rect.moveTo(ui.m_buttonB->pos()); 77 | l_rect.setSize(ui.m_buttonB->size()); 78 | m_onButtonB = l_rect.contains(p_pos.x, p_pos.y); 79 | if(m_onButtonB) 80 | ui.m_buttonB->setStyleSheet(QString("QFrame{background-color:#%1;border-radius:10px;}").arg((p_pressure > 0.75f) ? "ffa500" : ((p_pressure > 0.5f) ? "00ff00" : "23262e"))); 81 | else 82 | ui.m_buttonB->setStyleSheet("QFrame{background-color:#23262e;border-radius:10px;}"); 83 | 84 | l_rect.moveTo(ui.m_buttonSys->pos()); 85 | l_rect.setSize(ui.m_buttonSys->size()); 86 | m_onButtonS = l_rect.contains(p_pos.x, p_pos.y); 87 | if(m_onButtonS) 88 | ui.m_buttonSys->setStyleSheet(QString("QFrame{background-color:#%1;border-radius:10px;}").arg((p_pressure > 0.75f) ? "ffa500" : ((p_pressure > 0.5f) ? "00ff00" : "23262e"))); 89 | else 90 | ui.m_buttonSys->setStyleSheet("QFrame{background-color:#23262e;border-radius:10px;}"); 91 | 92 | ui.m_pressureRectangle->resize(10, static_cast(p_pressure * 320.f)); 93 | ui.m_pressureRectangle->setStyleSheet(QString("QFrame{background-color:#%1;border-radius:2px;}").arg((p_pressure > 0.75f) ? "ffa500" : ((p_pressure > 0.5f) ? "00ff00" : "3399ff"))); 94 | } 95 | 96 | bool vr_overlay::IsOnThumbstick() const 97 | { 98 | return m_onThumbstick; 99 | } 100 | 101 | bool vr_overlay::IsOnTouchpad() const 102 | { 103 | return m_onTouchpad; 104 | } 105 | 106 | bool vr_overlay::IsOnButtonA() const 107 | { 108 | return m_onButtonA; 109 | } 110 | 111 | bool vr_overlay::IsOnButtonB() const 112 | { 113 | return m_onButtonB; 114 | } 115 | 116 | bool vr_overlay::IsOnButtonSys() const 117 | { 118 | return m_onButtonS; 119 | } 120 | 121 | const glm::vec2 & vr_overlay::GetThumbstickAxis() const 122 | { 123 | return m_thumbstickAxis; 124 | } 125 | 126 | const glm::vec2 & vr_overlay::GetTouchpadAxis() const 127 | { 128 | return m_touchpadAxis; 129 | } 130 | 131 | void vr_overlay::Mirror(QWidget *p_frame, int p_mainWidth) 132 | { 133 | QPoint l_pos = p_frame->pos(); 134 | QSize l_size = p_frame->size(); 135 | int l_newX = p_mainWidth - (l_pos.x() + l_size.width()); 136 | l_pos.setX(l_newX); 137 | p_frame->move(l_pos); 138 | } 139 | -------------------------------------------------------------------------------- /leap_control/Ui/vr_overlay.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "ui_vr_overlay.h" 5 | 6 | class vr_overlay : public QWidget 7 | { 8 | Q_OBJECT 9 | 10 | public: 11 | vr_overlay(QWidget *parent = nullptr); 12 | ~vr_overlay() = default; 13 | 14 | void Mirror(); 15 | 16 | void Update(const glm::vec2 &p_pos, float p_pressure); 17 | 18 | bool IsOnThumbstick() const; 19 | bool IsOnTouchpad() const; 20 | bool IsOnButtonA() const; 21 | bool IsOnButtonB() const; 22 | bool IsOnButtonSys() const; 23 | 24 | const glm::vec2& GetThumbstickAxis() const; 25 | const glm::vec2& GetTouchpadAxis() const; 26 | private: 27 | Ui::vr_overlayClass ui; 28 | 29 | bool m_onThumbstick; 30 | glm::vec2 m_thumbstickAxis; 31 | 32 | bool m_onTouchpad; 33 | glm::vec2 m_touchpadAxis; 34 | 35 | bool m_onButtonA; 36 | bool m_onButtonB; 37 | bool m_onButtonS; 38 | 39 | static void Mirror(QWidget *m_frame, int p_mainWidth); 40 | }; 41 | -------------------------------------------------------------------------------- /leap_control/Ui/vr_overlay.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | vr_overlayClass 4 | 5 | 6 | 7 | 0 8 | 0 9 | 512 10 | 512 11 | 12 | 13 | 14 | 15 | 0 16 | 0 17 | 18 | 19 | 20 | vr_overlay 21 | 22 | 23 | QWidget#vr_overlayClass 24 | { 25 | background-color: transparent; 26 | border: 0px; 27 | } 28 | 29 | 30 | 31 | 32 | 0 33 | 0 34 | 512 35 | 512 36 | 37 | 38 | 39 | QFrame#frame 40 | { 41 | background-color: rgb(14, 20, 27); 42 | border-radius: 10px; 43 | } 44 | 45 | 46 | QFrame::StyledPanel 47 | 48 | 49 | QFrame::Raised 50 | 51 | 52 | 53 | 54 | 480 55 | 100 56 | 10 57 | 320 58 | 59 | 60 | 61 | QFrame 62 | { 63 | background-color: #23262e; 64 | border-radius: 2px; 65 | } 66 | 67 | 68 | QFrame::StyledPanel 69 | 70 | 71 | QFrame::Raised 72 | 73 | 74 | 75 | 76 | 0 77 | 0 78 | 10 79 | 50 80 | 81 | 82 | 83 | QFrame 84 | { 85 | background-color: #ffffff; 86 | border-radius: 2px; 87 | } 88 | 89 | 90 | QFrame::StyledPanel 91 | 92 | 93 | QFrame::Raised 94 | 95 | 96 | 97 | 98 | 99 | 100 | 310 101 | 325 102 | 150 103 | 100 104 | 105 | 106 | 107 | QFrame 108 | { 109 | background-color: #23262e; 110 | border-radius: 10px; 111 | } 112 | 113 | 114 | QFrame::StyledPanel 115 | 116 | 117 | QFrame::Raised 118 | 119 | 120 | 121 | 122 | 0 123 | 0 124 | 150 125 | 100 126 | 127 | 128 | 129 | 130 | 48 131 | 132 | 133 | 134 | QLabel 135 | { 136 | color: rgb(14, 20, 27); 137 | } 138 | 139 | 140 | S 141 | 142 | 143 | Qt::AlignCenter 144 | 145 | 146 | 147 | 148 | 149 | 150 | 40 151 | 270 152 | 210 153 | 210 154 | 155 | 156 | 157 | QFrame 158 | { 159 | background-color: #23262e; 160 | border-radius: 105px; 161 | } 162 | 163 | 164 | QFrame::StyledPanel 165 | 166 | 167 | QFrame::Raised 168 | 169 | 170 | 171 | 172 | 0 173 | 103 174 | 210 175 | 4 176 | 177 | 178 | 179 | QFrame 180 | { 181 | background-color: rgb(14, 20, 27); 182 | } 183 | 184 | 185 | QFrame::StyledPanel 186 | 187 | 188 | QFrame::Raised 189 | 190 | 191 | 192 | 193 | 194 | 103 195 | 0 196 | 4 197 | 210 198 | 199 | 200 | 201 | QFrame 202 | { 203 | background-color: rgb(14, 20, 27); 204 | } 205 | 206 | 207 | QFrame::StyledPanel 208 | 209 | 210 | QFrame::Raised 211 | 212 | 213 | 214 | 215 | 216 | 0 217 | 0 218 | 16 219 | 16 220 | 221 | 222 | 223 | QFrame 224 | { 225 | background-color: rgb(0, 255, 0); 226 | border-radius: 8px; 227 | } 228 | 229 | 230 | QFrame::StyledPanel 231 | 232 | 233 | QFrame::Raised 234 | 235 | 236 | 237 | 238 | 239 | 240 | 310 241 | 210 242 | 150 243 | 100 244 | 245 | 246 | 247 | QFrame 248 | { 249 | background-color: #23262e; 250 | border-radius: 10px; 251 | } 252 | 253 | 254 | QFrame::StyledPanel 255 | 256 | 257 | QFrame::Raised 258 | 259 | 260 | 261 | 262 | 0 263 | 0 264 | 150 265 | 100 266 | 267 | 268 | 269 | 270 | 48 271 | 272 | 273 | 274 | QLabel 275 | { 276 | color: rgb(14, 20, 27); 277 | } 278 | 279 | 280 | A 281 | 282 | 283 | Qt::AlignCenter 284 | 285 | 286 | 287 | 288 | 289 | 290 | 310 291 | 95 292 | 150 293 | 100 294 | 295 | 296 | 297 | QFrame 298 | { 299 | background-color: #23262e; 300 | border-radius: 10px; 301 | } 302 | 303 | 304 | QFrame::StyledPanel 305 | 306 | 307 | QFrame::Raised 308 | 309 | 310 | 311 | 312 | 0 313 | 0 314 | 150 315 | 100 316 | 317 | 318 | 319 | 320 | 48 321 | 322 | 323 | 324 | QLabel 325 | { 326 | color: rgb(14, 20, 27); 327 | } 328 | 329 | 330 | B 331 | 332 | 333 | Qt::AlignCenter 334 | 335 | 336 | 337 | 338 | 339 | 340 | 40 341 | 40 342 | 210 343 | 210 344 | 345 | 346 | 347 | QFrame 348 | { 349 | background-color: #23262e; 350 | border-radius: 105px; 351 | } 352 | 353 | 354 | QFrame::StyledPanel 355 | 356 | 357 | QFrame::Raised 358 | 359 | 360 | 361 | 362 | 0 363 | 103 364 | 210 365 | 4 366 | 367 | 368 | 369 | QFrame 370 | { 371 | background-color: rgb(14, 20, 27); 372 | } 373 | 374 | 375 | QFrame::StyledPanel 376 | 377 | 378 | QFrame::Raised 379 | 380 | 381 | 382 | 383 | 384 | 103 385 | 0 386 | 4 387 | 210 388 | 389 | 390 | 391 | QFrame 392 | { 393 | background-color: rgb(14, 20, 27); 394 | } 395 | 396 | 397 | QFrame::StyledPanel 398 | 399 | 400 | QFrame::Raised 401 | 402 | 403 | 404 | 405 | 406 | 0 407 | 0 408 | 16 409 | 16 410 | 411 | 412 | 413 | QFrame 414 | { 415 | background-color: rgb(0, 255, 0); 416 | border-radius: 8px; 417 | } 418 | 419 | 420 | QFrame::StyledPanel 421 | 422 | 423 | QFrame::Raised 424 | 425 | 426 | 427 | 428 | 429 | 430 | 0 431 | 0 432 | 10 433 | 10 434 | 435 | 436 | 437 | QFrame 438 | { 439 | background-color: #3399ff; 440 | border-radius: 5px; 441 | } 442 | 443 | 444 | QFrame::StyledPanel 445 | 446 | 447 | QFrame::Raised 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | -------------------------------------------------------------------------------- /leap_control/Utils/CButton.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Utils/CButton.h" 3 | 4 | CButton::CButton(ButtonType p_type, std::string p_name) 5 | { 6 | m_name.assign(p_name); 7 | m_type = p_type; 8 | m_updated = false; 9 | } 10 | 11 | void CButton::SetState(ButtonState p_state) 12 | { 13 | if(m_state != p_state) 14 | { 15 | m_state = p_state; 16 | m_updated = true; 17 | } 18 | } 19 | 20 | CButton::ButtonState CButton::GetState() const 21 | { 22 | return m_state; 23 | } 24 | 25 | void CButton::SetAxis(const glm::vec2 & p_value) 26 | { 27 | if(m_axisValues != p_value) 28 | { 29 | m_axisValues = p_value; 30 | m_updated = true; 31 | } 32 | } 33 | 34 | const glm::vec2 & CButton::GetAxis() const 35 | { 36 | return m_axisValues; 37 | } 38 | 39 | const std::string & CButton::GetName() const 40 | { 41 | return m_name; 42 | } 43 | 44 | CButton::ButtonType CButton::GetType() const 45 | { 46 | return m_type; 47 | } 48 | 49 | bool CButton::IsUpdated() const 50 | { 51 | return m_updated; 52 | } 53 | 54 | void CButton::ResetUpdate() 55 | { 56 | m_updated = false; 57 | } 58 | -------------------------------------------------------------------------------- /leap_control/Utils/CButton.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class CButton 3 | { 4 | public: // I _love_ C++ for this ... 5 | enum ButtonType : size_t 6 | { 7 | BT_Button = 0, 8 | BT_Axis 9 | }; 10 | enum ButtonState : size_t 11 | { 12 | BS_None = 0, 13 | BS_Touched, 14 | BS_Clicked 15 | }; 16 | private: 17 | std::string m_name; 18 | ButtonType m_type; 19 | ButtonState m_state; 20 | glm::vec2 m_axisValues; 21 | bool m_updated = false; 22 | public: 23 | CButton(ButtonType p_type, std::string p_name); 24 | ~CButton() = default; 25 | 26 | void SetState(ButtonState p_state); 27 | ButtonState GetState() const; 28 | 29 | void SetAxis(const glm::vec2 &p_value); 30 | const glm::vec2& GetAxis() const; 31 | 32 | const std::string& GetName() const; 33 | ButtonType GetType() const; 34 | 35 | bool IsUpdated() const; 36 | void ResetUpdate(); 37 | }; 38 | 39 | -------------------------------------------------------------------------------- /leap_control/Utils/Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Utils/Utils.h" 3 | 4 | size_t ReadEnumVector(const std::string& p_val, const std::vector& p_vec) 5 | { 6 | size_t l_result = std::numeric_limits::max(); 7 | for(auto iter = p_vec.begin(), iterEnd = p_vec.end(); iter != iterEnd; ++iter) 8 | { 9 | if(!iter->compare(p_val)) 10 | { 11 | l_result = std::distance(p_vec.begin(), iter); 12 | break; 13 | } 14 | } 15 | return l_result; 16 | } 17 | 18 | size_t ReadEnumVector(const char* p_val, const std::vector& p_vec) 19 | { 20 | size_t l_result = std::numeric_limits::max(); 21 | for(auto iter = p_vec.begin(), iterEnd = p_vec.end(); iter != iterEnd; ++iter) 22 | { 23 | if(!iter->compare(p_val)) 24 | { 25 | l_result = std::distance(p_vec.begin(), iter); 26 | break; 27 | } 28 | } 29 | return l_result; 30 | } 31 | 32 | void ConvertMatrix(const vr::HmdMatrix34_t& p_matVR, glm::mat4& p_mat) 33 | { 34 | for(int i = 0; i < 4; i++) 35 | { 36 | for(int j = 0; j < 3; j++) p_mat[i][j] = p_matVR.m[j][i]; 37 | } 38 | for(int i = 0; i < 3; i++) p_mat[i][3] = 0.f; 39 | p_mat[3][3] = 1.f; 40 | } 41 | void ConvertMatrix(const glm::mat4& p_mat, vr::HmdMatrix34_t& p_matVR) 42 | { 43 | for(int i = 0; i < 4; i++) 44 | { 45 | for(int j = 0; j < 3; j++) p_matVR.m[j][i] = p_mat[i][j]; 46 | } 47 | } 48 | 49 | bool IsInRange(float p_value, float p_min, float p_max) 50 | { 51 | return ((p_value >= p_min) && (p_value <= p_max)); 52 | } 53 | 54 | float ProgressLerp(int p_progress, float p_min, float p_max) 55 | { 56 | return glm::mix(p_min, p_max, static_cast(p_progress) * 0.01f); 57 | } 58 | int InvProgressLerp(float p_value, float p_min, float p_max) 59 | { 60 | return glm::clamp(static_cast(((p_value - p_min) / (p_max - p_min)) *100.f), 0, 100); 61 | } 62 | -------------------------------------------------------------------------------- /leap_control/Utils/Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | size_t ReadEnumVector(const std::string &p_val, const std::vector &p_vec); 4 | size_t ReadEnumVector(const char* p_val, const std::vector& p_vec); 5 | void ConvertMatrix(const vr::HmdMatrix34_t &p_matVR, glm::mat4 &p_mat); 6 | void ConvertMatrix(const glm::mat4& p_mat, vr::HmdMatrix34_t& p_matVR); 7 | bool IsInRange(float p_value, float p_min, float p_max); 8 | float ProgressLerp(int p_progress, float p_min, float p_max); 9 | int InvProgressLerp(float p_value, float p_min, float p_max); 10 | -------------------------------------------------------------------------------- /leap_control/leap_control.vcxproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | x64 7 | 8 | 9 | Release 10 | x64 11 | 12 | 13 | 14 | {C3C7197E-4752-4680-9AAB-78120ED43093} 15 | QtVS_v304 16 | 10.0.19041.0 17 | 10.0.19041.0 18 | $(MSBuildProjectDirectory)\QtMsBuild 19 | 20 | 21 | 22 | Application 23 | v141 24 | 25 | 26 | Application 27 | v141 28 | 29 | 30 | 31 | 32 | 33 | 34 | 5.12.10_msvc2017_64 35 | core;opengl;gui;widgets 36 | debug 37 | true 38 | 39 | 40 | core;opengl;gui;widgets 41 | release 42 | true 43 | 5.12.10_msvc2017_64 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | $(Qt_INCLUDEPATH_);$(IncludePath) 61 | $(SolutionDir)bin\win64\leap_control\ 62 | $(SolutionDir)objs\$(ProjectName)\$(PlatformName)\$(Configuration)\ 63 | 64 | 65 | $(Qt_INCLUDEPATH_);$(IncludePath) 66 | $(SolutionDir)bin\win64\leap_control\ 67 | $(SolutionDir)objs\$(ProjectName)\$(PlatformName)\$(Configuration)\ 68 | 69 | 70 | 71 | ../vendor/LeapSDK/lib/x64;../vendor/openvr/lib/win64/;%(AdditionalLibraryDirectories) 72 | openvr_api.lib;LeapC.lib;%(AdditionalDependencies) 73 | 74 | 75 | ./;../vendor/openvr/headers;../vendor/LeapSDK/include;../vendor/glm;../vendor/pugixml/src;%(AdditionalIncludeDirectories) 76 | %(PreprocessorDefinitions) 77 | 78 | 79 | copy /y "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\leap\bin\win64\leap_control\$(TargetFileName)" 80 | 81 | 82 | 83 | 84 | ../vendor/LeapSDK/lib/x64;../vendor/openvr/lib/win64/;%(AdditionalLibraryDirectories) 85 | openvr_api.lib;LeapC.lib;%(AdditionalDependencies) 86 | 87 | 88 | ./;../vendor/openvr/headers;../vendor/LeapSDK/include;../vendor/glm;../vendor/pugixml/src;%(AdditionalIncludeDirectories) 89 | %(PreprocessorDefinitions) 90 | 91 | 92 | copy /y "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\leap\bin\win64\leap_control\$(TargetFileName)" 93 | 94 | 95 | 96 | 97 | true 98 | true 99 | ProgramDatabase 100 | Disabled 101 | Use 102 | stdafx.h 103 | 104 | 105 | Windows 106 | true 107 | 108 | 109 | stdafx.h;%(PrependInclude) 110 | 111 | 112 | 113 | 114 | true 115 | true 116 | None 117 | MaxSpeed 118 | Use 119 | stdafx.h 120 | 121 | 122 | Windows 123 | false 124 | 125 | 126 | stdafx.h;%(PrependInclude) 127 | 128 | 129 | 130 | 131 | NotUsing 132 | NotUsing 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | Create 166 | Create 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | -------------------------------------------------------------------------------- /leap_control/leap_control.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {06392c3b-913e-4d64-b857-e8202b5dc60e} 6 | 7 | 8 | {7d3569e6-aa25-4a20-a21a-6c946c085983} 9 | 10 | 11 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 12 | qrc;rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 13 | 14 | 15 | {5a2a5f55-7103-4b85-aa32-ddab7ec625e7} 16 | 17 | 18 | {26e6f03d-0c4e-4cb3-b23a-42ecc9099fa0} 19 | 20 | 21 | {44c96d25-eab6-4598-9e32-b23438ee4f30} 22 | 23 | 24 | {0ddde06f-10dd-4511-9592-75798015308f} 25 | 26 | 27 | {a81eff6d-76ef-477b-9a74-dc46715f98fa} 28 | 29 | 30 | {3cc7d4c7-6bc4-4685-baee-6be510fd0b8e} 31 | 32 | 33 | 34 | 35 | 36 | 37 | vendor\pugixml 38 | 39 | 40 | Core 41 | 42 | 43 | Managers 44 | 45 | 46 | Managers 47 | 48 | 49 | Managers 50 | 51 | 52 | Managers 53 | 54 | 55 | Ui 56 | 57 | 58 | Ui 59 | 60 | 61 | Utils 62 | 63 | 64 | Overlay 65 | 66 | 67 | Leap 68 | 69 | 70 | Managers 71 | 72 | 73 | Overlay 74 | 75 | 76 | Overlay 77 | 78 | 79 | Utils 80 | 81 | 82 | 83 | 84 | 85 | Core 86 | 87 | 88 | Managers 89 | 90 | 91 | Managers 92 | 93 | 94 | Managers 95 | 96 | 97 | Managers 98 | 99 | 100 | Utils 101 | 102 | 103 | Overlay 104 | 105 | 106 | Leap 107 | 108 | 109 | Managers 110 | 111 | 112 | Overlay 113 | 114 | 115 | Overlay 116 | 117 | 118 | Utils 119 | 120 | 121 | 122 | 123 | Ui 124 | 125 | 126 | Ui 127 | 128 | 129 | 130 | 131 | Ui 132 | 133 | 134 | Ui 135 | 136 | 137 | 138 | 139 | Resources 140 | 141 | 142 | 143 | 144 | Resources 145 | 146 | 147 | 148 | 149 | Resources 150 | 151 | 152 | -------------------------------------------------------------------------------- /leap_control/main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | #include "Core/CCore.h" 3 | 4 | extern "C" __declspec(dllexport) unsigned long NvOptimusEnablement = 1; 5 | extern "C" __declspec(dllexport) unsigned long AmdPowerXpressRequestHighPerformance = 1; 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | CCore l_core(argc, argv); 10 | l_core.Launch(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /leap_control/stdafx.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | -------------------------------------------------------------------------------- /leap_control/stdafx.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "openvr.h" 7 | #include "LeapC.h" 8 | 9 | #define GLM_ENABLE_EXPERIMENTAL 10 | #include "glm/glm.hpp" 11 | #include "glm/gtc/matrix_transform.hpp" 12 | #include "glm/gtc/quaternion.hpp" 13 | #include "glm/gtx/norm.hpp" 14 | #include "glm/gtx/intersect.hpp" 15 | 16 | #include "pugixml.hpp" 17 | -------------------------------------------------------------------------------- /resources/icons/base_status_ready.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/resources/icons/base_status_ready.png -------------------------------------------------------------------------------- /resources/icons/base_status_ready@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/resources/icons/base_status_ready@2x.png -------------------------------------------------------------------------------- /resources/icons/base_status_searching.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/resources/icons/base_status_searching.png -------------------------------------------------------------------------------- /resources/icons/base_status_searching@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/resources/icons/base_status_searching@2x.png -------------------------------------------------------------------------------- /resources/rendermodels/leap_motion_1_0/base_diff.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/resources/rendermodels/leap_motion_1_0/base_diff.png -------------------------------------------------------------------------------- /resources/rendermodels/leap_motion_1_0/leap_motion_1_0.json: -------------------------------------------------------------------------------- 1 | { 2 | "thumbnail" : "thumbnail_leap.png", 3 | "components": { 4 | "body": { 5 | "filename": "leap_motion_1_0.obj", 6 | "component_local" : { 7 | "origin": [0.0, 0.0, 0.0], 8 | "rotate_xyz" : [0.0,0.0,0.0] 9 | } 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /resources/rendermodels/leap_motion_1_0/leap_motion_1_0.mtl: -------------------------------------------------------------------------------- 1 | # Blender MTL File: 'lmc.blend' 2 | # Material Count: 1 3 | 4 | newmtl Combined 5 | illum 4 6 | Kd 0.00 0.00 0.00 7 | Ka 0.00 0.00 0.00 8 | Tf 1.00 1.00 1.00 9 | Ni 1.00 10 | map_Kd base_diff.png 11 | -------------------------------------------------------------------------------- /resources/rendermodels/leap_motion_1_0/thumbnail_leap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/resources/rendermodels/leap_motion_1_0/thumbnail_leap.png -------------------------------------------------------------------------------- /resources/settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /resources/textures/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SDraw/driver_leap/f2c3050c6339e86c375cc8083a587561de4245ce/resources/textures/cursor.png -------------------------------------------------------------------------------- /vendor/JSL: -------------------------------------------------------------------------------- 1 | https://github.com/JibbSmart/JoyShockLibrary/releases/tag/v3.0 -------------------------------------------------------------------------------- /vendor/LeapSDK: -------------------------------------------------------------------------------- 1 | C:/Program Files/Ultraleap/LeapSDK --------------------------------------------------------------------------------