diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..6bfe0ca0 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +ko_fi: sdraw_ diff --git a/.gitignore b/.gitignore index 7e5b945d..1e8ed921 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ ipch *.opensdf *.opendb *.VC.db +bin \ No newline at end of file diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..fdea109d --- /dev/null +++ b/.gitmodules @@ -0,0 +1,9 @@ +[submodule "vendor/glm"] + path = vendor/glm + url = git://github.com/g-truc/glm.git +[submodule "vendor/pugixml"] + path = vendor/pugixml + url = https://github.com/zeux/pugixml.git +[submodule "vendor/openvr"] + path = vendor/openvr + url = https://github.com/ValveSoftware/openvr.git diff --git a/LICENSE b/LICENSE deleted file mode 100644 index ee83337d..00000000 --- a/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2015, Valve Corporation -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation and/or -other materials provided with the distribution. - -3. Neither the name of the copyright holder nor the names of its contributors -may be used to endorse or promote products derived from this software without -specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/Paths.props b/Paths.props deleted file mode 100644 index bbf5bf66..00000000 --- a/Paths.props +++ /dev/null @@ -1,26 +0,0 @@ - - - - - D:\Steam\steamapps\common\SteamVR - C:\Users\Christian Buchner\Documents\Visual Studio 2015\Projects\Leap\openvr-1.0.0 - C:\Users\Christian Buchner\Documents\Visual Studio 2015\Projects\Leap\LeapSDK - D:\Steam\steamapps\common\SteamVR\drivers\leap - - - - - - $(SteamVRRuntimeDir) - - - $(OpenVRDir) - - - $(LeapSDKDir) - - - $(InstallDir) - - - \ No newline at end of file diff --git a/README.md b/README.md index c1201d5e..17136686 100644 --- a/README.md +++ b/README.md @@ -1,161 +1,30 @@ -# Leap Motion Driver for SteamVR +# Warning +This projects is closed due to unmanageable memory issues that came along with new Gemini versions. -## Installation of this driver. - -- Get the Leap Motion Orion Beta runtimes https://developer.leapmotion.com/get-started -- Install the Visual C++ 2015 Update 2 redistributables (32 and 64 bits) https://www.microsoft.com/en-us/download/details.aspx?id=51682 -- Download the most recent zip file from the Releases section of this project and run the contained exe setup program https://github.com/cbuchner1/driver_leap/releases - -Start SteamVR to see if two additional controllers show up (they should be blinking if your hands are -not in the field of view of the Leap Motion, solid otherwise). - -### Troubleshooting - -If you experience frequent crashes of SteamVR on exit and this bothers you, uninstall my driver. I will try to fix this ASAP, but at the moment I have no clue why SteamVR is crashing. - - -## Note about WORK IN PROGRESS - -You're seeing an early version of this software. I've got positional tracking established now as well as hand pose tracking. Some experimental mappings of hand gestures to triggers and buttons were added: - -Trigger: -- bending of the index finger maps to the trigger button, like you would fire a gun. - -Grip: -- clenching the middle, ring, pinky finger to a fist maps to the grabbing buttons - -Trackpad: -- the thumbpress gesture (just point the thumb in the direction of your palm) touches and clicks the trackpad, depending on the intensity of your gesture. -- pointing the index finger towards the are of the other hand's palm will emulate the touchpad. To press the touchpad in the desired position use the tumbpress gesture simultaneously while pointing. - -Menu buttons: -- Flat hand held in front of you, palm towards face is used for application menu button -- the Timeout pose (as used in sports), registers as the system menu button - - -Swapped hands? - -when SteamVR confuses the left and right controller hands (which will be indicated by little hand icons shown near the bottom of the displayed Wand controllers), simply cross your hands the first time you bring them into view after starting SteamVR. This reverses the hand assignment and can improve the gaming experience for example in Audioshield. - - - - -I am working on allowing to freely map gestures to buttons in the steamvr.vrsettings config file in your Steam\config folder. However note that the "leap_gestures" section is currently not parsed yet. It's merely a sign of things to come. - -## Supported gestures - -There are other gestures detected currently, but not mapped to buttons. If you want to try these out, click on the application "gesture_checker.exe" in the directory C:\Program Files (x86)\SteamVR Leap Motion driver\leap\bin\Win32 - -Then I also recommend that you simultaneously bring up your Leap Motion's settings and from there start the diagnostic visualizer (the windowed version, not the VR one). Press "v" once to switch it to headmount optimized mode. - -Now pull both windows side by side and bring a hand into view. The command prompt running the gesture_checker program should output a series of numbers next to the names of the gestures. A "1.0" means confidential detection, a "0.0" means no detection. - -You can practise some gestures this way and also cross-check your pose in the Leap Motion diagnostic visualizer against the detection confidence. - - // Finger gestures (these would not throw your hand's orientation off much) - TriggerFinger, // bend your index finger as if pulling a trigger - LowerFist, // grab with your middle, ring, pinky fingers - Pinch, // pinch with your thumb and index fingers - Thumbpress, // point the thumb towards the direction of your pinky - - // Hand gestures (these would significantly change the orientation of your hand) - FlippingTheBird, // flip someone off with your middle finger - ILY, // pinky and index finger extended, middle and ring bent - Victory, // V shape with your index, middle fingers, other fingers curled - FlatHandPalmUp, // flat hand, palm points upwards (relative to alignment of Leap!) - FlatHandPalmDown, // flat hand, palm points downwards (relative to alignment of Leap!) - FlatHandPalmAway, // flat hand, palm points away from self (relative to alignment of Leap!) - FlatHandPalmTowards, // flat hand, palm points towards self (relative to alignment of Leap!) - ThumbUp, // thumb points up, remaining fingers form a fist - ThumbInward, // thumb points towards the left for the right hand and vice versa - - // Two handed gestures - Timeout, // both Hands form a T shape, signals a Timeout in sports - TouchpadAxisX, // Touchpad emulation: index finger of other hand points towards palm - TouchpadAxisY, // Touchpad emulation: index finger of other hand points towards palm - - -### Games/Experiences that work mostly - -- the Blu (all three stages) -- Irrational Exuberance: Prologue -- the Rose and I -- The Lab (some experiences work, others are tricky) -- Final Approach -- Audioshield: somehow the controllers are swapped? Control is tricky and not very precise. Semi-playable though. +# Driver Leap [![Release](http://img.shields.io/github/release/SDraw/driver_leap.svg)](../../releases/latest) +Fork with updated vendor libraries. -### Games/Experiences that are starting but not quite playable yet. - -- Tilt Brush: starts and you can start doing things, but there is lack of complete trackpad support in my driver. -- Brookhaven Experiment: tracking only works while SteamVR window is in focus. Why? Gun in right hand needs a 60 degree uptilt angle (define this in steamvr.vrsettings config file in Steam config folder). Trigger gesture detection is way to imprecise, you won't even survive the first wave of Zombies. - - -### Demos that won't work at all -- n/a - - -## Known Issues - -I am seeing SteamVR Server crash on shutdown a lot. This could be related to my driver, but I have not yet found the root cause for the crash. - -The Brookhaven experiment seems to steal focus from StreamVR, so that Steam does not get any position tracking. Clicking on the SteamVR window restores tracking, but mutes the audio on Brookhaven. Meh. - -Some games work better when no grip angle is added to the controller pose, other games actually require a steep angle to be playable (Brookhaven, Audioshield). We may have to add a feature to chose the preferred default pose at runtime. - -Tracking is not quite reliable to always detect my trigger gestures. I think we will have to integrate small handheld controllers like the Wiimote or the Playstation Move Navigation controller in the future. - -I do not think I will be able to get animated hands into the 3D view, as the render model you can assign to each controller is mostly a static object. There are some JSON files to map joystick axes and triggers to animated parts of the displayed controller. But the fingers do not directly map to joystick axes directly and hence cannot be shown. Also not all games make use of SteamVR's internal controller visualization. - - -## Building from Sourcecode (Developers only) - -### Install Dependencies - -1. Install SteamVR. It is under "Tools" in everyone's Steam Library. steam://install/250820 -2. Install "Leap Motion Orion SDK V3.1.2". https://developer.leapmotion.com/get-started -3. Fetch the OpenVR SDK 1.0.0 from https://github.com/ValveSoftware/openvr . - -The solution and project files are for Visual Studio 2015. - -### Configure Paths - -Under "Property Manager" in Visual Studio, expand any of the configurations and find "Paths". Right click and select "Properties" and then "User Macros". Modify the paths to match your setup. InstallDir will be created, and will be configured as an external driver path for SteamVR. - -### Build - -You will probably want to build Release x86. You can also build x64. The post-build step will install the binaries and copy the resources to the configured InstallDir and register that path with SteamVR. - -## Preapring The Leap Motion Driver for use (Developers only) - -After building, the InstallDir should be a complete binary distribution. To use it: - -1. Register it with the SteamVR runtime via "vrpathreg adddriver $(InstallDir)". This is done automatically by a Post-Build step, but if you copy the files elsewhere you will have to do it by hand. -2. Edit your config/steamvr.vrsettings to enable "activateMultipleDrivers". This is what allows the hydra driver to co-exist with any HMD. **Be sure to mind your commas.** Check vrserver.txt log to see if there were parse errors. Many of the settings are described at https://developer.valvesoftware.com/wiki/SteamVR/steamvr.vrsettings . -```{ - ... - "steamvr" : { - "activateMultipleDrivers" : true - } -}``` -3. If you are trying to use the Hydra driver without an HMD, you might want to enable driver_null (no HMD) or set "requireHmd": false. - -After starting SteamVR, you should see controllers blinking in the status window until you move your hands into the field of view. - -You can use "vrcmd" (with no arguments) to see a list of devices to verify things are working. -use "vrcmd" to verify things are loading: - -```... -Driver leap : 2 displays - leap (Serial number leap0_lefthand) - leap (Serial number leap0_righthand) -... +## Installation (for users) +* Install [Ultraleap Gemini v5.3.1](https://developer.leapmotion.com/tracking-software-download) +* Extract [latest release archive](../../releases/latest) to `/drivers` +* Add line in section `steamvr` of `/config/steamvr.vrsettings` file: +```JSON +"activateMultipleDrivers": true, ``` -You can also use "vrcmd --pollposes" (followed by an index number to limit the output) to see if things are working. - -## Licenses - -The code in this distribution is distributed under the terms of the LICENSE file in the root directory. - -The compiled driver and the install directory use the Leap Motion Orion SDK. Use subject to the terms of the Leap Motion SDK Agreement available at -https://developer.leapmotion.com/sdk_agreement. +## Usage +### Settings +Driver settings are configurated by editing `resources/settings.xml`. Available settings: +* `trackingLevel`: skeleton tracking style for OpenVR. Can be `partial` or `full`. `partial` by default. +* `handsReset`: marks controllers as out of range if hand for controller isn't detected by Leap Motion. `false` by default. +* `interpolation`: enables internal Leap Motion data capture interpolation. `false` by default. +* `useVelocity`: enables velocity data from Leap Motion for hands. `false` by default. + +### Gestures +List of hands gestures that correspond to controller original input: +* **Grip:** bending of middle, ring and pinky fingers +* **Trigger:** bending of index finger. + +### Notes +* Testing commits are currently pushed. +* If you see only green dots that represent tip of your index fingers, force application to launch on dGPU through control panel of your GPU vendor. diff --git a/driver.vrdrivermanifest b/driver.vrdrivermanifest new file mode 100644 index 00000000..37c4d97b --- /dev/null +++ b/driver.vrdrivermanifest @@ -0,0 +1,6 @@ +{ + "alwaysActivate": true, + "name" : "leap", + "directory" : "", + "resourceOnly" : false +} diff --git a/driver_leap.sln b/driver_leap.sln index e27313b9..ab45c045 100644 --- a/driver_leap.sln +++ b/driver_leap.sln @@ -1,68 +1,31 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +# Visual Studio 15 +VisualStudioVersion = 15.0.28307.1738 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver_leap", "drivers\driver_leap\driver_leap.vcxproj", "{52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "driver_leap", "driver_leap\driver_leap.vcxproj", "{52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "leap_monitor", "tools\leap_monitor\leap_monitor.vcxproj", "{BC06AF9C-36D6-455A-B421-00A9635684AD}" -EndProject -Project("{54435603-DBB4-11D2-8724-00A0C9A8B90C}") = "leap_installer", "tools\leap_installer\leap_installer.vdproj", "{60517323-2772-4341-9161-56C776DC1840}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gesture_checker", "tools\gesture_checker\gesture_checker.vcxproj", "{9C28E205-C4CD-43D4-91BC-4852D7A588EC}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "config_tool", "tools\config_tool\config_tool.vcxproj", "{FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "leap_control", "leap_control\leap_control.csproj", "{B156A0E6-BC15-4987-A1E8-F6D6E69786BC}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 Release|x64 = Release|x64 - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Debug|x64.ActiveCfg = Debug|x64 {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Debug|x64.Build.0 = Debug|x64 - {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Debug|x86.ActiveCfg = Debug|Win32 - {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Debug|x86.Build.0 = Debug|Win32 {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Release|x64.ActiveCfg = Release|x64 {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Release|x64.Build.0 = Release|x64 - {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Release|x86.ActiveCfg = Release|Win32 - {52D3F16D-A7A5-4D6F-8F17-5E4B459A1440}.Release|x86.Build.0 = Release|Win32 - {BC06AF9C-36D6-455A-B421-00A9635684AD}.Debug|x64.ActiveCfg = Debug|x64 - {BC06AF9C-36D6-455A-B421-00A9635684AD}.Debug|x64.Build.0 = Debug|x64 - {BC06AF9C-36D6-455A-B421-00A9635684AD}.Debug|x86.ActiveCfg = Debug|Win32 - {BC06AF9C-36D6-455A-B421-00A9635684AD}.Debug|x86.Build.0 = Debug|Win32 - {BC06AF9C-36D6-455A-B421-00A9635684AD}.Release|x64.ActiveCfg = Release|x64 - {BC06AF9C-36D6-455A-B421-00A9635684AD}.Release|x64.Build.0 = Release|x64 - {BC06AF9C-36D6-455A-B421-00A9635684AD}.Release|x86.ActiveCfg = Release|Win32 - {BC06AF9C-36D6-455A-B421-00A9635684AD}.Release|x86.Build.0 = Release|Win32 - {60517323-2772-4341-9161-56C776DC1840}.Debug|x64.ActiveCfg = Debug - {60517323-2772-4341-9161-56C776DC1840}.Debug|x64.Build.0 = Debug - {60517323-2772-4341-9161-56C776DC1840}.Debug|x86.ActiveCfg = Debug - {60517323-2772-4341-9161-56C776DC1840}.Debug|x86.Build.0 = Debug - {60517323-2772-4341-9161-56C776DC1840}.Release|x64.ActiveCfg = Release - {60517323-2772-4341-9161-56C776DC1840}.Release|x64.Build.0 = Release - {60517323-2772-4341-9161-56C776DC1840}.Release|x86.ActiveCfg = Release - {60517323-2772-4341-9161-56C776DC1840}.Release|x86.Build.0 = Release - {9C28E205-C4CD-43D4-91BC-4852D7A588EC}.Debug|x64.ActiveCfg = Debug|x64 - {9C28E205-C4CD-43D4-91BC-4852D7A588EC}.Debug|x64.Build.0 = Debug|x64 - {9C28E205-C4CD-43D4-91BC-4852D7A588EC}.Debug|x86.ActiveCfg = Debug|Win32 - {9C28E205-C4CD-43D4-91BC-4852D7A588EC}.Debug|x86.Build.0 = Debug|Win32 - {9C28E205-C4CD-43D4-91BC-4852D7A588EC}.Release|x64.ActiveCfg = Release|x64 - {9C28E205-C4CD-43D4-91BC-4852D7A588EC}.Release|x64.Build.0 = Release|x64 - {9C28E205-C4CD-43D4-91BC-4852D7A588EC}.Release|x86.ActiveCfg = Release|Win32 - {9C28E205-C4CD-43D4-91BC-4852D7A588EC}.Release|x86.Build.0 = Release|Win32 - {FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1}.Debug|x64.ActiveCfg = Debug|x64 - {FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1}.Debug|x64.Build.0 = Debug|x64 - {FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1}.Debug|x86.ActiveCfg = Debug|Win32 - {FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1}.Debug|x86.Build.0 = Debug|Win32 - {FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1}.Release|x64.ActiveCfg = Release|x64 - {FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1}.Release|x64.Build.0 = Release|x64 - {FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1}.Release|x86.ActiveCfg = Release|Win32 - {FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1}.Release|x86.Build.0 = Release|Win32 + {B156A0E6-BC15-4987-A1E8-F6D6E69786BC}.Debug|x64.ActiveCfg = Debug|x64 + {B156A0E6-BC15-4987-A1E8-F6D6E69786BC}.Debug|x64.Build.0 = Debug|x64 + {B156A0E6-BC15-4987-A1E8-F6D6E69786BC}.Release|x64.ActiveCfg = Release|x64 + {B156A0E6-BC15-4987-A1E8-F6D6E69786BC}.Release|x64.Build.0 = Release|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {5B906255-44C8-427C-8F9B-99D222337F78} + EndGlobalSection EndGlobal diff --git a/driver_leap/Core/CDriverConfig.cpp b/driver_leap/Core/CDriverConfig.cpp new file mode 100644 index 00000000..8ea7098f --- /dev/null +++ b/driver_leap/Core/CDriverConfig.cpp @@ -0,0 +1,93 @@ +#include "stdafx.h" + +#include "Core/CDriverConfig.h" + +#include "Utils/Utils.h" + +extern char g_modulePath[]; + +const std::vector g_settingNames +{ + "skeleton", "trackingLevel", + "handsReset", "interpolation", "velocity" +}; + +enum ConfigSetting : size_t +{ + CS_TrackingLevel = 0U, + CS_HandsReset, + CS_Interpolation, + CS_Velocity +}; + +const std::vector g_trackingLevels +{ + "partial", "full" +}; + +unsigned char CDriverConfig::ms_trackingLevel = CDriverConfig::TL_Partial; +bool CDriverConfig::ms_handsReset = false; +bool CDriverConfig::ms_interpolation = false; +bool CDriverConfig::ms_useVelocity = false; + +void CDriverConfig::Load() +{ + std::string l_path(g_modulePath); + l_path.erase(l_path.begin() + l_path.rfind('\\'), l_path.end()); + l_path.append("\\..\\..\\resources\\settings.xml"); + + pugi::xml_document *l_document = new pugi::xml_document(); + if(l_document->load_file(l_path.c_str())) + { + const pugi::xml_node l_root = l_document->child("settings"); + if(l_root) + { + for(pugi::xml_node l_node = l_root.child("setting"); l_node; l_node = l_node.next_sibling("setting")) + { + const pugi::xml_attribute l_attribName = l_node.attribute("name"); + const pugi::xml_attribute l_attribValue = l_node.attribute("value"); + if(l_attribName && l_attribValue) + { + switch(ReadEnumVector(l_attribName.as_string(), g_settingNames)) + { + case ConfigSetting::CS_TrackingLevel: + { + const size_t l_tableIndex = ReadEnumVector(l_attribValue.as_string(), g_trackingLevels); + if(l_tableIndex != std::numeric_limits::max()) ms_trackingLevel = static_cast(l_tableIndex); + } break; + case ConfigSetting::CS_HandsReset: + ms_handsReset = l_attribValue.as_bool(false); + break; + case ConfigSetting::CS_Interpolation: + ms_interpolation = l_attribValue.as_bool(false); + break; + case ConfigSetting::CS_Velocity: + ms_useVelocity = l_attribValue.as_bool(false); + break; + } + } + } + } + } + delete l_document; +} + +unsigned char CDriverConfig::GetTrackingLevel() +{ + return ms_trackingLevel; +} + +bool CDriverConfig::IsHandsResetEnabled() +{ + return ms_handsReset; +} + +bool CDriverConfig::IsInterpolationEnabled() +{ + return ms_interpolation; +} + +bool CDriverConfig::IsVelocityUsed() +{ + return ms_useVelocity; +} diff --git a/driver_leap/Core/CDriverConfig.h b/driver_leap/Core/CDriverConfig.h new file mode 100644 index 00000000..2e9e363e --- /dev/null +++ b/driver_leap/Core/CDriverConfig.h @@ -0,0 +1,27 @@ +#pragma once + +class CDriverConfig final +{ + static unsigned char ms_trackingLevel; + static bool ms_handsReset; + static bool ms_interpolation; + static bool ms_useVelocity; + + CDriverConfig() = delete; + ~CDriverConfig() = delete; + CDriverConfig(const CDriverConfig &that) = delete; + CDriverConfig& operator=(const CDriverConfig &that) = delete; +public: + enum TrackingLevel : unsigned char + { + TL_Partial = 0U, + TL_Full + }; + + static void Load(); + + static unsigned char GetTrackingLevel(); + static bool IsHandsResetEnabled(); + static bool IsInterpolationEnabled(); + static bool IsVelocityUsed(); +}; diff --git a/driver_leap/Core/CLeapPoller.cpp b/driver_leap/Core/CLeapPoller.cpp new file mode 100644 index 00000000..d3433be7 --- /dev/null +++ b/driver_leap/Core/CLeapPoller.cpp @@ -0,0 +1,189 @@ +#include "stdafx.h" + +#include "Core/CLeapPoller.h" + +CLeapPoller::CLeapPoller() +{ + m_active = false; + m_thread = nullptr; + m_connection = nullptr; + m_clockSynchronizer = nullptr; + m_connected = false; + m_allocator.allocate = CLeapPoller::AllocateMemory; + m_allocator.deallocate = CLeapPoller::DeallocateMemory; + m_allocator.state = nullptr; + m_lastFrame = nullptr; + m_newFrame = nullptr; + m_device = nullptr; +} + +CLeapPoller::~CLeapPoller() +{ + delete m_lastFrame; +} + +bool CLeapPoller::Initialize() +{ + if(!m_active) + { + if(LeapCreateConnection(nullptr, &m_connection) == eLeapRS_Success) + { + if(LeapOpenConnection(m_connection) == eLeapRS_Success) + { + LeapSetAllocator(m_connection, &m_allocator); + LeapCreateClockRebaser(&m_clockSynchronizer); + m_lastFrame = new LEAP_TRACKING_EVENT(); + m_newFrame = new LEAP_TRACKING_EVENT(); + m_active = true; + m_thread = new std::thread(&CLeapPoller::ThreadUpdate, this); + } + else + { + LeapDestroyConnection(m_connection); + m_connection = nullptr; + } + } + else m_connection = nullptr; + } + + return m_active; +} + +void CLeapPoller::Terminate() +{ + if(m_active) + { + m_active = false; + m_thread->join(); + m_thread = nullptr; + + if(m_device) LeapCloseDevice(m_device); + LeapDestroyClockRebaser(m_clockSynchronizer); + LeapCloseConnection(m_connection); + LeapDestroyConnection(m_connection); + + m_connection = nullptr; + m_clockSynchronizer = nullptr; + m_interpolatedFrameBuffer.clear(); + m_device = nullptr; + + delete m_lastFrame; + m_lastFrame = nullptr; + delete m_newFrame; + m_newFrame = nullptr; + } +} + +bool CLeapPoller::IsConnected() const +{ + return m_connected; +} + +const LEAP_TRACKING_EVENT* CLeapPoller::GetInterpolatedFrame() +{ + LEAP_TRACKING_EVENT *l_result = nullptr; + if(m_active) + { + if(!m_interpolatedFrameBuffer.empty()) l_result = reinterpret_cast(m_interpolatedFrameBuffer.data()); + } + return l_result; +} + +const LEAP_TRACKING_EVENT* CLeapPoller::GetFrame() +{ + LEAP_TRACKING_EVENT *l_result = nullptr; + if(m_active) l_result = m_lastFrame; + return l_result; +} + +void CLeapPoller::SetTrackingMode(eLeapTrackingMode f_mode) +{ + if(m_active) LeapSetTrackingMode(m_connection, f_mode); +} + +void CLeapPoller::SetPolicy(uint64_t f_set, uint64_t f_clear) +{ + if(m_active) LeapSetPolicyFlags(m_connection, f_set, f_clear); +} + +void CLeapPoller::SetPaused(bool f_state) +{ + if(m_active) LeapSetPause(m_connection, f_state); +} + +void CLeapPoller::Update() +{ + if(m_active) + { + LeapUpdateRebase(m_clockSynchronizer, std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), LeapGetNow()); + + if(m_frameLock.try_lock()) + { + std::memcpy(m_lastFrame, m_newFrame, sizeof(LEAP_TRACKING_EVENT)); + m_frameLock.unlock(); + } + + LEAP_CONNECTION_INFO l_info{ sizeof(LEAP_CONNECTION_INFO) }; + if(LeapGetConnectionInfo(m_connection, &l_info) == eLeapRS_Success) m_connected = (l_info.status == eLeapConnectionStatus_Connected); + else m_connected = false; + } +} + +void CLeapPoller::UpdateInterpolation() +{ + if(m_active) + { + int64_t l_targetFrameTime = 0; + uint64_t l_targetFrameSize = 0U; + LeapRebaseClock(m_clockSynchronizer, std::chrono::duration_cast(std::chrono::system_clock::now().time_since_epoch()).count(), &l_targetFrameTime); + + if(LeapGetFrameSize(m_connection, l_targetFrameTime, &l_targetFrameSize) == eLeapRS_Success) + { + // Weird SDK requires weird solutions + m_interpolatedFrameBuffer.resize(static_cast(l_targetFrameSize)); + LeapInterpolateFrame(m_connection, l_targetFrameTime, reinterpret_cast(m_interpolatedFrameBuffer.data()), l_targetFrameSize); + } + } +} + +void CLeapPoller::ThreadUpdate() +{ + const std::chrono::milliseconds l_threadDelay(1U); + while(m_active) + { + // Poll events + LEAP_CONNECTION_MESSAGE l_message{ sizeof(LEAP_CONNECTION_MESSAGE) }; + while(LeapPollConnection(m_connection, 0U, &l_message) == eLeapRS_Success) + { + if(l_message.type == eLeapEventType_None) break; + switch(l_message.type) + { + case eLeapEventType_Device: + { + if(!m_device) + { + if(LeapOpenDevice(l_message.device_event->device, &m_device) != eLeapRS_Success) m_device = nullptr; + } + } break; + case eLeapEventType_Tracking: + { + m_frameLock.lock(); + std::memcpy(m_newFrame, l_message.tracking_event, sizeof(LEAP_TRACKING_EVENT)); + m_frameLock.unlock(); + } break; + } + } + + std::this_thread::sleep_for(l_threadDelay); + } +} + +void* CLeapPoller::AllocateMemory(uint32_t size, eLeapAllocatorType typeHint, void *state) +{ + return new uint8_t[size]; +} + +void CLeapPoller::DeallocateMemory(void *ptr, void *state) +{ + delete[]reinterpret_cast(ptr); +} diff --git a/driver_leap/Core/CLeapPoller.h b/driver_leap/Core/CLeapPoller.h new file mode 100644 index 00000000..a0cb3666 --- /dev/null +++ b/driver_leap/Core/CLeapPoller.h @@ -0,0 +1,41 @@ +#pragma once + +class CLeapPoller +{ + std::atomic m_active; + std::mutex m_frameLock; + std::thread *m_thread; + + LEAP_CONNECTION m_connection; + LEAP_CLOCK_REBASER m_clockSynchronizer; + LEAP_ALLOCATOR m_allocator; + LEAP_TRACKING_EVENT *m_lastFrame; + LEAP_TRACKING_EVENT *m_newFrame; + std::vector m_interpolatedFrameBuffer; + LEAP_DEVICE m_device; + bool m_connected; + + void ThreadUpdate(); + + static void* AllocateMemory(uint32_t size, eLeapAllocatorType typeHint, void *state); + static void DeallocateMemory(void *ptr, void *state); +public: + CLeapPoller(); + ~CLeapPoller(); + + bool Initialize(); + void Terminate(); + + bool IsConnected() const; + const LEAP_TRACKING_EVENT* GetInterpolatedFrame(); + const LEAP_TRACKING_EVENT* GetFrame(); + + void SetPolicy(uint64_t f_set, uint64_t f_clear = 0U); + void SetTrackingMode(eLeapTrackingMode f_mode); + void SetPaused(bool f_state); + + void Update(); + void UpdateInterpolation(); +}; + + diff --git a/driver_leap/Core/CServerDriver.cpp b/driver_leap/Core/CServerDriver.cpp new file mode 100644 index 00000000..9755eee8 --- /dev/null +++ b/driver_leap/Core/CServerDriver.cpp @@ -0,0 +1,328 @@ +#include "stdafx.h" + +#include "Core/CServerDriver.h" +#include "Core/CLeapPoller.h" +#include "Devices/CLeapController/CLeapControllerIndex.h" +#include "Devices/CLeapStation.h" + +#include "Core/CDriverConfig.h" +#include "Utils/Utils.h" + +extern char g_modulePath[]; + +const std::vector g_debugRequests +{ + "input" +}; +enum DebugRequest : size_t +{ + DR_Input = 0U +}; + +const std::vector g_inputHands +{ + "left", "right" +}; +enum InputHands : size_t +{ + IH_LeftHand = 0U, + IH_RightHand +}; + +const std::vector g_buttonTypes +{ + "button", "axis" +}; +enum ButtonTypes : size_t +{ + BT_Button = 0U, + BT_Axis +}; + +const std::vector g_buttonNames +{ + "a", "b", "system" +}; +enum ButtonNames : size_t +{ + BN_A = 0U, + BN_B, + BN_System +}; + +const std::vector g_axisNames +{ + "thumbstick", "touchpad" +}; +enum AxisNames : size_t +{ + AN_Thumbstick = 0U, + AN_Touchpad +}; + +const std::vector g_buttonStates +{ + "none", "touched", "clicked" +}; +enum ButtonStates : size_t +{ + BS_None = 0U, + BS_Touched, + BS_Clicked +}; + +const char* const CServerDriver::ms_interfaces[] +{ + vr::ITrackedDeviceServerDriver_Version, + vr::IServerTrackedDeviceProvider_Version, + nullptr +}; + +CServerDriver::CServerDriver() +{ + m_leapPoller = nullptr; + m_connectionState = false; + for(size_t i = 0U; i < LCH_Count; i++) m_controllers[i] = nullptr; + m_leapStation = nullptr; +} + +CServerDriver::~CServerDriver() +{ +} + +// vr::IServerTrackedDeviceProvider +vr::EVRInitError CServerDriver::Init(vr::IVRDriverContext *pDriverContext) +{ + VR_INIT_SERVER_DRIVER_CONTEXT(pDriverContext); + CDriverConfig::Load(); + + // Relay device for events from leap_control + m_leapStation = new CLeapStation(this); + vr::VRServerDriverHost()->TrackedDeviceAdded(m_leapStation->GetSerialNumber().c_str(), vr::TrackedDeviceClass_TrackingReference, m_leapStation); + + m_controllers[LCH_Left] = new CLeapControllerIndex(CLeapController::CH_Left); + m_controllers[LCH_Right] = new CLeapControllerIndex(CLeapController::CH_Right); + + for(size_t i = 0U; i < LCH_Count; i++) + { + vr::VRServerDriverHost()->TrackedDeviceAdded(m_controllers[i]->GetSerialNumber().c_str(), vr::TrackedDeviceClass_Controller, m_controllers[i]); + } + + m_leapPoller = new CLeapPoller(); + if(m_leapPoller->Initialize()) + { + m_leapPoller->SetPolicy(eLeapPolicyFlag_AllowPauseResume); + m_leapPoller->SetTrackingMode(_eLeapTrackingMode::eLeapTrackingMode_HMD); + m_leapPoller->SetPolicy(eLeapPolicyFlag::eLeapPolicyFlag_OptimizeHMD, eLeapPolicyFlag::eLeapPolicyFlag_OptimizeScreenTop); + } + + // Start leap_control + std::string l_path(g_modulePath); + l_path.erase(l_path.begin() + l_path.rfind('\\'), l_path.end()); + + std::string l_appPath(l_path); + l_appPath.append("\\leap_control.exe"); + + STARTUPINFOA l_infoProcess = { 0 }; + PROCESS_INFORMATION l_monitorInfo = { 0 }; + l_infoProcess.cb = sizeof(STARTUPINFOA); + CreateProcessA(l_appPath.c_str(), NULL, NULL, NULL, FALSE, 0, NULL, l_path.c_str(), &l_infoProcess, &l_monitorInfo); + + return vr::VRInitError_None; +} + +void CServerDriver::Cleanup() +{ + for(size_t i = 0U; i < LCH_Count; i++) + { + delete m_controllers[i]; + m_controllers[i] = nullptr; + } + delete m_leapStation; + m_leapStation = nullptr; + + m_leapPoller->Terminate(); + delete m_leapPoller; + m_leapPoller = nullptr; + + VR_CLEANUP_SERVER_DRIVER_CONTEXT(); +} + +const char* const* CServerDriver::GetInterfaceVersions() +{ + return ms_interfaces; +} + +void CServerDriver::RunFrame() +{ + CLeapController::UpdateHMDCoordinates(); + m_leapPoller->Update(); + + if(m_connectionState != m_leapPoller->IsConnected()) + { + m_connectionState = m_leapPoller->IsConnected(); + m_leapStation->SetTrackingState(m_connectionState ? CLeapStation::TS_Connected : CLeapStation::TS_Search); + for(size_t i = 0U; i < LCH_Count; i++) + { + m_controllers[i]->SetEnabled(m_connectionState); + } + } + + LEAP_HAND *l_hands[LCH_Count] = { nullptr }; + if(m_connectionState) + { + if(CDriverConfig::IsInterpolationEnabled()) m_leapPoller->UpdateInterpolation(); + + const LEAP_TRACKING_EVENT *l_frame = (CDriverConfig::IsInterpolationEnabled() ? m_leapPoller->GetInterpolatedFrame() : m_leapPoller->GetFrame()); + if(l_frame) + { + for(size_t i = 0U; i < l_frame->nHands; i++) + { + if(!l_hands[l_frame->pHands[i].type]) l_hands[l_frame->pHands[i].type] = &l_frame->pHands[i]; + } + } + } + + // Update devices + for(size_t i = 0U; i < LCH_Count; i++) + { + m_controllers[i]->RunFrame(l_hands[i], l_hands[(i + 1) % LCH_Count]); + } + m_leapStation->RunFrame(); +} + +bool CServerDriver::ShouldBlockStandbyMode() +{ + return false; +} + +void CServerDriver::EnterStandby() +{ +} + +void CServerDriver::LeaveStandby() +{ +} + +// CServerDriver +void CServerDriver::ProcessExternalMessage(const char *f_message) +{ + std::stringstream l_stream(f_message); + std::string l_event; + + // Scary stuff + l_stream >> l_event; + if(!l_stream.fail() && !l_event.empty()) + { + switch(ReadEnumVector(l_event, g_debugRequests)) + { + case DR_Input: + { + std::string l_inputHand; + l_stream >> l_inputHand; + if(!l_stream.fail() && !l_inputHand.empty()) + { + size_t l_inputHandIndex = ReadEnumVector(l_inputHand, g_inputHands); + if(l_inputHandIndex != std::numeric_limits::max()) + { + std::string l_buttonType; + l_stream >> l_buttonType; + if(!l_stream.fail() && !l_buttonType.empty()) + { + size_t l_buttonTypeIndex = ReadEnumVector(l_buttonType, g_buttonTypes); + if(l_buttonTypeIndex != std::numeric_limits::max()) + { + switch(l_buttonTypeIndex) + { + case ButtonTypes::BT_Button: + { + std::string l_buttonName; + l_stream >> l_buttonName; + if(!l_stream.fail() && !l_buttonName.empty()) + { + size_t l_buttonNameIndex = ReadEnumVector(l_buttonName, g_buttonNames); + if(l_buttonNameIndex != std::numeric_limits::max()) + { + std::string l_buttonState; + l_stream >> l_buttonState; + if(!l_stream.fail() && !l_buttonState.empty()) + { + size_t l_buttonStateIndex = ReadEnumVector(l_buttonState, g_buttonStates); + if(l_buttonStateIndex != std::numeric_limits::max()) + { + switch(l_buttonNameIndex) + { + case ButtonNames::BN_A: + { + m_controllers[l_inputHandIndex]->SetButtonState(CLeapControllerIndex::IB_ATouch, l_buttonStateIndex >= ButtonStates::BS_Touched); + m_controllers[l_inputHandIndex]->SetButtonState(CLeapControllerIndex::IB_AClick, l_buttonStateIndex >= ButtonStates::BS_Clicked); + } break; + case ButtonNames::BN_B: + { + m_controllers[l_inputHandIndex]->SetButtonState(CLeapControllerIndex::IB_BTouch, l_buttonStateIndex >= ButtonStates::BS_Touched); + m_controllers[l_inputHandIndex]->SetButtonState(CLeapControllerIndex::IB_BClick, l_buttonStateIndex >= ButtonStates::BS_Clicked); + } break; + case ButtonNames::BN_System: + { + m_controllers[l_inputHandIndex]->SetButtonState(CLeapControllerIndex::IB_SystemTouch, l_buttonStateIndex >= ButtonStates::BS_Touched); + m_controllers[l_inputHandIndex]->SetButtonState(CLeapControllerIndex::IB_SystemClick, l_buttonStateIndex >= ButtonStates::BS_Clicked); + } break; + } + } + } + } + } + } break; + + case ButtonTypes::BT_Axis: + { + std::string l_axisName; + l_stream >> l_axisName; + if(!l_stream.fail() && !l_axisName.empty()) + { + size_t l_axisNameIndex = ReadEnumVector(l_axisName, g_axisNames); + if(l_axisNameIndex != std::numeric_limits::max()) + { + std::string l_buttonState; + l_stream >> l_buttonState; + if(!l_stream.fail() && !l_buttonState.empty()) + { + size_t l_buttonStateIndex = ReadEnumVector(l_buttonState, g_buttonStates); + if(l_buttonStateIndex != std::numeric_limits::max()) + { + glm::vec2 l_axisValues(0.f); + l_stream >> l_axisValues.x >> l_axisValues.y; + if(!l_stream.fail()) + { + switch(l_axisNameIndex) + { + case AxisNames::AN_Thumbstick: + { + m_controllers[l_inputHandIndex]->SetButtonState(CLeapControllerIndex::IB_ThumbstickTouch, l_buttonStateIndex >= ButtonStates::BS_Touched); + m_controllers[l_inputHandIndex]->SetButtonState(CLeapControllerIndex::IB_ThumbstickClick, l_buttonStateIndex >= ButtonStates::BS_Clicked); + m_controllers[l_inputHandIndex]->SetButtonValue(CLeapControllerIndex::IB_ThumbstickX, (l_buttonStateIndex >= ButtonStates::BS_Touched) ? l_axisValues.x : 0.f); + m_controllers[l_inputHandIndex]->SetButtonValue(CLeapControllerIndex::IB_ThumbstickY, (l_buttonStateIndex >= ButtonStates::BS_Touched) ? l_axisValues.y : 0.f); + } break; + case AxisNames::AN_Touchpad: + { + m_controllers[l_inputHandIndex]->SetButtonState(CLeapControllerIndex::IB_TrackpadTouch, l_buttonStateIndex >= ButtonStates::BS_Touched); + m_controllers[l_inputHandIndex]->SetButtonValue(CLeapControllerIndex::IB_TrackpadForce, (l_buttonStateIndex == ButtonStates::BS_Clicked) ? 1.f : 0.f); + m_controllers[l_inputHandIndex]->SetButtonValue(CLeapControllerIndex::IB_TrackpadX, (l_buttonStateIndex >= ButtonStates::BS_Touched) ? l_axisValues.x : 0.f); + m_controllers[l_inputHandIndex]->SetButtonValue(CLeapControllerIndex::IB_TrackpadY, (l_buttonStateIndex >= ButtonStates::BS_Touched) ? l_axisValues.y : 0.f); + } break; + } + } + } + } + } + } + } break; + } + } + } + } + } + } break; + } + } +} diff --git a/driver_leap/Core/CServerDriver.h b/driver_leap/Core/CServerDriver.h new file mode 100644 index 00000000..c8babcab --- /dev/null +++ b/driver_leap/Core/CServerDriver.h @@ -0,0 +1,42 @@ +#pragma once + +class CLeapPoller; +class CLeapControllerIndex; +class CLeapStation; + +class CServerDriver final : public vr::IServerTrackedDeviceProvider +{ + enum LeapControllerHand : size_t + { + LCH_Left = 0U, + LCH_Right = 1U, + + LCH_Count + }; + + static const char* const ms_interfaces[]; + + bool m_connectionState; + CLeapPoller *m_leapPoller; + CLeapControllerIndex *m_controllers[LCH_Count]; + CLeapStation *m_leapStation; + + CServerDriver(const CServerDriver &that) = delete; + CServerDriver& operator=(const CServerDriver &that) = delete; + + void TryToPause(); + + // vr::IServerTrackedDeviceProvider + vr::EVRInitError Init(vr::IVRDriverContext *pDriverContext); + void Cleanup(); + const char* const* GetInterfaceVersions(); + void RunFrame(); + bool ShouldBlockStandbyMode(); + void EnterStandby(); + void LeaveStandby(); +public: + CServerDriver(); + ~CServerDriver(); + + void ProcessExternalMessage(const char *f_message); +}; diff --git a/driver_leap/Devices/CLeapController/CControllerButton.cpp b/driver_leap/Devices/CLeapController/CControllerButton.cpp new file mode 100644 index 00000000..01b04311 --- /dev/null +++ b/driver_leap/Devices/CLeapController/CControllerButton.cpp @@ -0,0 +1,80 @@ +#include "stdafx.h" + +#include "Devices/CLeapController/CControllerButton.h" + +CControllerButton::CControllerButton() +{ + m_handle = vr::k_ulInvalidInputComponentHandle; + m_inputType = IT_Boolean; + m_state = false; + m_value = 0.f; + m_updated = false; +} + +CControllerButton::~CControllerButton() +{ +} + +vr::VRInputComponentHandle_t CControllerButton::GetHandle() const +{ + return m_handle; +} + +vr::VRInputComponentHandle_t& CControllerButton::GetHandleRef() +{ + return m_handle; +} + +void CControllerButton::SetInputType(unsigned char f_type) +{ + m_inputType = f_type; +} + +unsigned char CControllerButton::GetInputType() const +{ + return m_inputType; +} + +void CControllerButton::SetState(bool f_state) +{ + if(m_inputType == IT_Boolean) + { + if(m_state != f_state) + { + m_state = f_state; + m_updated = true; + } + } +} + +bool CControllerButton::GetState() const +{ + return m_state; +} + +void CControllerButton::SetValue(float f_value) +{ + if(m_inputType == IT_Float) + { + if(m_value != f_value) + { + m_value = f_value; + m_updated = true; + } + } +} + +float CControllerButton::GetValue() const +{ + return m_value; +} + +bool CControllerButton::IsUpdated() const +{ + return m_updated; +} + +void CControllerButton::ResetUpdate() +{ + m_updated = false; +} diff --git a/driver_leap/Devices/CLeapController/CControllerButton.h b/driver_leap/Devices/CLeapController/CControllerButton.h new file mode 100644 index 00000000..a7eb7332 --- /dev/null +++ b/driver_leap/Devices/CLeapController/CControllerButton.h @@ -0,0 +1,38 @@ +#pragma once + +class CControllerButton final +{ + vr::VRInputComponentHandle_t m_handle; + unsigned char m_inputType; + float m_value; + bool m_state; + bool m_updated; + + CControllerButton(const CControllerButton &that) = delete; + CControllerButton& operator=(const CControllerButton &that) = delete; +public: + enum InputType : unsigned char + { + IT_None = 0U, + IT_Boolean, + IT_Float + }; + + CControllerButton(); + ~CControllerButton(); + + vr::VRInputComponentHandle_t GetHandle() const; + vr::VRInputComponentHandle_t& GetHandleRef(); + + void SetInputType(unsigned char f_type); + unsigned char GetInputType() const; + + void SetState(bool f_state); + bool GetState() const; + + void SetValue(float f_value); + float GetValue() const; + + bool IsUpdated() const; + void ResetUpdate(); +}; diff --git a/driver_leap/Devices/CLeapController/CLeapController.cpp b/driver_leap/Devices/CLeapController/CLeapController.cpp new file mode 100644 index 00000000..951f5c1b --- /dev/null +++ b/driver_leap/Devices/CLeapController/CLeapController.cpp @@ -0,0 +1,235 @@ +#include "stdafx.h" + +#include "Devices/CLeapController/CLeapController.h" +#include "Devices/CLeapController/CControllerButton.h" + +#include "Core/CDriverConfig.h" +#include "Utils/Utils.h" + +const glm::quat g_reverseRotation(0.f, 0.f, 0.70106769f, -0.70106769f); +const glm::quat g_rotateHalfPiZ(0.70106769f, 0.f, 0.f, 0.70106769f); +const glm::quat g_rotateHalfPiZN(0.70106769f, 0.f, 0.f, -0.70106769f); +const vr::HmdQuaternion_t g_vrZeroRotation = { 1.0, .0, .0, .0 }; + +double CLeapController::ms_headPosition[] = { .0, .0, .0 }; +vr::HmdQuaternion_t CLeapController::ms_headRotation = { 1.0, .0, .0, .0 }; + +CLeapController::CLeapController() +{ + m_propertyContainer = vr::k_ulInvalidPropertyContainer; + m_trackedDevice = vr::k_unTrackedDeviceIndexInvalid; + m_haptic = vr::k_ulInvalidPropertyContainer; + + m_pose = { 0 }; + m_pose.deviceIsConnected = false; + for(size_t i = 0U; i < 3U; i++) + { + m_pose.vecAcceleration[i] = .0; + m_pose.vecAngularAcceleration[i] = .0; + m_pose.vecAngularVelocity[i] = .0; + m_pose.vecDriverFromHeadTranslation[i] = .0; + } + m_pose.poseTimeOffset = .0; + m_pose.qDriverFromHeadRotation = g_vrZeroRotation; + m_pose.qRotation = g_vrZeroRotation; + m_pose.qWorldFromDriverRotation = g_vrZeroRotation; + m_pose.result = vr::TrackingResult_Uninitialized; + m_pose.shouldApplyHeadModel = false; + m_pose.willDriftInYaw = false; + + m_hand = CH_Left; + m_type = CT_Invalid; +} + +CLeapController::~CLeapController() +{ + for(auto l_button : m_buttons) delete l_button; +} + +// vr::ITrackedDeviceServerDriver +vr::EVRInitError CLeapController::Activate(uint32_t unObjectId) +{ + vr::EVRInitError l_resultError = vr::VRInitError_Driver_Failed; + + if(m_trackedDevice == vr::k_unTrackedDeviceIndexInvalid) + { + m_trackedDevice = unObjectId; + m_propertyContainer = vr::VRProperties()->TrackedDeviceToPropertyContainer(m_trackedDevice); + + ActivateInternal(); + + l_resultError = vr::VRInitError_None; + } + + return l_resultError; +} + +void CLeapController::Deactivate() +{ + ResetControls(); + m_trackedDevice = vr::k_unTrackedDeviceIndexInvalid; +} + +void CLeapController::EnterStandby() +{ +} + +void* CLeapController::GetComponent(const char* pchComponentNameAndVersion) +{ + void *l_result = nullptr; + if(!strcmp(pchComponentNameAndVersion, vr::ITrackedDeviceServerDriver_Version)) l_result = dynamic_cast(this); + return l_result; +} + +void CLeapController::DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) +{ +} + +vr::DriverPose_t CLeapController::GetPose() +{ + return m_pose; +} + +// CLeapController +bool CLeapController::IsEnabled() const +{ + return m_pose.deviceIsConnected; +} + +void CLeapController::SetEnabled(bool f_state) +{ + m_pose.deviceIsConnected = f_state; + if(m_trackedDevice != vr::k_unTrackedDeviceIndexInvalid) vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_trackedDevice, m_pose, sizeof(vr::DriverPose_t)); +} + +const std::string& CLeapController::GetSerialNumber() const +{ + return m_serialNumber; +} + +void CLeapController::ResetControls() +{ + for(auto l_button : m_buttons) + { + l_button->SetValue(0.f); + l_button->SetState(false); + } +} + +void CLeapController::RunFrame(const LEAP_HAND *f_hand, const LEAP_HAND *f_oppHand) +{ + if(m_trackedDevice != vr::k_unTrackedDeviceIndexInvalid) + { + if(m_pose.deviceIsConnected) + { + UpdateTransformation(f_hand); + vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_trackedDevice, m_pose, sizeof(vr::DriverPose_t)); + + UpdateGestures(f_hand, f_oppHand); + UpdateInput(); + } + else vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_trackedDevice, m_pose, sizeof(vr::DriverPose_t)); + } +} + +void CLeapController::UpdateInput() +{ + for(auto l_button : m_buttons) + { + if(l_button->IsUpdated()) + { + switch(l_button->GetInputType()) + { + case CControllerButton::IT_Boolean: + vr::VRDriverInput()->UpdateBooleanComponent(l_button->GetHandle(), l_button->GetState(), .0); + break; + case CControllerButton::IT_Float: + vr::VRDriverInput()->UpdateScalarComponent(l_button->GetHandle(), l_button->GetValue(), .0); + break; + } + l_button->ResetUpdate(); + } + } + UpdateInputInternal(); +} + +void CLeapController::UpdateTransformation(const LEAP_HAND *f_hand) +{ + m_pose.poseIsValid = (f_hand != nullptr); + + if(f_hand) + { + std::memcpy(m_pose.vecWorldFromDriverTranslation, ms_headPosition, sizeof(double) * 3U); + + const LEAP_VECTOR l_palmPosition = f_hand->palm.position; + const LEAP_QUATERNION l_palmOrientation = f_hand->palm.orientation; + + std::memcpy(&m_pose.qWorldFromDriverRotation, &ms_headRotation, sizeof(vr::HmdQuaternion_t)); + + m_pose.vecPosition[0] = -0.001f*l_palmPosition.x; + m_pose.vecPosition[1] = -0.001f*l_palmPosition.z; + m_pose.vecPosition[2] = -0.001f*l_palmPosition.y; + + if(CDriverConfig::IsVelocityUsed()) + { + const LEAP_VECTOR l_palmVelocity = f_hand->palm.velocity; + glm::vec3 l_resultVelocity(-0.001f*l_palmVelocity.x, -0.001f*l_palmVelocity.z, -0.001f*l_palmVelocity.y); + l_resultVelocity = glm::quat(ms_headRotation.w, ms_headRotation.x, ms_headRotation.y, ms_headRotation.z) * l_resultVelocity; + m_pose.vecVelocity[0] = l_resultVelocity.x; + m_pose.vecVelocity[1] = l_resultVelocity.y; + m_pose.vecVelocity[2] = l_resultVelocity.z; + } + + glm::quat l_rotation(l_palmOrientation.w, l_palmOrientation.x, l_palmOrientation.y, l_palmOrientation.z); + l_rotation = g_reverseRotation * l_rotation; + l_rotation *= ((m_hand == CH_Left) ? g_rotateHalfPiZN : g_rotateHalfPiZ); + l_rotation = glm::normalize(l_rotation); + + m_pose.qRotation.x = l_rotation.x; + m_pose.qRotation.y = l_rotation.y; + m_pose.qRotation.z = l_rotation.z; + m_pose.qRotation.w = l_rotation.w; + m_pose.result = vr::TrackingResult_Running_OK; + } + else + { + for(size_t i = 0U; i < 3U; i++) m_pose.vecVelocity[i] = .0; + if(CDriverConfig::IsHandsResetEnabled()) m_pose.result = vr::TrackingResult_Running_OutOfRange; + else + { + m_pose.result = vr::TrackingResult_Running_OK; + m_pose.poseIsValid = true; + } + } +} + +void CLeapController::ActivateInternal() +{ +} + +void CLeapController::UpdateGestures(const LEAP_HAND *f_hand, const LEAP_HAND *f_oppHand) +{ +} + +void CLeapController::UpdateInputInternal() +{ +} + +void CLeapController::UpdateHMDCoordinates() +{ + vr::TrackedDevicePose_t l_hmdPose; + vr::VRServerDriverHost()->GetRawTrackedDevicePoses(0.f, &l_hmdPose, 1U); // HMD has device ID 0 + if(l_hmdPose.bPoseIsValid) + { + glm::mat4 l_rotMat(1.f); + ConvertMatrix(l_hmdPose.mDeviceToAbsoluteTracking, l_rotMat); + + const glm::quat l_headRot = glm::quat_cast(l_rotMat); + ms_headRotation.x = l_headRot.x; + ms_headRotation.y = l_headRot.y; + ms_headRotation.z = l_headRot.z; + ms_headRotation.w = l_headRot.w; + + for(size_t i = 0U; i < 3U; i++) ms_headPosition[i] = l_hmdPose.mDeviceToAbsoluteTracking.m[i][3]; + } +} diff --git a/driver_leap/Devices/CLeapController/CLeapController.h b/driver_leap/Devices/CLeapController/CLeapController.h new file mode 100644 index 00000000..5f4f393b --- /dev/null +++ b/driver_leap/Devices/CLeapController/CLeapController.h @@ -0,0 +1,68 @@ +#pragma once + +class CControllerButton; + +class CLeapController : public vr::ITrackedDeviceServerDriver +{ + static double ms_headPosition[3U]; + static vr::HmdQuaternion_t ms_headRotation; + + vr::DriverPose_t m_pose; + + CLeapController(const CLeapController &that) = delete; + CLeapController& operator=(const CLeapController &that) = delete; + + void ResetControls(); + void UpdateInput(); + void UpdateTransformation(const LEAP_HAND *f_hand); + + // vr::ITrackedDeviceServerDriver + vr::EVRInitError Activate(uint32_t unObjectId); + void Deactivate(); + void EnterStandby(); + void* GetComponent(const char* pchComponentNameAndVersion); + void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize); + vr::DriverPose_t GetPose(); +public: + enum ControllerHand : unsigned char + { + CH_Left = 0U, + CH_Right, + + CH_Count + }; + enum ControllerType : unsigned char + { + CT_ViveWand = 0U, + CT_IndexKnuckle, + CT_OculusTouch, + + CT_Count, + CT_Invalid = 0xFFU + }; + + CLeapController(); + virtual ~CLeapController(); + + const std::string& GetSerialNumber() const; + + bool IsEnabled() const; + void SetEnabled(bool f_state); + + void RunFrame(const LEAP_HAND *f_hand, const LEAP_HAND *f_oppHand); + + static void UpdateHMDCoordinates(); +protected: + uint32_t m_trackedDevice; + vr::PropertyContainerHandle_t m_propertyContainer; + vr::VRInputComponentHandle_t m_haptic; + + std::string m_serialNumber; + unsigned char m_hand; + unsigned char m_type; + std::vector m_buttons; + + virtual void ActivateInternal(); + virtual void UpdateGestures(const LEAP_HAND *f_hand, const LEAP_HAND *f_oppHand); + virtual void UpdateInputInternal(); +}; diff --git a/driver_leap/Devices/CLeapController/CLeapControllerIndex.cpp b/driver_leap/Devices/CLeapController/CLeapControllerIndex.cpp new file mode 100644 index 00000000..d30feb2c --- /dev/null +++ b/driver_leap/Devices/CLeapController/CLeapControllerIndex.cpp @@ -0,0 +1,358 @@ +#include "stdafx.h" + +#include "Devices/CLeapController/CLeapControllerIndex.h" + +#include "Devices/CLeapController/CControllerButton.h" +#include "Core/CDriverConfig.h" +#include "Utils/CGestureMatcher.h" +#include "Utils/Utils.h" + +extern const glm::mat4 g_identityMatrix; +extern const vr::VRBoneTransform_t g_openHandGesture[]; +extern const glm::vec4 g_zeroPoint; + +enum HandFinger : size_t +{ + HF_Thumb = 0U, + HF_Index, + HF_Middle, + HF_Ring, + HF_Pinky, + + HF_Count +}; + +CLeapControllerIndex::CLeapControllerIndex(unsigned char f_hand) +{ + m_hand = (f_hand % CH_Count); + m_type = CT_IndexKnuckle; + m_serialNumber.assign((m_hand == CH_Left) ? "LHR-E217CD00" : "LHR-E217CD01"); + + for(size_t i = 0U; i < HSB_Count; i++) m_boneTransform[i] = g_openHandGesture[i]; + m_skeletonHandle = vr::k_ulInvalidInputComponentHandle; + + if(m_hand == CH_Right) + { + // Transformation inversion along 0YZ plane + for(size_t i = 1U; i < HSB_Count; i++) + { + m_boneTransform[i].position.v[0] *= -1.f; + + switch(i) + { + case HSB_Wrist: + { + m_boneTransform[i].orientation.y *= -1.f; + m_boneTransform[i].orientation.z *= -1.f; + } break; + + case HSB_Thumb0: + case HSB_IndexFinger0: + case HSB_MiddleFinger0: + case HSB_RingFinger0: + case HSB_PinkyFinger0: + { + m_boneTransform[i].orientation.z *= -1.f; + std::swap(m_boneTransform[i].orientation.x, m_boneTransform[i].orientation.w); + m_boneTransform[i].orientation.w *= -1.f; + std::swap(m_boneTransform[i].orientation.y, m_boneTransform[i].orientation.z); + } break; + } + } + } + +} + +CLeapControllerIndex::~CLeapControllerIndex() +{ +} + +void CLeapControllerIndex::ChangeBoneOrientation(glm::quat &f_rot) +{ + std::swap(f_rot.x, f_rot.z); + f_rot.z *= -1.f; + if(m_hand == CH_Left) + { + f_rot.x *= -1.f; + f_rot.y *= -1.f; + } +} + +void CLeapControllerIndex::ChangeAuxTransformation(glm::vec3 &f_pos, glm::quat &f_rot) +{ + f_pos.y *= -1.f; + f_pos.z *= -1.f; + + std::swap(f_rot.x, f_rot.w); + f_rot.w *= -1.f; + std::swap(f_rot.y, f_rot.z); + f_rot.y *= -1.f; +} + +size_t CLeapControllerIndex::GetFingerBoneIndex(size_t f_id) +{ + size_t l_result = 0U; + switch(f_id) + { + case HF_Thumb: + l_result = HSB_Thumb0; + break; + case HF_Index: + l_result = HSB_IndexFinger0; + break; + case HF_Middle: + l_result = HSB_MiddleFinger0; + break; + case HF_Ring: + l_result = HSB_RingFinger0; + break; + case HF_Pinky: + l_result = HSB_PinkyFinger0; + break; + } + return l_result; +} + +void CLeapControllerIndex::ActivateInternal() +{ + // Properties + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_TrackingSystemName_String, "lighthouse"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_SerialNumber_String, m_serialNumber.c_str()); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_WillDriftInYaw_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_DeviceIsWireless_Bool, true); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_DeviceIsCharging_Bool, false); + vr::VRProperties()->SetFloatProperty(m_propertyContainer, vr::Prop_DeviceBatteryPercentage_Float, 1.f); // Always charged + + vr::HmdMatrix34_t l_matrix = { -1.f, 0.f, 0.f, 0.f, 0.f, 0.f, -1.f, 0.f, 0.f, -1.f, 0.f, 0.f }; + vr::VRProperties()->SetProperty(m_propertyContainer, vr::Prop_StatusDisplayTransform_Matrix34, &l_matrix, sizeof(vr::HmdMatrix34_t), vr::k_unHmdMatrix34PropertyTag); + + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_Firmware_UpdateAvailable_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_Firmware_ManualUpdate_Bool, false); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_Firmware_ManualUpdateURL_String, "https://developer.valvesoftware.com/wiki/SteamVR/HowTo_Update_Firmware"); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_DeviceProvidesBatteryStatus_Bool, true); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_DeviceCanPowerOff_Bool, true); + vr::VRProperties()->SetInt32Property(m_propertyContainer, vr::Prop_DeviceClass_Int32, vr::TrackedDeviceClass_Controller); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_Firmware_ForceUpdateRequired_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_Identifiable_Bool, true); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_Firmware_RemindUpdate_Bool, false); + vr::VRProperties()->SetInt32Property(m_propertyContainer, vr::Prop_Axis0Type_Int32, vr::k_eControllerAxis_TrackPad); + vr::VRProperties()->SetInt32Property(m_propertyContainer, vr::Prop_Axis1Type_Int32, vr::k_eControllerAxis_Trigger); + vr::VRProperties()->SetInt32Property(m_propertyContainer, vr::Prop_ControllerRoleHint_Int32, (m_hand == CH_Left) ? vr::TrackedControllerRole_LeftHand : vr::TrackedControllerRole_RightHand); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_HasDisplayComponent_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_HasCameraComponent_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_HasDriverDirectModeComponent_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyContainer, vr::Prop_HasVirtualDisplayComponent_Bool, false); + vr::VRProperties()->SetInt32Property(m_propertyContainer, vr::Prop_ControllerHandSelectionPriority_Int32, 0); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_ModelNumber_String, (m_hand == CH_Left) ? "Knuckles Left" : "Knuckles Right"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_RenderModelName_String, (m_hand == CH_Left) ? "{indexcontroller}valve_controller_knu_1_0_left" : "{indexcontroller}valve_controller_knu_1_0_right"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_ManufacturerName_String, "Valve"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_TrackingFirmwareVersion_String, "1562916277 watchman@ValveBuilder02 2019-07-12 FPGA 538(2.26/10/2) BL 0 VRC 1562916277 Radio 1562882729"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_HardwareRevision_String, "product 17 rev 14.1.9 lot 2019/4/20 0"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_ConnectedWirelessDongle_String, "C2F75F5986-DIY"); // Changed + vr::VRProperties()->SetUint64Property(m_propertyContainer, vr::Prop_HardwareRevision_Uint64, 286130441U); + vr::VRProperties()->SetUint64Property(m_propertyContainer, vr::Prop_FirmwareVersion_Uint64, 1562916277U); + vr::VRProperties()->SetUint64Property(m_propertyContainer, vr::Prop_FPGAVersion_Uint64, 538U); + vr::VRProperties()->SetUint64Property(m_propertyContainer, vr::Prop_VRCVersion_Uint64, 1562916277U); + vr::VRProperties()->SetUint64Property(m_propertyContainer, vr::Prop_RadioVersion_Uint64, 1562882729U); + vr::VRProperties()->SetUint64Property(m_propertyContainer, vr::Prop_DongleVersion_Uint64, 1558748372U); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_Firmware_ProgrammingTarget_String, (m_hand == CH_Left) ? "LHR-E217CD00" : "LHR-E217CD01"); // Changed + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_ResourceRoot_String, "indexcontroller"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_RegisteredDeviceType_String, (m_hand == CH_Left) ? "valve/index_controllerLHR-E217CD00" : "valve/index_controllerLHR-E217CD01"); // Changed + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_InputProfilePath_String, "{indexcontroller}/input/index_controller_profile.json"); + vr::VRProperties()->SetInt32Property(m_propertyContainer, vr::Prop_Axis2Type_Int32, vr::k_eControllerAxis_Trigger); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_NamedIconPathDeviceOff_String, (m_hand == CH_Left) ? "{indexcontroller}/icons/left_controller_status_off.png" : "{indexcontroller}/icons/right_controller_status_off.png"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_NamedIconPathDeviceSearching_String, (m_hand == CH_Left) ? "{indexcontroller}/icons/left_controller_status_searching.gif" : "{indexcontroller}/icons/right_controller_status_searching.gif"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_NamedIconPathDeviceSearchingAlert_String, (m_hand == CH_Left) ? "{indexcontroller}/icons/left_controller_status_searching_alert.gif" : "{indexcontroller}/icons//right_controller_status_searching_alert.gif"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_NamedIconPathDeviceReady_String, (m_hand == CH_Left) ? "{indexcontroller}/icons/left_controller_status_ready.png" : "{indexcontroller}/icons//right_controller_status_ready.png"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_NamedIconPathDeviceReadyAlert_String, (m_hand == CH_Left) ? "{indexcontroller}/icons/left_controller_status_ready_alert.png" : "{indexcontroller}/icons//right_controller_status_ready_alert.png"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_NamedIconPathDeviceNotReady_String, (m_hand == CH_Left) ? "{indexcontroller}/icons/left_controller_status_error.png" : "{indexcontroller}/icons//right_controller_status_error.png"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_NamedIconPathDeviceStandby_String, (m_hand == CH_Left) ? "{indexcontroller}/icons/left_controller_status_off.png" : "{indexcontroller}/icons//right_controller_status_off.png"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_NamedIconPathDeviceAlertLow_String, (m_hand == CH_Left) ? "{indexcontroller}/icons/left_controller_status_ready_low.png" : "{indexcontroller}/icons//right_controller_status_ready_low.png"); + vr::VRProperties()->SetStringProperty(m_propertyContainer, vr::Prop_ControllerType_String, "knuckles"); + + // Input + if(m_buttons.empty()) + { + for(size_t i = 0U; i < IB_Count; i++) m_buttons.push_back(new CControllerButton()); + } + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/system/click", &m_buttons[IB_SystemClick]->GetHandleRef()); + m_buttons[IB_SystemClick]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/system/touch", &m_buttons[IB_SystemTouch]->GetHandleRef()); + m_buttons[IB_SystemTouch]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/trigger/click", &m_buttons[IB_TriggerClick]->GetHandleRef()); + m_buttons[IB_TriggerClick]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/trigger/value", &m_buttons[IB_TriggerValue]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + m_buttons[IB_TriggerValue]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/trackpad/x", &m_buttons[IB_TrackpadX]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + m_buttons[IB_TrackpadX]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/trackpad/y", &m_buttons[IB_TrackpadY]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + m_buttons[IB_TrackpadY]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/trackpad/touch", &m_buttons[IB_TrackpadTouch]->GetHandleRef()); + m_buttons[IB_TrackpadTouch]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/trackpad/force", &m_buttons[IB_TrackpadForce]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + m_buttons[IB_TrackpadForce]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/grip/touch", &m_buttons[IB_GripTouch]->GetHandleRef()); + m_buttons[IB_GripTouch]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/grip/force", &m_buttons[IB_GripForce]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + m_buttons[IB_GripForce]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/grip/value", &m_buttons[IB_GripValue]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + m_buttons[IB_GripValue]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/thumbstick/click", &m_buttons[IB_ThumbstickClick]->GetHandleRef()); + m_buttons[IB_ThumbstickClick]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/thumbstick/touch", &m_buttons[IB_ThumbstickTouch]->GetHandleRef()); + m_buttons[IB_ThumbstickTouch]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/thumbstick/x", &m_buttons[IB_ThumbstickX]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + m_buttons[IB_ThumbstickX]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/thumbstick/y", &m_buttons[IB_ThumbstickY]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedTwoSided); + m_buttons[IB_ThumbstickY]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/a/click", &m_buttons[IB_AClick]->GetHandleRef()); + m_buttons[IB_AClick]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/a/touch", &m_buttons[IB_ATouch]->GetHandleRef()); + m_buttons[IB_ATouch]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/b/click", &m_buttons[IB_BClick]->GetHandleRef()); + m_buttons[IB_BClick]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateBooleanComponent(m_propertyContainer, "/input/b/touch", &m_buttons[IB_BTouch]->GetHandleRef()); + m_buttons[IB_BTouch]->SetInputType(CControllerButton::IT_Boolean); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/finger/index", &m_buttons[IB_FingerIndex]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + m_buttons[IB_FingerIndex]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/finger/middle", &m_buttons[IB_FingerMiddle]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + m_buttons[IB_FingerMiddle]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/finger/ring", &m_buttons[IB_FingerRing]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + m_buttons[IB_FingerRing]->SetInputType(CControllerButton::IT_Float); + + vr::VRDriverInput()->CreateScalarComponent(m_propertyContainer, "/input/finger/pinky", &m_buttons[IB_FingerPinky]->GetHandleRef(), vr::VRScalarType_Absolute, vr::VRScalarUnits_NormalizedOneSided); + m_buttons[IB_FingerPinky]->SetInputType(CControllerButton::IT_Float); + + const vr::EVRSkeletalTrackingLevel l_trackingLevel = ((CDriverConfig::GetTrackingLevel() == CDriverConfig::TL_Partial) ? vr::VRSkeletalTracking_Partial : vr::VRSkeletalTracking_Full); + switch(m_hand) + { + case CH_Left: + vr::VRDriverInput()->CreateSkeletonComponent(m_propertyContainer, "/input/skeleton/left", "/skeleton/hand/left", "/pose/raw", l_trackingLevel, nullptr, 0U, &m_skeletonHandle); + break; + case CH_Right: + vr::VRDriverInput()->CreateSkeletonComponent(m_propertyContainer, "/input/skeleton/right", "/skeleton/hand/right", "/pose/raw", l_trackingLevel, nullptr, 0U, &m_skeletonHandle); + break; + } + + vr::VRDriverInput()->CreateHapticComponent(m_propertyContainer, "/output/haptic", &m_haptic); +} + +void CLeapControllerIndex::UpdateGestures(const LEAP_HAND *f_hand, const LEAP_HAND *f_oppHand) +{ + if(f_hand) + { + std::vector l_gestures; + CGestureMatcher::GetGestures(f_hand, l_gestures, f_oppHand); + + m_buttons[IB_TriggerValue]->SetValue(l_gestures[CGestureMatcher::HG_Trigger]); + m_buttons[IB_TriggerClick]->SetState(l_gestures[CGestureMatcher::HG_Trigger] >= 0.75f); + + m_buttons[IB_GripValue]->SetValue(l_gestures[CGestureMatcher::HG_Grab]); + m_buttons[IB_GripTouch]->SetState(l_gestures[CGestureMatcher::HG_Grab] >= 0.25f); + m_buttons[IB_GripForce]->SetValue((l_gestures[CGestureMatcher::HG_Grab] >= 0.75f) ? (l_gestures[CGestureMatcher::HG_Grab] - 0.75f) * 4.f : 0.f); + + m_buttons[IB_FingerIndex]->SetValue(l_gestures[CGestureMatcher::HG_IndexBend]); + m_buttons[IB_FingerMiddle]->SetValue(l_gestures[CGestureMatcher::HG_MiddleBend]); + m_buttons[IB_FingerRing]->SetValue(l_gestures[CGestureMatcher::HG_RingBend]); + m_buttons[IB_FingerPinky]->SetValue(l_gestures[CGestureMatcher::HG_PinkyBend]); + + for(size_t i = 0U; i < 5U; i++) + { + const LEAP_DIGIT &l_finger = f_hand->digits[i]; + size_t l_transformIndex = GetFingerBoneIndex(i); + if(l_transformIndex != HSB_Thumb0) l_transformIndex++; + + LEAP_QUATERNION l_leapRotation = f_hand->palm.orientation; + glm::quat l_segmentRotation; + ConvertQuaternion(l_leapRotation, l_segmentRotation); + + for(size_t j = 1U; j < 4U; j++) + { + const glm::quat l_prevSegmentRotationInv = glm::inverse(l_segmentRotation); + l_leapRotation = l_finger.bones[j].rotation; + ConvertQuaternion(l_leapRotation, l_segmentRotation); + + glm::quat l_segmentResult = l_prevSegmentRotationInv * l_segmentRotation; + ChangeBoneOrientation(l_segmentResult); + if(l_transformIndex == HSB_Thumb0) + { + std::swap(l_segmentResult.z, l_segmentResult.w); + l_segmentResult.w *= -1.f; + if(m_hand == CH_Right) + { + std::swap(l_segmentResult.x, l_segmentResult.w); + l_segmentResult.w *= -1.f; + std::swap(l_segmentResult.y, l_segmentResult.z); + l_segmentResult.y *= -1.f; + } + } + ConvertQuaternion(l_segmentResult, m_boneTransform[l_transformIndex].orientation); + l_transformIndex++; + } + } + + // Update aux bones + glm::vec3 l_position; + glm::quat l_rotation; + ConvertVector3(m_boneTransform[HSB_Wrist].position, l_position); + ConvertQuaternion(m_boneTransform[HSB_Wrist].orientation, l_rotation); + const glm::mat4 l_wristMat = glm::translate(g_identityMatrix, l_position) * glm::mat4_cast(l_rotation); + + for(size_t i = HF_Thumb; i < HF_Count; i++) + { + glm::mat4 l_chainMat(l_wristMat); + const size_t l_chainIndex = GetFingerBoneIndex(i); + for(size_t j = 0U; j < ((i == HF_Thumb) ? 3U : 4U); j++) + { + ConvertVector3(m_boneTransform[l_chainIndex + j].position, l_position); + ConvertQuaternion(m_boneTransform[l_chainIndex + j].orientation, l_rotation); + l_chainMat = l_chainMat * (glm::translate(g_identityMatrix, l_position)*glm::mat4_cast(l_rotation)); + } + l_position = l_chainMat * g_zeroPoint; + l_rotation = glm::quat_cast(l_chainMat); + if(m_hand == CH_Left) ChangeAuxTransformation(l_position, l_rotation); + ConvertVector3(l_position, m_boneTransform[HSB_Aux_Thumb + i].position); + ConvertQuaternion(l_rotation, m_boneTransform[HSB_Aux_Thumb + i].orientation); + } + } +} + +void CLeapControllerIndex::UpdateInputInternal() +{ + vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletonHandle, vr::VRSkeletalMotionRange_WithController, m_boneTransform, HSB_Count); + vr::VRDriverInput()->UpdateSkeletonComponent(m_skeletonHandle, vr::VRSkeletalMotionRange_WithoutController, m_boneTransform, HSB_Count); +} + +void CLeapControllerIndex::SetButtonState(size_t f_button, bool f_state) +{ + if(f_button < m_buttons.size()) + m_buttons[f_button]->SetState(f_state); +} + +void CLeapControllerIndex::SetButtonValue(size_t f_button, float f_value) +{ + if(f_button < m_buttons.size()) + m_buttons[f_button]->SetValue(f_value); +} diff --git a/driver_leap/Devices/CLeapController/CLeapControllerIndex.h b/driver_leap/Devices/CLeapController/CLeapControllerIndex.h new file mode 100644 index 00000000..9bf09052 --- /dev/null +++ b/driver_leap/Devices/CLeapController/CLeapControllerIndex.h @@ -0,0 +1,93 @@ +#pragma once + +#include "Devices/CLeapController/CLeapController.h" + +class CLeapControllerIndex final : public CLeapController +{ + enum HandSkeletonBone : size_t + { + HSB_Root = 0U, + HSB_Wrist, + HSB_Thumb0, + HSB_Thumb1, + HSB_Thumb2, + HSB_Thumb3, // Last, no effect + HSB_IndexFinger0, + HSB_IndexFinger1, + HSB_IndexFinger2, + HSB_IndexFinger3, + HSB_IndexFinger4, // Last, no effect + HSB_MiddleFinger0, + HSB_MiddleFinger1, + HSB_MiddleFinger2, + HSB_MiddleFinger3, + HSB_MiddleFinger4, // Last, no effect + HSB_RingFinger0, + HSB_RingFinger1, + HSB_RingFinger2, + HSB_RingFinger3, + HSB_RingFinger4, // Last, no effect + HSB_PinkyFinger0, + HSB_PinkyFinger1, + HSB_PinkyFinger2, + HSB_PinkyFinger3, + HSB_PinkyFinger4, // Last, no effect + HSB_Aux_Thumb, + HSB_Aux_IndexFinger, + HSB_Aux_MiddleFinger, + HSB_Aux_RingFinger, + HSB_Aux_PinkyFinger, + + HSB_Count + }; + + vr::VRBoneTransform_t m_boneTransform[HSB_Count]; + vr::VRInputComponentHandle_t m_skeletonHandle; + + CLeapControllerIndex(const CLeapControllerIndex &that) = delete; + CLeapControllerIndex& operator=(const CLeapControllerIndex &that) = delete; + + void ChangeBoneOrientation(glm::quat &f_rot); + static void ChangeAuxTransformation(glm::vec3 &f_pos, glm::quat &f_rot); + static size_t GetFingerBoneIndex(size_t f_id); + + // CLeapController + void ActivateInternal() override; + void UpdateGestures(const LEAP_HAND *f_hand, const LEAP_HAND *f_oppHand) override; + void UpdateInputInternal() override; +public: + enum IndexButton : size_t + { + IB_SystemClick = 0U, + IB_SystemTouch, + IB_TriggerClick, + IB_TriggerValue, + IB_TrackpadX, + IB_TrackpadY, + IB_TrackpadTouch, + IB_TrackpadForce, + IB_GripTouch, + IB_GripForce, + IB_GripValue, + IB_ThumbstickClick, + IB_ThumbstickTouch, + IB_ThumbstickX, + IB_ThumbstickY, + IB_AClick, + IB_ATouch, + IB_BClick, + IB_BTouch, + IB_FingerIndex, + IB_FingerMiddle, + IB_FingerRing, + IB_FingerPinky, + + IB_Count + }; + + explicit CLeapControllerIndex(unsigned char f_hand); + ~CLeapControllerIndex(); + + void SetButtonState(size_t f_button, bool f_state); + void SetButtonValue(size_t f_button, float f_value); +}; diff --git a/driver_leap/Devices/CLeapStation.cpp b/driver_leap/Devices/CLeapStation.cpp new file mode 100644 index 00000000..5c535b38 --- /dev/null +++ b/driver_leap/Devices/CLeapStation.cpp @@ -0,0 +1,147 @@ +#include "stdafx.h" + +#include "Devices/CLeapStation.h" +#include "Core/CServerDriver.h" + +CLeapStation::CLeapStation(CServerDriver *f_server) +{ + m_pose = { 0 }; + m_pose.deviceIsConnected = true; + m_pose.poseIsValid = true; + m_pose.poseTimeOffset = 0.; + m_pose.qDriverFromHeadRotation = { 1.0, .0, .0, .0 }; + m_pose.qRotation = { 1.0, .0, .0, .0 }; + m_pose.qWorldFromDriverRotation = { 1.0, .0, .0, .0 }; + m_pose.result = vr::TrackingResult_Running_OK; + m_pose.shouldApplyHeadModel = false; + for(size_t i = 0U; i < 3U; i++) + { + m_pose.vecAcceleration[i] = 0.; + m_pose.vecAngularAcceleration[i] = 0.; + m_pose.vecAngularVelocity[i] = 0.; + m_pose.vecDriverFromHeadTranslation[i] = 0.; + m_pose.vecPosition[i] = 0.; + m_pose.vecVelocity[i] = 0.; + } + m_pose.willDriftInYaw = false; + + m_propertyHandle = vr::k_ulInvalidPropertyContainer; + m_trackedDevice = vr::k_unTrackedDeviceIndexInvalid; + + m_serialNumber.assign("leap_motion_station"); + m_serverDriver = f_server; +} + +CLeapStation::~CLeapStation() +{ +} + +// vr::ITrackedDeviceServerDriver +vr::EVRInitError CLeapStation::Activate(uint32_t unObjectId) +{ + vr::EVRInitError l_resultError = vr::VRInitError_Driver_CalibrationInvalid; + + if(m_trackedDevice == vr::k_unTrackedDeviceIndexInvalid) + { + m_trackedDevice = unObjectId; + m_propertyHandle = vr::VRProperties()->TrackedDeviceToPropertyContainer(m_trackedDevice); + + vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_TrackingSystemName_String, "leap_motion"); + vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_SerialNumber_String, m_serialNumber.c_str()); + vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_ModelNumber_String, m_serialNumber.c_str()); + vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_ManufacturerName_String, "Leap Motion"); + vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_ModeLabel_String, "L"); + + vr::VRProperties()->SetInt32Property(m_propertyHandle, vr::Prop_DeviceClass_Int32, vr::TrackedDeviceClass_TrackingReference); + vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_IsOnDesktop_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_NeverTracked_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_WillDriftInYaw_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_CanWirelessIdentify_Bool, false); + + vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_FieldOfViewLeftDegrees_Float, 150.f); + vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_FieldOfViewRightDegrees_Float, 150.f); + vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_FieldOfViewTopDegrees_Float, 120.f); + vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_FieldOfViewBottomDegrees_Float, 120.f); + vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_TrackingRangeMinimumMeters_Float, 0.025f); + vr::VRProperties()->SetFloatProperty(m_propertyHandle, vr::Prop_TrackingRangeMaximumMeters_Float, 0.6f); + + vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_ResourceRoot_String, "leap"); + vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_RenderModelName_String, "{leap}leap_motion_1_0"); + + vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_NamedIconPathDeviceReady_String, "{leap}/icons/base_status_ready.png"); + vr::VRProperties()->SetStringProperty(m_propertyHandle, vr::Prop_NamedIconPathDeviceSearching_String, "{leap}/icons/base_status_searching.png"); + + vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_HasDisplayComponent_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_HasCameraComponent_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_HasDriverDirectModeComponent_Bool, false); + vr::VRProperties()->SetBoolProperty(m_propertyHandle, vr::Prop_HasVirtualDisplayComponent_Bool, false); + + vr::VRProperties()->SetUint64Property(m_propertyHandle, vr::Prop_VendorSpecific_Reserved_Start, 0x4C4D6F74696F6E); // "LMotion", hidden property for leap_monitor + + m_pose.vecWorldFromDriverTranslation[0U] = 0.1f; // Slightly move to avoid base stations + + l_resultError = vr::VRInitError_None; + } + + return l_resultError; +} + +void CLeapStation::Deactivate() +{ + m_trackedDevice = vr::k_unTrackedDeviceIndexInvalid; +} + +void CLeapStation::EnterStandby() +{ +} + +void* CLeapStation::GetComponent(const char* pchComponentNameAndVersion) +{ + void *l_result = nullptr; + if(!strcmp(pchComponentNameAndVersion, vr::ITrackedDeviceServerDriver_Version)) l_result = dynamic_cast(this); + return l_result; +} + +void CLeapStation::DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize) +{ + if(m_trackedDevice != vr::k_unTrackedDeviceIndexInvalid) + { + if(m_serverDriver) m_serverDriver->ProcessExternalMessage(pchRequest); + } +} + +vr::DriverPose_t CLeapStation::GetPose() +{ + return m_pose; +} + +// CLeapStation +const std::string& CLeapStation::GetSerialNumber() const +{ + return m_serialNumber; +} + +void CLeapStation::SetTrackingState(TrackingState f_state) +{ + switch(f_state) + { + case TS_Connected: + { + m_pose.result = vr::TrackingResult_Running_OK; + m_pose.poseIsValid = true; + } break; + case TS_Search: + { + m_pose.result = vr::TrackingResult_Calibrating_OutOfRange; + m_pose.poseIsValid = false; + } break; + } +} + +void CLeapStation::RunFrame() +{ + if(m_trackedDevice != vr::k_unTrackedDeviceIndexInvalid) + { + vr::VRServerDriverHost()->TrackedDevicePoseUpdated(m_trackedDevice, m_pose, sizeof(vr::DriverPose_t)); + } +} diff --git a/driver_leap/Devices/CLeapStation.h b/driver_leap/Devices/CLeapStation.h new file mode 100644 index 00000000..80cf9163 --- /dev/null +++ b/driver_leap/Devices/CLeapStation.h @@ -0,0 +1,39 @@ +#pragma once + +class CServerDriver; + +class CLeapStation final : public vr::ITrackedDeviceServerDriver +{ + vr::DriverPose_t m_pose; + vr::PropertyContainerHandle_t m_propertyHandle; + uint32_t m_trackedDevice; + + CServerDriver *m_serverDriver; + std::string m_serialNumber; + + CLeapStation(const CLeapStation &that) = delete; + CLeapStation& operator=(const CLeapStation &that) = delete; + + // vr::ITrackedDeviceServerDriver + vr::EVRInitError Activate(uint32_t unObjectId); + void Deactivate(); + void EnterStandby(); + void* GetComponent(const char* pchComponentNameAndVersion); + void DebugRequest(const char* pchRequest, char* pchResponseBuffer, uint32_t unResponseBufferSize); + vr::DriverPose_t GetPose(); +public: + enum TrackingState : unsigned char + { + TS_Connected = 0U, + TS_Search + }; + + explicit CLeapStation(CServerDriver *f_server); + ~CLeapStation(); + + const std::string& GetSerialNumber() const; + + void SetTrackingState(TrackingState f_state); + + void RunFrame(); +}; diff --git a/driver_leap/Utils/CGestureMatcher.cpp b/driver_leap/Utils/CGestureMatcher.cpp new file mode 100644 index 00000000..eb7f6662 --- /dev/null +++ b/driver_leap/Utils/CGestureMatcher.cpp @@ -0,0 +1,42 @@ +#include "stdafx.h" + +#include "Utils/CGestureMatcher.h" + +const float g_pi = glm::pi(); +const float g_piHalf = g_pi * 0.5f; +const float g_piQuarter = g_pi * 0.25f; +extern const glm::mat4 g_identityMatrix; + +void CGestureMatcher::GetGestures(const LEAP_HAND *f_hand, std::vector &f_result, const LEAP_HAND *f_oppHand) +{ + f_result.resize(HG_Count, 0.f); + + // Finger bends + float l_fingerBend[5U] = { 0.f }; + for(size_t i = 0U; i < 5U; i++) + { + const LEAP_DIGIT &l_finger = f_hand->digits[i]; + glm::vec3 l_prevDirection; + const size_t l_startBoneIndex = ((i == 0U) ? 1U : 0U); + for(size_t j = l_startBoneIndex; j < 4U; j++) + { + const LEAP_BONE &l_bone = l_finger.bones[j]; + 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); + l_direction = glm::normalize(l_direction); + if(j > l_startBoneIndex) l_fingerBend[i] += glm::acos(glm::dot(l_direction, l_prevDirection)); + l_prevDirection = l_direction; + } + } + + for(size_t i = 0U; i <= HG_PinkyBend; i++) f_result[i] = NormalizeRange(l_fingerBend[i], (i == 0U) ? 0.f : g_piQuarter, (i == 0U) ? g_piQuarter : g_pi); + + // Simple gestures + f_result[HG_Trigger] = f_result[HG_IndexBend]; + f_result[HG_Grab] = NormalizeRange((l_fingerBend[2U] + l_fingerBend[3U] + l_fingerBend[4U]) / 3.f, g_piHalf, g_pi); +} + +float CGestureMatcher::NormalizeRange(float f_val, float f_min, float f_max) +{ + const float l_mapped = (f_val - f_min) / (f_max - f_min); + return glm::clamp(l_mapped, 0.f, 1.f); +} diff --git a/driver_leap/Utils/CGestureMatcher.h b/driver_leap/Utils/CGestureMatcher.h new file mode 100644 index 00000000..cbdeeef2 --- /dev/null +++ b/driver_leap/Utils/CGestureMatcher.h @@ -0,0 +1,24 @@ +#pragma once + +class CGestureMatcher +{ + static float NormalizeRange(float f_val, float f_min, float f_max); +public: + enum HandGesture : size_t + { + // Finger bends + HG_ThumbBend = 0U, + HG_IndexBend, + HG_MiddleBend, + HG_RingBend, + HG_PinkyBend, + + // Simple gestures + HG_Trigger, + HG_Grab, + + HG_Count + }; + + static void GetGestures(const LEAP_HAND *f_hand, std::vector &f_result, const LEAP_HAND *f_oppHand = nullptr); +}; diff --git a/driver_leap/Utils/Utils.cpp b/driver_leap/Utils/Utils.cpp new file mode 100644 index 00000000..d88ca87b --- /dev/null +++ b/driver_leap/Utils/Utils.cpp @@ -0,0 +1,91 @@ +#include "stdafx.h" + +#include "Utils/Utils.h" + +extern const glm::mat4 g_identityMatrix(1.f); + +// Left hand open gesture transformation, thanks to https://github.com/spayne and his soft_knuckles repository +extern const vr::VRBoneTransform_t g_openHandGesture[31U] +{ + { {{ 0.000000f, 0.000000f, 0.000000f, 1.000000f }}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f } }, + { {{ -0.034038f, 0.026503f, 0.174722f, 1.000000f }}, { -0.055147f, -0.078608f, -0.920279f, 0.379296f } }, + { {{ -0.012083f, 0.028070f, 0.025050f, 1.000000f }}, { 0.464112f, 0.567418f, 0.272106f, 0.623374f } }, + { {{ 0.040406f, 0.000000f, -0.000000f, 1.000000f }}, { 0.994838f, 0.082939f, 0.019454f, 0.055130f } }, + { {{ 0.032517f, 0.000000f, 0.000000f, 1.000000f }}, { 0.974793f, -0.003213f, 0.021867f, -0.222015f } }, + { {{ 0.030464f, -0.000000f, -0.000000f, 1.000000f }}, { 1.000000f, -0.000000f, -0.000000f, 0.000000f } }, + { {{ 0.000632f, 0.026866f, 0.015002f, 1.000000f }}, { 0.644251f, 0.421979f, -0.478202f, 0.422133f } }, + { {{ 0.074204f, -0.005002f, 0.000234f, 1.000000f }}, { 0.995332f, 0.007007f, -0.039124f, 0.087949f } }, + { {{ 0.043930f, -0.000000f, -0.000000f, 1.000000f }}, { 0.997891f, 0.045808f, 0.002142f, -0.045943f } }, + { {{ 0.028695f, 0.000000f, 0.000000f, 1.000000f }}, { 0.999649f, 0.001850f, -0.022782f, -0.013409f } }, + { {{ 0.022821f, 0.000000f, -0.000000f, 1.000000f }}, { 1.000000f, -0.000000f, 0.000000f, -0.000000f } }, + { {{ 0.002177f, 0.007120f, 0.016319f, 1.000000f }}, { 0.546723f, 0.541276f, -0.442520f, 0.460749f } }, + { {{ 0.070953f, 0.000779f, 0.000997f, 1.000000f }}, { 0.980294f, -0.167261f, -0.078959f, 0.069368f } }, + { {{ 0.043108f, 0.000000f, 0.000000f, 1.000000f }}, { 0.997947f, 0.018493f, 0.013192f, 0.059886f } }, + { {{ 0.033266f, 0.000000f, 0.000000f, 1.000000f }}, { 0.997394f, -0.003328f, -0.028225f, -0.066315f } }, + { {{ 0.025892f, -0.000000f, 0.000000f, 1.000000f }}, { 0.999195f, -0.000000f, 0.000000f, 0.040126f } }, + { {{ 0.000513f, -0.006545f, 0.016348f, 1.000000f }}, { 0.516692f, 0.550143f, -0.495548f, 0.429888f } }, + { {{ 0.065876f, 0.001786f, 0.000693f, 1.000000f }}, { 0.990420f, -0.058696f, -0.101820f, 0.072495f } }, + { {{ 0.040697f, 0.000000f, 0.000000f, 1.000000f }}, { 0.999545f, -0.002240f, 0.000004f, 0.030081f } }, + { {{ 0.028747f, -0.000000f, -0.000000f, 1.000000f }}, { 0.999102f, -0.000721f, -0.012693f, 0.040420f } }, + { {{ 0.022430f, -0.000000f, 0.000000f, 1.000000f }}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f } }, + { {{ -0.002478f, -0.018981f, 0.015214f, 1.000000f }}, { 0.526918f, 0.523940f, -0.584025f, 0.326740f } }, + { {{ 0.062878f, 0.002844f, 0.000332f, 1.000000f }}, { 0.986609f, -0.059615f, -0.135163f, 0.069132f } }, + { {{ 0.030220f, 0.000000f, 0.000000f, 1.000000f }}, { 0.994317f, 0.001896f, -0.000132f, 0.106446f } }, + { {{ 0.018187f, 0.000000f, 0.000000f, 1.000000f }}, { 0.995931f, -0.002010f, -0.052079f, -0.073526f } }, + { {{ 0.018018f, 0.000000f, -0.000000f, 1.000000f }}, { 1.000000f, 0.000000f, 0.000000f, 0.000000f } }, + { {{ -0.006059f, 0.056285f, 0.060064f, 1.000000f }}, { 0.737238f, 0.202745f, 0.594267f, 0.249441f } }, + { {{ -0.040416f, -0.043018f, 0.019345f, 1.000000f }}, { -0.290331f, 0.623527f, -0.663809f, -0.293734f } }, + { {{ -0.039354f, -0.075674f, 0.047048f, 1.000000f }}, { -0.187047f, 0.678062f, -0.659285f, -0.265683f } }, + { {{ -0.038340f, -0.090987f, 0.082579f, 1.000000f }}, { -0.183037f, 0.736793f, -0.634757f, -0.143936f } }, + { {{ -0.031806f, -0.087214f, 0.121015f, 1.000000f }}, { -0.003659f, 0.758407f, -0.639342f, -0.126678f } } +}; + +extern const glm::vec4 g_zeroPoint(0.f, 0.f, 0.f, 1.f); + +void ConvertMatrix(const vr::HmdMatrix34_t &f_matVR, glm::mat4 &f_mat) +{ + for(int i = 0; i < 4; i++) + { + for(int j = 0; j < 3; j++) f_mat[i][j] = f_matVR.m[j][i]; + } + for(int i = 0; i < 3; i++) f_mat[i][3] = 0.f; + f_mat[3][3] = 1.f; +} + +void ConvertVector3(const vr::HmdVector4_t &f_vrVec, glm::vec3 &f_glmVec) +{ + for(size_t i = 0U; i < 3U; i++) f_glmVec[i] = f_vrVec.v[i]; +} + +void ConvertVector3(const glm::vec3 &f_glmVec, vr::HmdVector4_t &f_vrVec) +{ + for(size_t i = 0U; i < 3U; i++) f_vrVec.v[i] = f_glmVec[i]; +} + +size_t ReadEnumVector(const std::string &f_val, const std::vector &f_vec) +{ + size_t l_result = std::numeric_limits::max(); + for(auto iter = f_vec.begin(), iterEnd = f_vec.end(); iter != iterEnd; ++iter) + { + if(!iter->compare(f_val)) + { + l_result = std::distance(f_vec.begin(), iter); + break; + } + } + return l_result; +} + +size_t ReadEnumVector(const char *f_val, const std::vector &f_vec) +{ + size_t l_result = std::numeric_limits::max(); + for(auto iter = f_vec.begin(), iterEnd = f_vec.end(); iter != iterEnd; ++iter) + { + if(!iter->compare(f_val)) + { + l_result = std::distance(f_vec.begin(), iter); + break; + } + } + return l_result; +} diff --git a/driver_leap/Utils/Utils.h b/driver_leap/Utils/Utils.h new file mode 100644 index 00000000..a6a9426d --- /dev/null +++ b/driver_leap/Utils/Utils.h @@ -0,0 +1,15 @@ +#pragma once + +void ConvertMatrix(const vr::HmdMatrix34_t &f_matVR, glm::mat4 &f_mat); +template void ConvertQuaternion(const T &f_quatA, U &f_quatB) +{ + f_quatB.x = f_quatA.x; + f_quatB.y = f_quatA.y; + f_quatB.z = f_quatA.z; + f_quatB.w = f_quatA.w; +} +void ConvertVector3(const vr::HmdVector4_t &f_vrVec, glm::vec3 &f_glmVec); +void ConvertVector3(const glm::vec3 &f_glmVec, vr::HmdVector4_t &f_vrVec); + +size_t ReadEnumVector(const std::string &f_val, const std::vector &f_vec); +size_t ReadEnumVector(const char *f_val, const std::vector &f_vec); diff --git a/driver_leap/dllmain.cpp b/driver_leap/dllmain.cpp new file mode 100644 index 00000000..b619752d --- /dev/null +++ b/driver_leap/dllmain.cpp @@ -0,0 +1,31 @@ +#include "stdafx.h" + +#include "Core/CServerDriver.h" + +char g_modulePath[2048U]; + +BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID /* lpReserved */) +{ + switch(ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + GetModuleFileNameA(hModule, g_modulePath, 2048U); + break; + case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +CServerDriver g_serverDriver; + +extern "C" __declspec(dllexport) void* HmdDriverFactory(const char *pInterfaceName, int *pReturnCode) +{ + void *l_result = nullptr; + if(!strcmp(vr::IServerTrackedDeviceProvider_Version, pInterfaceName)) l_result = dynamic_cast(&g_serverDriver); + else + { + if(pReturnCode) *pReturnCode = vr::VRInitError_Init_InterfaceNotFound; + } + return l_result; +} diff --git a/driver_leap/driver_leap.vcxproj b/driver_leap/driver_leap.vcxproj new file mode 100644 index 00000000..f081abcb --- /dev/null +++ b/driver_leap/driver_leap.vcxproj @@ -0,0 +1,160 @@ + + + + + Debug + x64 + + + Release + x64 + + + + {52d3f16d-a7a5-4d6f-8f17-5e4b459a1440} + DynamicLibrary + driver_leap + driver_leap + en-US + 12.0 + 8.1 + 8.1 + + + + DynamicLibrary + true + v141 + + + DynamicLibrary + false + true + v141 + + + + + + + + + + false + false + false + $(SolutionDir)bin\win64\ + $(SolutionDir)objs\$(ProjectName)\$(PlatformName)\$(Configuration)\ + + + false + false + true + $(SolutionDir)bin\win64\ + $(SolutionDir)objs\$(ProjectName)\$(PlatformName)\$(Configuration)\ + + + + Use + false + + + Console + false + false + + + + + Use + false + + + Console + false + false + + + + + Use + false + ./;../vendor/LeapSDK/include;../vendor/openvr/headers;../vendor/pugixml/src;../vendor/glm;%(AdditionalIncludeDirectories) + stdafx.h + + + Windows + false + false + ../vendor/LeapSDK/lib/x64;../vendor/openvr/lib/win64;%(AdditionalLibraryDirectories) + openvr_api.lib;LeapC.lib;%(AdditionalDependencies) + true + + + + + + copy /y "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\leap\bin\win64\$(TargetFileName)" + Install Binary + + + + + Use + false + ./;../vendor/LeapSDK/include;../vendor/openvr/headers;../vendor/pugixml/src;../vendor/glm;%(AdditionalIncludeDirectories) + stdafx.h + true + + + Windows + false + false + ../vendor/LeapSDK/lib/x64;../vendor/openvr/lib/win64;%(AdditionalLibraryDirectories) + openvr_api.lib;LeapC.lib;%(AdditionalDependencies) + false + + + + + + copy /y "$(TargetPath)" "C:\Program Files (x86)\Steam\steamapps\common\SteamVR\drivers\leap\bin\win64\$(TargetFileName)" + Install Binary + + + + + + + + + + + + + + + + + NotUsing + NotUsing + + + + + + + + + + + Create + Create + + + + + + + + \ No newline at end of file diff --git a/driver_leap/driver_leap.vcxproj.filters b/driver_leap/driver_leap.vcxproj.filters new file mode 100644 index 00000000..48c82205 --- /dev/null +++ b/driver_leap/driver_leap.vcxproj.filters @@ -0,0 +1,87 @@ + + + + + + + vendor\pugixml + + + Utils + + + Utils + + + Devices + + + Devices\CLeapController + + + Devices\CLeapController + + + Devices\CLeapController + + + Core + + + Core + + + Core + + + + + + Utils + + + Utils + + + Devices + + + Devices\CLeapController + + + Devices\CLeapController + + + Devices\CLeapController + + + Core + + + Core + + + Core + + + + + {4dd100d6-5318-4ebc-a9eb-9ef27f1ae76b} + + + {21c081d3-867d-441e-90d0-ef26e9d05cae} + + + {839b3e7e-6f9e-49a2-b8e7-c8c40d0cd982} + + + {b03c9f12-ff59-41c2-addf-e0d1c366d73a} + + + {5709dbc5-cf75-4243-a691-22f7d553f0da} + + + {82e3a6c5-9886-457e-8308-b6c62ec7ce03} + + + \ No newline at end of file diff --git a/driver_leap/stdafx.cpp b/driver_leap/stdafx.cpp new file mode 100644 index 00000000..d1303f39 --- /dev/null +++ b/driver_leap/stdafx.cpp @@ -0,0 +1 @@ +#include "stdafx.h" diff --git a/driver_leap/stdafx.h b/driver_leap/stdafx.h new file mode 100644 index 00000000..b6d2a751 --- /dev/null +++ b/driver_leap/stdafx.h @@ -0,0 +1,28 @@ +#pragma once + +#define WIN32_LEAN_AND_MEAN +#define NOMINMAX +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "openvr_driver.h" +#include "LeapC.h" + +#include "glm/glm.hpp" +#include "glm/gtc/matrix_transform.hpp" +#include "glm/gtc/quaternion.hpp" +#include "glm/gtx/norm.hpp" +#include "glm/gtx/intersect.hpp" + +#include "pugixml.hpp" diff --git a/drivers/driver_leap/GestureMatcher.cpp b/drivers/driver_leap/GestureMatcher.cpp deleted file mode 100644 index 98f7ce34..00000000 --- a/drivers/driver_leap/GestureMatcher.cpp +++ /dev/null @@ -1,258 +0,0 @@ - -#include "GestureMatcher.h" - -const Vector GestureMatcher::RightVector = Vector(-1, 0, 0); -const Vector GestureMatcher::InVector = Vector( 0, 1, 0); -const Vector GestureMatcher::UpVector = Vector( 0, 0, -1); - -// invert a 3x3 matrix -static void invert_3x3(const float(*A)[3], float(*R)[3]) { - float det; - - det = A[0][0] * (A[2][2] * A[1][1] - A[2][1] * A[1][2]) - - A[1][0] * (A[2][2] * A[0][1] - A[2][1] * A[0][2]) - + A[2][0] * (A[1][2] * A[0][1] - A[1][1] * A[0][2]); - - R[0][0] = (A[2][2] * A[1][1] - A[2][1] * A[1][2]) / det; - R[0][1] = -(A[2][2] * A[0][1] - A[2][1] * A[0][2]) / det; - R[0][2] = (A[1][2] * A[0][1] - A[1][1] * A[0][2]) / det; - - R[1][0] = -(A[2][2] * A[1][0] - A[2][0] * A[1][2]) / det; - R[1][1] = (A[2][2] * A[0][0] - A[2][0] * A[0][2]) / det; - R[1][2] = -(A[1][2] * A[0][0] - A[1][0] * A[0][2]) / det; - - R[2][0] = (A[2][1] * A[1][0] - A[2][0] * A[1][1]) / det; - R[2][1] = -(A[2][1] * A[0][0] - A[2][0] * A[0][1]) / det; - R[2][2] = (A[1][1] * A[0][0] - A[1][0] * A[0][1]) / det; -} - -// compute matrix * column vector product -static Vector matrix_vector(const float(*A)[3], Vector &v) -{ - Vector result; - result.x = A[0][0] * v.x + A[0][1] * v.y + A[0][2] * v.z; - result.y = A[1][0] * v.x + A[1][1] * v.y + A[1][2] * v.z; - result.z = A[2][0] * v.x + A[2][1] * v.y + A[2][2] * v.z; - return result; -} - - - -GestureMatcher::GestureMatcher() -{ -} - -GestureMatcher::~GestureMatcher() -{ -} - -bool GestureMatcher::MatchGestures(const Frame &frame, WhichHand which, float(&result)[NUM_GESTURES], - Vector right, Vector in, Vector up) -{ - // first, set all gesture matches to zero - bool success = false; - memset(result, 0, sizeof(result)); - - // Go through the hands in the dataset - HandList &hands = frame.hands(); - - for (int h = 0; h < hands.count(); h++) - { - Hand hand = hands[h]; - - // these are the conditions under which we do not want - // to evaluate a hand from the Frame dataset. - if (!hand.isValid()) continue; - if (which == RightHand && hand.isLeft()) continue; - if (which == LeftHand && hand.isRight()) continue; - - Hand otherhand; - if (hands.count() == 2) otherhand = hands[(h + 1) % 2]; - - // okay, found a hand we want to look at. - success = true; - - // stores the bend angles per finger and per joint - float bends[5][3] = { 0 }; - - // total bend angle of a finger - float sumbend[5] = { 0 }; - - Vector fingerdir[5]; - Vector fingertip[5]; - bool extended[5]; - memset(fingerdir, 0, sizeof(fingerdir)); - memset(fingertip, 0, sizeof(fingertip)); - memset(extended, 0, sizeof(extended)); - - // Evaluate bending of all fingers - const FingerList &fingers = hand.fingers(); - for (auto fl = fingers.begin(); fl != fingers.end(); ++fl) { - const Finger &finger = *fl; - - int f = finger.type(); // thumb, index, middle, ring, pinky - if (finger.isFinger() && finger.isValid()) - { - fingertip[f] = finger.tipPosition(); - extended[f] = finger.isExtended(); - - // go through the finger's bones: - // metacarpal, proximal, intermediate, distal - Vector prev_direction; - for (int b = 0; b < 4; b++) - { - Bone &bone = finger.bone(Bone::Type(b)); - Vector direction = -bone.direction(); // for some reaason bone directions point handinwards? - - if (b == Bone::TYPE_DISTAL) - fingerdir[f] = direction; - - if (b > 0) - { - // get the bend angle of each finger joint - bends[f][b-1] = 57.2957795f * direction.angleTo(prev_direction); // in degrees - - // also sum up the total - sumbend[f] += bends[f][b - 1]; - } - prev_direction = direction; - } - } - } - - // trigger figure gesture means the bend angles of the upper two joints - // of the index finger exceed 70 degrees. - float triggerbend = bends[Finger::TYPE_INDEX][1] + bends[Finger::TYPE_INDEX][2]; - float trigger = maprange(triggerbend, 70.0, 100.0); - merge(result[TriggerFinger], trigger); - - // lower first gesture means clenching middle, ring, pinky fingers beyond 90 degrees - float grip = maprange((sumbend[Finger::TYPE_MIDDLE] + sumbend[Finger::TYPE_RING] + sumbend[Finger::TYPE_PINKY]) / 3, 90.0, 180.0); - merge(result[LowerFist], grip); - - // pinch gesture means pinching the index and thumb (distance closer than 30mm) - float pinch = maprange(hand.pinchDistance(), 40, 30); - merge(result[Pinch], pinch); - - // Thumbpress gesture means that the thumb points the direction of the pinky - Vector palmNormal = hand.palmNormal(); - Vector direction = hand.direction(); - Vector pinkyside; - if (hand.isRight()) - pinkyside = palmNormal.cross(direction); - else - pinkyside = direction.cross(palmNormal); - merge(result[Thumbpress], maprange(pinkyside.dot(fingerdir[Finger::TYPE_THUMB]), 0.0f, 0.6f)); - - - // *UNRELIABLE* ILY gesture means pinky and index finger extended, middle and ring finger curled up - // Thumb doesn't matter. It's easier to point it inwards for many people. - merge(result[ILY], std::min(maprange((sumbend[Finger::TYPE_PINKY] + sumbend[Finger::TYPE_INDEX]) / 2, 50.0, 40.0), - maprange((sumbend[Finger::TYPE_MIDDLE] + sumbend[Finger::TYPE_RING]) / 2, 120.0, 150.0))); - - // *UNRELIABLE* Flipping the Bird: You know how to flip a bird. - merge(result[FlippingTheBird], std::min(maprange(sumbend[Finger::TYPE_MIDDLE], 50.0, 40.0), - maprange((sumbend[Finger::TYPE_INDEX] + sumbend[Finger::TYPE_RING] + sumbend[Finger::TYPE_PINKY]) / 3, 120.0, 150.0))); - - // Victory gesture: make a nice V sign with your index and middle finger - float angle = fingerdir[Finger::TYPE_INDEX].angleTo(fingerdir[Finger::TYPE_MIDDLE]); - merge(result[Victory], std::min(std::min(maprange((sumbend[Finger::TYPE_INDEX] + sumbend[Finger::TYPE_MIDDLE]) / 2, 50.0, 40.0), - maprange((sumbend[Finger::TYPE_PINKY] + sumbend[Finger::TYPE_RING]) / 2, 120.0, 150.0)), - maprange(57.2957795f * fingerdir[Finger::TYPE_INDEX].angleTo(fingerdir[Finger::TYPE_MIDDLE]), 10.0, 20.0) )); - - // FlatHand gestures - float flatHand = maprange((sumbend[Finger::TYPE_THUMB] + sumbend[Finger::TYPE_INDEX] + sumbend[Finger::TYPE_MIDDLE] + sumbend[Finger::TYPE_RING] + sumbend[Finger::TYPE_PINKY]) / 5, 50.0, 40.0); - merge(result[FlatHandPalmUp] , std::min(flatHand, maprange(( up).dot(palmNormal), 0.8f, 0.95f))); - merge(result[FlatHandPalmDown] , std::min(flatHand, maprange((-up).dot(palmNormal), 0.8f, 0.95f))); - merge(result[FlatHandPalmAway] , std::min(flatHand, maprange(( in).dot(palmNormal), 0.8f, 0.95f))); - merge(result[FlatHandPalmTowards], std::min(flatHand, maprange((-in).dot(palmNormal), 0.8f, 0.95f))); - - // ThumbsUp/Inward gestures - Vector inward = hand.isLeft() ? right : -right; - float fistHand = maprange((sumbend[Finger::TYPE_INDEX] + sumbend[Finger::TYPE_MIDDLE] + sumbend[Finger::TYPE_RING] + sumbend[Finger::TYPE_PINKY]) / 5, 120.0, 150.0); - float straightThumb = maprange(sumbend[Finger::TYPE_THUMB], 50.0, 40.0); - merge(result[ThumbUp] , std::min(fistHand, std::min(straightThumb, maprange(( up).dot(fingerdir[Finger::TYPE_THUMB]), 0.8f, 0.95f)))); - merge(result[ThumbInward] , std::min(fistHand, std::min(straightThumb, maprange((inward).dot(fingerdir[Finger::TYPE_THUMB]), 0.8f, 0.95f)))); - - if (otherhand.isValid()) // two handed gestures really need two hands - { - // Timeout gesture. Note that only the lower hand forming the T shape will register the gesture. - // TODO: might also validate that the lower hand points upward - // TODO: might as well check that the other hand is also flat - merge(result[Timeout], std::min( flatHand, // I reuse the flatHand metric from above - std::min( maprange(hand.direction().dot(-otherhand.palmNormal()), 0.8f, 0.95f), - maprange(fingertip[Leap::Finger::TYPE_INDEX].distanceTo(otherhand.palmPosition()), 80.0f, 60.0f) ) - )); - - // Touchpad emulation - Finger otherIndex = otherhand.fingers().fingerType(Leap::Finger::TYPE_INDEX)[0]; - if (otherIndex.isFinger() && otherIndex.isValid()) - { - // we need the index finger direction and the other hand's palm to face opposing directions - if (otherIndex.direction().dot(hand.palmNormal()) < 0) - { - // Origin o of the plane is the hand's palm position - Vector o = hand.palmPosition(); - - // sideways vector on the hand - Vector uvec = direction.cross(palmNormal) * hand.palmWidth() / 2; - - // vvec going from palm towards the hand's pointing direction - Vector vvec = hand.direction() * hand.palmWidth() / 2; - - // p and d form a line originating at the index finger's tip - Vector p = otherIndex.tipPosition(); - Vector d = otherIndex.direction(); - - // solve this linear equation system - // p0 d0 o0 uvec0 vvec0 - // p1 + n * d1 = o1 + u * uvec1 + v * vvec1 - // p2 d2 o2 uvec1 vvec2 - - // u u0 v0 d0 p0 o0 - // v = inv( u1 v1 d1 ) * ( p1 - o1 ) - // n u2 v2 d2 p2 o2 - - float A[3][3] = { {uvec.x, vvec.x, d.x}, - {uvec.y, vvec.y, d.y}, - {uvec.z, vvec.z, d.z} }; - - float invA[3][3]; - invert_3x3(A, invA); - Vector R = matrix_vector(invA, Vector(p.x - o.x, p.y - o.y, p.z - o.z)); - - // u and v are in R.x and R.y respectively and are expected to be within -1...+1 - // when the index finger points into the palm area - // n is contained in R.z and represents the distance in mm between the index finger tip and the palm - - // compute length of u,v vector in plane - float u = R.x; - float v = R.y; - float length = sqrtf(u*u + v*v); - - // ignore if are we pointing way out of bounds - if (length < 5.0) - { - // limit vector to remain inside unit circle - if (length > 1.0) { - u /= length; - v /= length; - } - result[TouchpadAxisX] = u; - result[TouchpadAxisY] = v; - } - } - } - } - -#if 0 - fprintf(stderr, "handdir %f %f %f\n", hand.direction().x, hand.direction().y, hand.direction().z); - fprintf(stderr, "thumbdir %f %f %f\n", fingerdir[Finger::TYPE_THUMB].x, fingerdir[Finger::TYPE_THUMB].y, fingerdir[Finger::TYPE_THUMB].z); - fprintf(stderr, "indexdir %f %f %f\n", fingerdir[Finger::TYPE_INDEX].x, fingerdir[Finger::TYPE_INDEX].y, fingerdir[Finger::TYPE_INDEX].z); - fprintf(stderr, "palmpos %f %f %f\n", hand.palmPosition().x, hand.palmPosition().y, hand.palmPosition().z); - fprintf(stderr, "palmnormal %f %f %f\n", hand.palmNormal().x, hand.palmNormal().y, hand.palmNormal().z); -#endif - } - - return success; -} diff --git a/drivers/driver_leap/GestureMatcher.h b/drivers/driver_leap/GestureMatcher.h deleted file mode 100644 index 6f4d5f1e..00000000 --- a/drivers/driver_leap/GestureMatcher.h +++ /dev/null @@ -1,142 +0,0 @@ -#pragma once - -#include "Leap.h" - -#include - -using namespace Leap; - -/** - * Hand gesture recognizer that will return an array of matches against - * a list of predefined finger and hand poses. - */ -class GestureMatcher -{ -public: - GestureMatcher(); - ~GestureMatcher(); - - enum WhichHand - { - AnyHand, - LeftHand, - RightHand - }; - - enum GestureType - { - // Finger gestures (these would not throw your hand's orientation off much) - TriggerFinger, // bend your index finger as if pulling a trigger - LowerFist, // grab with your middle, ring, pinky fingers - Pinch, // pinch with your thumb and index fingers - Thumbpress, // point the thumb towards the direction of your pinky - - // Hand gestures (these would significantly change the orientation of your hand) - FlippingTheBird, // flip someone off with your middle finger - ILY, // pinky and index finger extended, middle and ring bent - Victory, // V shape with your index, middle fingers, other fingers curled - FlatHandPalmUp, // flat hand, palm points upwards (relative to alignment of Leap!) - FlatHandPalmDown, // flat hand, palm points downwards (relative to alignment of Leap!) - FlatHandPalmAway, // flat hand, palm points away from self (relative to alignment of Leap!) - FlatHandPalmTowards, // flat hand, palm points towards self (relative to alignment of Leap!) - ThumbUp, // thumb points up, remaining fingers form a fist - ThumbInward, // thumb points towards the left for the right hand and vice versa - - TODO_LiveLongAndProsper, // Spock's trademark greeting - TODO_DiverOkay, // Diver's "I'm Okay" sign. - TODO_FistBump, // a Fist Bump gesture - - // Two handed gestures - Timeout, // both Hands form a T shape, signals a Timeout in sports - TouchpadAxisX, // Touchpad emulation: index finger of other hand points towards palm - TouchpadAxisY, // Touchpad emulation: index finger of other hand points towards palm - - NUM_GESTURES, - - INVALID_GESTURE = -1 - }; - - // default orientation vectors with respect to the Leap's coordinate system - // in Head Mounted Mode. - static const Vector RightVector; - static const Vector InVector; - static const Vector UpVector; - - /** - * Perform gesture detection and quantification for the specified hand. - * If AnyHand is specified, the gesture classifications will be merged together (typically std::max) - */ - bool MatchGestures(const Frame &frame, WhichHand which, float (&result)[NUM_GESTURES], - Vector right = RightVector, Vector in = InVector, Vector up = UpVector); - - /** - * Map the GestureType enum to a string name. - */ - static std::string GestureNameFromType(GestureType gesture) - { - switch (gesture) - { - case TriggerFinger: return "TriggerFinger"; break; - case LowerFist: return "LowerFist"; break; - case Pinch: return "Pinch"; break; - case Thumbpress: return "Thumbpress"; break; - case ILY: return "ILY"; break; - case FlippingTheBird: return "FlippingTheBird"; break; - case Victory: return "Victory"; break; - case FlatHandPalmUp: return "FlatHandPalmUp"; break; - case FlatHandPalmDown: return "FlatHandPalmDown"; break; - case FlatHandPalmAway: return "FlatHandPalmAway"; break; - case FlatHandPalmTowards: return "FlatHandPalmTowards"; break; - case ThumbUp: return "ThumbUp"; break; - case ThumbInward: return "ThumbInward"; break; - case Timeout: return "Timeout"; break; - case TouchpadAxisX: return "TouchpadAxisX"; break; - case TouchpadAxisY: return "TouchpadAxisY"; break; - default: return ""; break; - } - } - - /** - * Map a string name to the GestureType enum. Case Sensitive! - * Be sure to check the return code for INVALID_GESTURE - */ - GestureType GestureTypeFromName(std::string &name) - { - if (name.compare("TriggerFinger") == 0) return TriggerFinger; - else if (name.compare("LowerFist") == 0) return LowerFist; - else if (name.compare("Pinch") == 0) return Pinch; - else if (name.compare("Thumbpress") == 0) return Thumbpress; - else if (name.compare("ILY") == 0) return ILY; - else if (name.compare("FlippingTheBird") == 0) return FlippingTheBird; - else if (name.compare("Victory") == 0) return Victory; - else if (name.compare("FlatHandPalmUp") == 0) return FlatHandPalmUp; - else if (name.compare("FlatHandPalmDown") == 0) return FlatHandPalmDown; - else if (name.compare("FlatHandPalmAway") == 0) return FlatHandPalmAway; - else if (name.compare("FlatHandPalmTowards") == 0) return FlatHandPalmTowards; - else if (name.compare("ThumbUp") == 0) return ThumbUp; - else if (name.compare("ThumbInward") == 0) return ThumbInward; - else if (name.compare("Timeout") == 0) return Timeout; - else if (name.compare("TouchpadAxisX") == 0) return TouchpadAxisX; - else if (name.compare("TouchpadAxisY") == 0) return TouchpadAxisY; - else return INVALID_GESTURE; - } - -protected: - - // some utility functions - - float maprange(float input, float minimum, float maximum) - { - float mapped = (input - minimum) / (maximum - minimum); - return std::max(std::min(mapped, 1.0f), 0.0f); - } - - void merge(float &result, float value) - { - result = std::max(result, value); - } - -protected: - - // place state variables here (if any) -}; diff --git a/drivers/driver_leap/dllmain.cpp b/drivers/driver_leap/dllmain.cpp deleted file mode 100644 index 9e0657bb..00000000 --- a/drivers/driver_leap/dllmain.cpp +++ /dev/null @@ -1,16 +0,0 @@ -// dllmain.cpp : Defines the entry point for the DLL application. -#include "pch.h" - -BOOL APIENTRY DllMain(HMODULE /* hModule */, DWORD ul_reason_for_call, LPVOID /* lpReserved */) -{ - switch (ul_reason_for_call) - { - case DLL_PROCESS_ATTACH: - case DLL_THREAD_ATTACH: - case DLL_THREAD_DETACH: - case DLL_PROCESS_DETACH: - break; - } - return TRUE; -} - diff --git a/drivers/driver_leap/driver_leap.cpp b/drivers/driver_leap/driver_leap.cpp deleted file mode 100644 index 1a35e2f1..00000000 --- a/drivers/driver_leap/driver_leap.cpp +++ /dev/null @@ -1,1274 +0,0 @@ -//========= Copyright Valve Corporation ============// -// -// driver_leap.cpp : Defines the client and server interfaces used by the SteamVR runtime. -// - -#include "pch.h" -#include "driver_leap.h" - -#include - -#ifdef _WIN32 -#include // for timeBeginPeriod() -#pragma comment(lib, "winmm.lib") -#endif - -#include - -#define HMD_DLL_EXPORT extern "C" __declspec( dllexport ) - -CServerDriver_Leap g_ServerTrackedDeviceProvider; -CClientDriver_Leap g_ClientTrackedDeviceProvider; - -// strangely, swapping the order here doesn't fix the swapped controllers in Audioshield -#define LEFT_CONTROLLER 0 -#define RIGHT_CONTROLLER 1 - -HMD_DLL_EXPORT -void *HmdDriverFactory( const char *pInterfaceName, int *pReturnCode ) -{ - if ( 0 == strcmp( vr::IServerTrackedDeviceProvider_Version, pInterfaceName ) ) - { - return &g_ServerTrackedDeviceProvider; - } - if ( 0 == strcmp( vr::IClientTrackedDeviceProvider_Version, pInterfaceName ) ) - { - return &g_ClientTrackedDeviceProvider; - } - - if ( pReturnCode ) - *pReturnCode = vr::VRInitError_Init_InterfaceNotFound; - - return NULL; -} - -//================================================================================================== -// Logging helpers -//================================================================================================== - -static vr::IDriverLog * s_pLogFile = NULL; - -static bool InitDriverLog( vr::IDriverLog *pDriverLog ) -{ - if ( s_pLogFile ) - return false; - s_pLogFile = pDriverLog; - return s_pLogFile != NULL; -} - -static void CleanupDriverLog() -{ - s_pLogFile = NULL; -} - -static void DriverLogVarArgs( const char *pMsgFormat, va_list args ) -{ - char buf[1024]; -#if defined( WIN32 ) - vsprintf_s( buf, pMsgFormat, args ); -#else - vsnprintf( buf, sizeof( buf ), pMsgFormat, args ); -#endif - - if ( s_pLogFile ) - s_pLogFile->Log( buf ); -} - -/** Provides printf-style debug logging via the vr::IDriverLog interface provided by SteamVR -* during initialization. Client logging ends up in vrclient_appname.txt and server logging -* ends up in vrserver.txt. -*/ -static void DriverLog( const char *pMsgFormat, ... ) -{ - va_list args; - va_start( args, pMsgFormat ); - - DriverLogVarArgs( pMsgFormat, args ); - - va_end( args ); -} - -//================================================================================================== -// Listener interface in Server Provider -//================================================================================================== - -/** - * Called once, when this Listener object is newly added to a Controller. - * - * \include Listener_onInit.txt - * - * @param controller The Controller object invoking this callback function. - * @since 1.0 - */ -void CServerDriver_Leap::onInit(const Controller&controller) -{ - DriverLog("CServerDriver_Leap::onInit()\n"); -} - -/** - * Called when the Controller object connects to the Leap Motion software and - * the Leap Motion hardware device is plugged in, - * or when this Listener object is added to a Controller that is already connected. - * - * When this callback is invoked, Controller::isServiceConnected is true, - * Controller::devices() is not empty, and, for at least one of the Device objects in the list, - * Device::isStreaming() is true. - * - * \include Listener_onConnect.txt - * - * @param controller The Controller object invoking this callback function. - * @since 1.0 - */ -void CServerDriver_Leap::onConnect(const Controller&controller) -{ - DriverLog("CServerDriver_Leap::onConnect()\n"); -} - -/** - * Called when the Controller object disconnects from the Leap Motion software or - * the Leap Motion hardware is unplugged. - * The controller can disconnect when the Leap Motion device is unplugged, the - * user shuts the Leap Motion software down, or the Leap Motion software encounters an - * unrecoverable error. - * - * \include Listener_onDisconnect.txt - * - * Note: When you launch a Leap-enabled application in a debugger, the - * Leap Motion library does not disconnect from the application. This is to allow - * you to step through code without losing the connection because of time outs. - * - * @param controller The Controller object invoking this callback function. - * @since 1.0 - */ -void CServerDriver_Leap::onDisconnect(const Controller&controller) -{ - DriverLog("CServerDriver_Leap::onDisconnect()\n"); -} - -/** - * Called when this Listener object is removed from the Controller - * or the Controller instance is destroyed. - * - * \include Listener_onExit.txt - * - * @param controller The Controller object invoking this callback function. - * @since 1.0 - */ -void CServerDriver_Leap::onExit(const Controller&controller) -{ - DriverLog("CServerDriver_Leap::onExit()\n"); -} - -/** - * Called when a new frame of hand and finger tracking data is available. - * Access the new frame data using the Controller::frame() function. - * - * \include Listener_onFrame.txt - * - * Note, the Controller skips any pending onFrame events while your - * onFrame handler executes. If your implementation takes too long to return, - * one or more frames can be skipped. The Controller still inserts the skipped - * frames into the frame history. You can access recent frames by setting - * the history parameter when calling the Controller::frame() function. - * You can determine if any pending onFrame events were skipped by comparing - * the ID of the most recent frame with the ID of the last received frame. - * - * @param controller The Controller object invoking this callback function. - * @since 1.0 - */ -void CServerDriver_Leap::onFrame(const Controller&controller) -{ -} - -/** - * Called when this application becomes the foreground application. - * - * Only the foreground application receives tracking data from the Leap - * Motion Controller. This function is only called when the controller - * object is in a connected state. - * - * \include Listener_onFocusGained.txt - * - * @param controller The Controller object invoking this callback function. - * @since 1.0 - */ -void CServerDriver_Leap::onFocusGained(const Controller&controller) -{ -// DriverLog("CServerDriver_Leap::onFocusGained()\n"); -} - -/** - * Called when this application loses the foreground focus. - * - * Only the foreground application receives tracking data from the Leap - * Motion Controller. This function is only called when the controller - * object is in a connected state. - * - * \include Listener_onFocusLost.txt - * - * @param controller The Controller object invoking this callback function. - * @since 1.0 - */ -void CServerDriver_Leap::onFocusLost(const Controller&controller) -{ -// DriverLog("CServerDriver_Leap::onFocusLost()\n"); -} - -// onServiceConnect/onServiceDisconnect are for connection established/lost. -// in normal course of events onServiceConnect will get called once after onInit -// and onServiceDisconnect will not get called. disconnect notification only happens -// if service stops running or something else bad happens to disconnect controller from service. -/** - * Called when the Leap Motion daemon/service connects to your application Controller. - * - * \include Listener_onServiceConnect.txt - * - * @param controller The Controller object invoking this callback function. - * @since 1.2 - */ -void CServerDriver_Leap::onServiceConnect(const Controller&controller) -{ - DriverLog("CServerDriver_Leap::onServiceConnect()\n"); -} - -/** - * Called if the Leap Motion daemon/service disconnects from your application Controller. - * - * Normally, this callback is not invoked. It is only called if some external event - * or problem shuts down the service or otherwise interrupts the connection. - * - * \include Listener_onServiceDisconnect.txt - * - * @param controller The Controller object invoking this callback function. - * @since 1.2 - */ -void CServerDriver_Leap::onServiceDisconnect(const Controller&controller) -{ - DriverLog("CServerDriver_Leap::onServiceDisconnect()\n"); -} - -/** - * Called when a Leap Motion controller is plugged in, unplugged, or the device changes state. - * - * State changes include entering or leaving robust mode and low resource mode. - * Note that there is no direct way to query whether the device is in these modes, - * although you can use Controller::isLightingBad() to check if there are environmental - * IR lighting problems. - * - * \include Listener_onDeviceChange.txt - * - * @param controller The Controller object invoking this callback function. - * @since 1.2 - */ -void CServerDriver_Leap::onDeviceChange(const Controller&controller) -{ - DriverLog("CServerDriver_Leap::onDeviceChange()\n"); - - if (controller.isConnected()) - { - bool backgroundModeAllowed = controller.config().getInt32("background_app_mode") == 2; - if (!backgroundModeAllowed) { - // TODO: Show dialog to request permission to allow background mode apps - bool userPermission = true; - if (userPermission) { - controller.config().setInt32("background_app_mode", 2); - controller.config().save(); - } - } - - controller.setPolicy(Leap::Controller::POLICY_OPTIMIZE_HMD); - controller.setPolicy(Leap::Controller::POLICY_BACKGROUND_FRAMES); - - // make sure we always get background frames even when we lose the focus to another - // Leap-enabled application - controller.setPolicy((Leap::Controller::PolicyFlag)(15)); - - // allow other background applications to receive frames even when SteamVR has the focus. - controller.setPolicy((Leap::Controller::PolicyFlag)(23)); - - ScanForNewControllers(true); - } - else - { - for (auto it = m_vecControllers.begin(); it != m_vecControllers.end(); ++it) - delete (*it); - m_vecControllers.clear(); - } -} - -/** - * Called when new images are available. - * Access the new frame data using the Controller::images() function. - * - * \include Listener_onImages.txt - * - * @param controller The Controller object invoking this callback function. - * @since 2.2.1 - */ -void CServerDriver_Leap::onImages(const Controller&controller) -{ -} - -/** - * Called when the Leap Motion service is paused or resumed or when a - * controller policy is changed. - * - * The service can change states because the computer user changes settings - * in the Leap Motion Control Panel application or because an application - * connected to the service triggers a change. Any application can pause or - * unpause the service, but only runtime policy changes you make apply to your - * own application. - * - * \include Listener_onServiceChange.txt - * - * You can query the pause state of the controller with Controller::isPaused(). - * You can check the state of those policies you are interested in with - * Controller::isPolicySet(). - * - * @param controller The Controller object invoking this callback function. - * @since 3.0 - */ -void CServerDriver_Leap::onServiceChange(const Controller&controller) -{ - DriverLog("CServerDriver_Leap::onServiceChange()\n"); -} - -/** - * Called when a Leap Motion controller device is plugged into the client - * computer, but fails to operate properly. - * - * Get the list containing all failed devices using Controller::failedDevices(). - * The members of this list provide the device pnpID and reason for failure. - * - * \include Listener_onDeviceFailure.txt - * - * @param controller The Controller object invoking this callback function. - * @since 3.0 - */ -void CServerDriver_Leap::onDeviceFailure(const Controller&controller) -{ - DriverLog("CServerDriver_Leap::onDeviceFailure()\n"); -} - -/** - * Called when the service emits a log message to report an error, warning, or - * status change. - * - * Log message text is provided as ASCII-encoded english. - * - * @param controller The Controller object invoking this callback function. - * @param severity The severity of the error, if known. - * @param timestamp The timestamp of the error in microseconds. - * (Use Controller::now() - timestamp to compute the age of the message.) - * @param msg The log message. - * @since 3.0 - */ -void CServerDriver_Leap::onLogMessage(const Controller&controller, MessageSeverity severity, int64_t timestamp, const char* msg) -{ - DriverLog("CServerDriver_Leap::onLogMessage(%d): %s\n", (int)severity, msg); -} - - -//================================================================================================== -// Server Provider -//================================================================================================== - -CServerDriver_Leap::CServerDriver_Leap() - : m_bLaunchedLeapMonitor( false ) -{ -// DriverLog not yet initialized at this point. -// DriverLog("CServerDriver_Leap::CServerDriver_Leap()\n"); -} - -CServerDriver_Leap::~CServerDriver_Leap() -{ - DriverLog("CServerDriver_Leap::~CServerDriver_Leap()\n"); - Cleanup(); -} - -vr::EVRInitError CServerDriver_Leap::Init( vr::IDriverLog * pDriverLog, vr::IServerDriverHost * pDriverHost, const char * pchUserDriverConfigDir, const char * pchDriverInstallDir ) -{ - InitDriverLog( pDriverLog ); - DriverLog("CServerDriver_Leap::Init()\n"); - - m_pDriverHost = pDriverHost; - m_strDriverInstallDir = pchDriverInstallDir; - - m_Controller = new Controller; - - Controller &controller = *m_Controller; - - m_Controller->addListener(*this); - - return vr::VRInitError_None; -} - -void CServerDriver_Leap::Cleanup() -{ - DriverLog("CServerDriver_Leap::Cleanup()\n"); - - // send a termination message to the leap monitor companion application - if (m_bLaunchedLeapMonitor) - { - // Ask leap_monitor to shut down. - PostThreadMessage(m_pInfoStartedProcess.dwThreadId, WM_QUIT, 0, 0); - m_bLaunchedLeapMonitor = false; - } - - // clean up our Leap::Controller object - if (m_Controller) - { - m_Controller->removeListener(*this); - delete m_Controller; - m_Controller = NULL; - } - - // clean up any controller objects we've created - for (auto it = m_vecControllers.begin(); it != m_vecControllers.end(); ++it) - delete (*it); - m_vecControllers.clear(); -} - -uint32_t CServerDriver_Leap::GetTrackedDeviceCount() -{ - return m_vecControllers.size(); -} - -vr::ITrackedDeviceServerDriver * CServerDriver_Leap::GetTrackedDeviceDriver( uint32_t unWhich ) -{ - if ( unWhich < m_vecControllers.size() ) - return m_vecControllers[unWhich]; - - return nullptr; -} - -vr::ITrackedDeviceServerDriver * CServerDriver_Leap::FindTrackedDeviceDriver( const char * pchId ) -{ - for ( auto it = m_vecControllers.begin(); it != m_vecControllers.end(); ++it ) - { - if ( 0 == strcmp( ( *it )->GetSerialNumber(), pchId ) ) - { - return *it; - } - } - return nullptr; -} - -void CServerDriver_Leap::RunFrame() -{ - if (m_vecControllers.size() == 2) - { - m_vecControllers[0]->RealignCoordinates(m_vecControllers[0], m_vecControllers[1]); - } - - if (m_Controller) - { - if (m_Controller->isConnected()) - { - Frame frame = m_Controller->frame(); - - // update the controllers - for (auto it = m_vecControllers.begin(); it != m_vecControllers.end(); ++it) - { - CLeapHmdLatest *pLeap = *it; - if (pLeap->IsActivated()) - { - // Returns true if this is new data (so we can sleep for long interval) - if (!pLeap->Update(frame)) - { - // not updated? - } - } - } - } - } -} - -bool CServerDriver_Leap::ShouldBlockStandbyMode() -{ - return false; -} - -void CServerDriver_Leap::EnterStandby() -{ - DriverLog("CServerDriver_Leap::EnterStandby()\n"); -} - -void CServerDriver_Leap::LeaveStandby() -{ - DriverLog("CServerDriver_Leap::LeaveStandby()\n"); -} - -static void GenerateSerialNumber( char *p, int psize, int base, int controller ) -{ - char tmp[32]; - _snprintf(tmp, 32, "controller%d", controller); - _snprintf( p, psize, "leap%d_%s", base, (controller == LEFT_CONTROLLER) ? "lefthand" : (controller == RIGHT_CONTROLLER) ? "righthand" : tmp ); -} - -void CServerDriver_Leap::ScanForNewControllers( bool bNotifyServer ) -{ - while (m_vecControllers.size() < 2) - { - char buf[256]; - int base = 0; - int i = m_vecControllers.size(); - GenerateSerialNumber( buf, sizeof( buf ), base, i ); - if ( !FindTrackedDeviceDriver( buf ) ) - { - DriverLog( "added new device %s\n", buf ); - m_vecControllers.push_back( new CLeapHmdLatest( m_pDriverHost, base, i ) ); - if ( bNotifyServer && m_pDriverHost ) - { - m_pDriverHost->TrackedDeviceAdded( m_vecControllers.back()->GetSerialNumber() ); - } - } - } -} - -// The leap_monitor is a companion program which will tell us the pose of the HMD. -void CServerDriver_Leap::LaunchLeapMonitor( const char * pchDriverInstallDir ) -{ - if ( m_bLaunchedLeapMonitor ) - return; - - DriverLog("CServerDriver_Leap::LaunchLeapMonitor()\n"); - - m_bLaunchedLeapMonitor = true; - - std::ostringstream ss; - - ss << pchDriverInstallDir << "\\bin\\"; -#if defined( _WIN64 ) - ss << "win64"; -#elif defined( _WIN32 ) - ss << "win32"; -#else -#error Do not know how to launch leap_monitor -#endif - DriverLog( "leap_monitor path: %s\n", ss.str().c_str() ); - -#if defined( _WIN32 ) - STARTUPINFOA sInfoProcess = { 0 }; - sInfoProcess.cb = sizeof(STARTUPINFOW); -// sInfoProcess.dwFlags = STARTF_USESHOWWINDOW; -// sInfoProcess.wShowWindow = SW_SHOWDEFAULT; - BOOL okay = CreateProcessA( (ss.str() + "\\leap_monitor.exe").c_str(), NULL, NULL, NULL, FALSE, 0, NULL, ss.str().c_str(), &sInfoProcess, &m_pInfoStartedProcess ); - DriverLog( "start leap_monitor okay: %d %08x\n", okay, GetLastError() ); -#else -#error Do not know how to launch leap_monitor -#endif -} - -/** Launch leap_monitor if needed (requested by devices as they activate) */ -void CServerDriver_Leap::LaunchLeapMonitor() -{ - LaunchLeapMonitor( m_strDriverInstallDir.c_str() ); -} - -//================================================================================================== -// Client Provider -//================================================================================================== - -CClientDriver_Leap::CClientDriver_Leap() -{ -} - -CClientDriver_Leap::~CClientDriver_Leap() -{ -} - -vr::EVRInitError CClientDriver_Leap::Init( vr::IDriverLog * pDriverLog, vr::IClientDriverHost * pDriverHost, const char * pchUserDriverConfigDir, const char * pchDriverInstallDir ) -{ - InitDriverLog( pDriverLog ); - DriverLog("CClientDriver_Leap::Init()\n"); - m_pDriverHost = pDriverHost; - return vr::VRInitError_None; -} - -void CClientDriver_Leap::Cleanup() -{ - DriverLog("CClientDriver_Leap::Cleanup()\n"); -} - -bool CClientDriver_Leap::BIsHmdPresent( const char * pchUserConfigDir ) -{ - return false; -} - -vr::EVRInitError CClientDriver_Leap::SetDisplayId( const char * pchDisplayId ) -{ - return vr::VRInitError_None; - //return vr::VRInitError_Driver_HmdUnknown; -} - -vr::HiddenAreaMesh_t CClientDriver_Leap::GetHiddenAreaMesh( vr::EVREye eEye ) -{ - return vr::HiddenAreaMesh_t(); -} - -uint32_t CClientDriver_Leap::GetMCImage( uint32_t * pImgWidth, uint32_t * pImgHeight, uint32_t * pChannels, void * pDataBuffer, uint32_t unBufferLen ) -{ - return uint32_t(); -} - -//================================================================================================== -// Device Driver -//================================================================================================== - -const std::chrono::milliseconds CLeapHmdLatest::k_TrackingLatency( -30 ); - -CLeapHmdLatest::CLeapHmdLatest( vr::IServerDriverHost * pDriverHost, int base, int n ) - : m_pDriverHost( pDriverHost ) - , m_nBase( base ) - , m_nId( n ) - , m_bCalibrated( true ) - , m_pAlignmentPartner( NULL ) - , m_unSteamVRTrackedDeviceId( vr::k_unTrackedDeviceIndexInvalid ) -{ - DriverLog("CLeapHmdLatest::CLeapHmdLatest(base=%d, n=%d)\n", base, n); - - memset(m_hmdPos, 0, sizeof(m_hmdPos)); - - char buf[256]; - GenerateSerialNumber( buf, sizeof( buf ), base, n ); - m_strSerialNumber = buf; - - memset( &m_ControllerState, 0, sizeof( m_ControllerState ) ); - memset( &m_Pose, 0, sizeof( m_Pose ) ); - m_Pose.result = vr::TrackingResult_Uninitialized; - - m_firmware_revision = 0x0001; - m_hardware_revision = 0x0001; - - // Load config from steamvr.vrsettings - vr::IVRSettings *settings_; - settings_ = m_pDriverHost->GetSettings(vr::IVRSettings_Version); - - // Load rendermodel - char tmp_[256]; - settings_->GetString("leap", (m_nId == LEFT_CONTROLLER) ? "renderModel_lefthand" : (m_nId == RIGHT_CONTROLLER) ? "renderModel_righthand" : "renderModel", tmp_, sizeof(tmp_), "vr_controller_vive_1_5"); - m_strRenderModel = tmp_; - - // set the - m_gripAngleOffset = settings_->GetFloat("leap", (m_nId == LEFT_CONTROLLER) ? "gripAngleOffset_lefthand" : (m_nId == RIGHT_CONTROLLER) ? "gripAngleOffset_righthand" : "gripAngleOffset", 0.0); -} - -CLeapHmdLatest::~CLeapHmdLatest() -{ - DriverLog("CLeapHmdLatest::~CLeapHmdLatest(base=%d, n=%d)\n", m_nBase, m_nId); -} - -void *CLeapHmdLatest::GetComponent( const char *pchComponentNameAndVersion ) -{ - if ( !stricmp( pchComponentNameAndVersion, vr::IVRControllerComponent_Version ) ) - { - return ( vr::IVRControllerComponent* )this; - } - - return NULL; -} - -vr::EVRInitError CLeapHmdLatest::Activate( uint32_t unObjectId ) -{ - DriverLog( "CLeapHmdLatest::Activate: %s is object id %d\n", GetSerialNumber(), unObjectId ); - m_unSteamVRTrackedDeviceId = unObjectId; - - g_ServerTrackedDeviceProvider.LaunchLeapMonitor(); - - return vr::VRInitError_None; -} - -void CLeapHmdLatest::Deactivate() -{ - DriverLog( "CLeapHmdLatest::Deactivate: %s was object id %d\n", GetSerialNumber(), m_unSteamVRTrackedDeviceId ); - m_unSteamVRTrackedDeviceId = vr::k_unTrackedDeviceIndexInvalid; -} - -void CLeapHmdLatest::PowerOff() -{ - DriverLog("CLeapHmdLatest::PowerOff()\n"); - // FIXME Implement -} - -void CLeapHmdLatest::DebugRequest( const char * pchRequest, char * pchResponseBuffer, uint32_t unResponseBufferSize ) -{ - std::istringstream ss( pchRequest ); - std::string strCmd; - - ss >> strCmd; - if ( strCmd == "leap:realign_coordinates" ) - { - // leap_monitor is calling us back with HMD tracking information so we can - // finish realigning our coordinate system to the HMD's - float m[3][3], v[3]; - for ( int i = 0; i < 3; ++i ) - { - for ( int j = 0; j < 3; ++j ) - { - ss >> m[j][i]; - } - ss >> v[i]; - } - FinishRealignCoordinates(m, v); - } -} - -const char * CLeapHmdLatest::GetSerialNumber() -{ - return m_strSerialNumber.c_str(); -} - -vr::DriverPose_t CLeapHmdLatest::GetPose() -{ - // This is only called at startup to synchronize with the driver. - // Future updates are driven by our thread calling TrackedDevicePoseUpdated() - return m_Pose; -} - -bool CLeapHmdLatest::GetBoolTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError * pError ) -{ - *pError = vr::TrackedProp_ValueNotProvidedByDevice; - return false; -} - -float CLeapHmdLatest::GetFloatTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError * pError ) -{ - *pError = vr::TrackedProp_ValueNotProvidedByDevice; - return 0.0f; -} - -int32_t CLeapHmdLatest::GetInt32TrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError * pError ) -{ - int32_t nRetVal = 0; - vr::ETrackedPropertyError error = vr::TrackedProp_UnknownProperty; - switch ( prop ) - { - case vr::Prop_DeviceClass_Int32: - nRetVal = vr::TrackedDeviceClass_Controller; - error = vr::TrackedProp_Success; - break; - - case vr::Prop_Axis0Type_Int32: - nRetVal = vr::k_eControllerAxis_Joystick; - error = vr::TrackedProp_Success; - break; - - case vr::Prop_Axis1Type_Int32: - nRetVal = vr::k_eControllerAxis_Trigger; - error = vr::TrackedProp_Success; - break; - - case vr::Prop_Axis2Type_Int32: - case vr::Prop_Axis3Type_Int32: - case vr::Prop_Axis4Type_Int32: - error = vr::TrackedProp_ValueNotProvidedByDevice; - break; - } - - *pError = error; - return nRetVal; -} - -uint64_t CLeapHmdLatest::GetUint64TrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError * pError ) -{ - uint64_t ulRetVal = 0; - vr::ETrackedPropertyError error = vr::TrackedProp_ValueNotProvidedByDevice; - - switch ( prop ) - { - case vr::Prop_CurrentUniverseId_Uint64: - case vr::Prop_PreviousUniverseId_Uint64: - error = vr::TrackedProp_ValueNotProvidedByDevice; - break; - - case vr::Prop_SupportedButtons_Uint64: - ulRetVal = - vr::ButtonMaskFromId( vr::k_EButton_ApplicationMenu) | - vr::ButtonMaskFromId( vr::k_EButton_System ) | - vr::ButtonMaskFromId( vr::k_EButton_SteamVR_Touchpad ) | - vr::ButtonMaskFromId( vr::k_EButton_SteamVR_Trigger) | - vr::ButtonMaskFromId( vr::k_EButton_Grip ); - error = vr::TrackedProp_Success; - break; - - case vr::Prop_HardwareRevision_Uint64: - ulRetVal = m_hardware_revision; - error = vr::TrackedProp_Success; - break; - - case vr::Prop_FirmwareVersion_Uint64: - ulRetVal = m_firmware_revision; - error = vr::TrackedProp_Success; - break; - - } - - *pError = error; - return ulRetVal; -} - -vr::HmdMatrix34_t CLeapHmdLatest::GetMatrix34TrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError * pError ) -{ - return vr::HmdMatrix34_t(); -} - -uint32_t CLeapHmdLatest::GetStringTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, char * pchValue, uint32_t unBufferSize, vr::ETrackedPropertyError * pError ) -{ - std::ostringstream ssRetVal; - - switch ( prop ) - { - case vr::Prop_SerialNumber_String: - ssRetVal << m_strSerialNumber; - break; - - case vr::Prop_RenderModelName_String: - // We return the user configured rendermodel here. Defaults to "vr_controller_vive_1_5". - ssRetVal << m_strRenderModel.c_str(); - break; - - case vr::Prop_ManufacturerName_String: - ssRetVal << "LeapMotion"; - break; - - case vr::Prop_ModelNumber_String: - ssRetVal << "Controller"; - break; - - case vr::Prop_TrackingFirmwareVersion_String: - ssRetVal << "cd.firmware_revision=" << m_firmware_revision; - break; - - case vr::Prop_HardwareRevision_String: - ssRetVal << "cd.hardware_revision=" << m_hardware_revision; - break; - } - - std::string sRetVal = ssRetVal.str(); - if ( sRetVal.empty() ) - { - *pError = vr::TrackedProp_ValueNotProvidedByDevice; - return 0; - } - else if ( sRetVal.size() + 1 > unBufferSize ) - { - *pError = vr::TrackedProp_BufferTooSmall; - return sRetVal.size() + 1; // caller needs to know how to size buffer - } - else - { - _snprintf( pchValue, unBufferSize, sRetVal.c_str() ); - *pError = vr::TrackedProp_Success; - return sRetVal.size() + 1; - } -} - -vr::VRControllerState_t CLeapHmdLatest::GetControllerState() -{ - // This is only called at startup to synchronize with the driver. - // Future updates are driven by our thread calling TrackedDeviceButton*() and TrackedDeviceAxis*() - return vr::VRControllerState_t(); -} - -bool CLeapHmdLatest::TriggerHapticPulse( uint32_t unAxisId, uint16_t usPulseDurationMicroseconds ) -{ - return true; // handled -- returning false will cause errors to come out of vrserver -} - -void CLeapHmdLatest::SendButtonUpdates( ButtonUpdate ButtonEvent, uint64_t ulMask ) -{ - if ( !ulMask ) - return; - - for ( int i = 0; i< vr::k_EButton_Max; i++ ) - { - vr::EVRButtonId button = ( vr::EVRButtonId )i; - - uint64_t bit = ButtonMaskFromId( button ); - - if ( bit & ulMask ) - { - ( m_pDriverHost->*ButtonEvent )( m_unSteamVRTrackedDeviceId, button, 0.0 ); - } - } -} - -void CLeapHmdLatest::UpdateControllerState(Frame &frame) -{ - vr::VRControllerState_t NewState = { 0 }; - - bool handFound = false; - GestureMatcher::WhichHand which = (m_nId == LEFT_CONTROLLER ) ? GestureMatcher::LeftHand : - (m_nId == RIGHT_CONTROLLER) ? GestureMatcher::RightHand : - GestureMatcher::AnyHand; - - float scores[GestureMatcher::NUM_GESTURES]; - handFound = matcher.MatchGestures(frame, which, scores); - - if (handFound) - { - // Changing unPacketNum tells anyone polling state that something might have - // changed. We don't try to be precise about that here. - NewState.unPacketNum = m_ControllerState.unPacketNum + 1; - - // system menu mapping (timeout gesture) - if (scores[GestureMatcher::Timeout] >= 0.5f) - NewState.ulButtonTouched |= vr::ButtonMaskFromId(vr::k_EButton_System); - if (scores[GestureMatcher::Timeout] >= 0.5f) - NewState.ulButtonPressed |= vr::ButtonMaskFromId(vr::k_EButton_System); - - // application menu mapping (Flat hand towards your face gesture) - if (scores[GestureMatcher::FlatHandPalmTowards] >= 0.8f) - NewState.ulButtonTouched |= vr::ButtonMaskFromId(vr::k_EButton_ApplicationMenu); - if (scores[GestureMatcher::FlatHandPalmTowards] >= 0.8f) - NewState.ulButtonPressed |= vr::ButtonMaskFromId(vr::k_EButton_ApplicationMenu); - - // digital trigger mapping (fist clenching gesture) - if (scores[GestureMatcher::TriggerFinger] > 0.5f) - NewState.ulButtonTouched |= vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger); - if (scores[GestureMatcher::TriggerFinger] > 0.5f) - NewState.ulButtonPressed |= vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Trigger); - - // grip mapping (clench fist with middle, index, pinky fingers) - if (scores[GestureMatcher::LowerFist] >= 0.5f) - NewState.ulButtonTouched |= vr::ButtonMaskFromId(vr::k_EButton_Grip); - if (scores[GestureMatcher::LowerFist] >= 0.5f) - NewState.ulButtonPressed |= vr::ButtonMaskFromId(vr::k_EButton_Grip); - - // touchpad button press mapping (Thumbpress gesture) - if (scores[GestureMatcher::Thumbpress] >= 0.2f) - NewState.ulButtonTouched |= vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Touchpad); - if (scores[GestureMatcher::Thumbpress] >= 1.0f) - NewState.ulButtonPressed |= vr::ButtonMaskFromId(vr::k_EButton_SteamVR_Touchpad); - -#if 0 - // sixense driver seems to have good deadzone, but add a small one here - if (fabsf(cd.joystick_x) > 0.03f || fabsf(cd.joystick_y) > 0.03f) - NewState.ulButtonTouched |= vr::ButtonMaskFromId(vr::k_EButton_StreamVR_Touchpad); -#endif - - // All pressed buttons are touched - NewState.ulButtonTouched |= NewState.ulButtonPressed; - - uint64_t ulChangedTouched = NewState.ulButtonTouched ^ m_ControllerState.ulButtonTouched; - uint64_t ulChangedPressed = NewState.ulButtonPressed ^ m_ControllerState.ulButtonPressed; - - SendButtonUpdates(&vr::IServerDriverHost::TrackedDeviceButtonTouched, ulChangedTouched & NewState.ulButtonTouched); - SendButtonUpdates(&vr::IServerDriverHost::TrackedDeviceButtonPressed, ulChangedPressed & NewState.ulButtonPressed); - SendButtonUpdates(&vr::IServerDriverHost::TrackedDeviceButtonUnpressed, ulChangedPressed & ~NewState.ulButtonPressed); - SendButtonUpdates(&vr::IServerDriverHost::TrackedDeviceButtonUntouched, ulChangedTouched & ~NewState.ulButtonTouched); - - NewState.rAxis[0].x = scores[GestureMatcher::TouchpadAxisX]; - NewState.rAxis[0].y = scores[GestureMatcher::TouchpadAxisY]; - - NewState.rAxis[1].x = scores[GestureMatcher::TriggerFinger]; - NewState.rAxis[1].y = 0.0f; - - // the touchpad maps to Axis 0 X/Y - if (NewState.rAxis[0].x != m_ControllerState.rAxis[0].x || NewState.rAxis[0].y != m_ControllerState.rAxis[0].y) - m_pDriverHost->TrackedDeviceAxisUpdated(m_unSteamVRTrackedDeviceId, 0, NewState.rAxis[0]); - - // trigger maps to Axis 1 X - if (NewState.rAxis[1].x != m_ControllerState.rAxis[1].x) - m_pDriverHost->TrackedDeviceAxisUpdated(m_unSteamVRTrackedDeviceId, 1, NewState.rAxis[1]); - - m_ControllerState = NewState; - } -} - -// multiplication of quaternions -vr::HmdQuaternion_t operator*(const vr::HmdQuaternion_t& a, const vr::HmdQuaternion_t& b) -{ - vr::HmdQuaternion_t tmp; - - tmp.w = (b.w * a.w) - (b.x * a.x) - (b.y * a.y) - (b.z * a.z); - tmp.x = (b.w * a.x) + (b.x * a.w) + (b.y * a.z) - (b.z * a.y); - tmp.y = (b.w * a.y) + (b.y * a.w) + (b.z * a.x) - (b.x * a.z); - tmp.z = (b.w * a.z) + (b.z * a.w) + (b.x * a.y) - (b.y * a.x); - - return tmp; -} - -// generate a rotation quaternion around an arbitrary axis -vr::HmdQuaternion_t rotate_around_axis(const Vector &v, const float &a) -{ - // Here we calculate the sin( a / 2) once for optimization - float factor = sinf(a* 0.01745329 / 2.0); - - // Calculate the x, y and z of the quaternion - float x = v.x * factor; - float y = v.y * factor; - float z = v.z * factor; - - // Calcualte the w value by cos( a / 2 ) - float w = cosf(a* 0.01745329 / 2.0); - - float mag = sqrtf(w*w + x*x + y*y + z*z); - - vr::HmdQuaternion_t result = { w / mag, x / mag, y / mag, z / mag }; - return result; -} - -// convert a 3x3 rotation matrix into a rotation quaternion -static vr::HmdQuaternion_t CalculateRotation(float(*a)[3]) { - - vr::HmdQuaternion_t q; - - float trace = a[0][0] + a[1][1] + a[2][2]; - if (trace > 0) { - float s = 0.5f / sqrtf(trace + 1.0f); - q.w = 0.25f / s; - q.x = (a[2][1] - a[1][2]) * s; - q.y = (a[0][2] - a[2][0]) * s; - q.z = (a[1][0] - a[0][1]) * s; - } - else { - if (a[0][0] > a[1][1] && a[0][0] > a[2][2]) { - float s = 2.0f * sqrtf(1.0f + a[0][0] - a[1][1] - a[2][2]); - q.w = (a[2][1] - a[1][2]) / s; - q.x = 0.25f * s; - q.y = (a[0][1] + a[1][0]) / s; - q.z = (a[0][2] + a[2][0]) / s; - } - else if (a[1][1] > a[2][2]) { - float s = 2.0f * sqrtf(1.0f + a[1][1] - a[0][0] - a[2][2]); - q.w = (a[0][2] - a[2][0]) / s; - q.x = (a[0][1] + a[1][0]) / s; - q.y = 0.25f * s; - q.z = (a[1][2] + a[2][1]) / s; - } - else { - float s = 2.0f * sqrtf(1.0f + a[2][2] - a[0][0] - a[1][1]); - q.w = (a[1][0] - a[0][1]) / s; - q.x = (a[0][2] + a[2][0]) / s; - q.y = (a[1][2] + a[2][1]) / s; - q.z = 0.25f * s; - } - } - q.x = -q.x; - q.y = -q.y; - q.z = -q.z; - return q; -} - -void CLeapHmdLatest::UpdateTrackingState(Frame &frame) -{ - HandList &hands = frame.hands(); - - bool handFound = false; - for (int h = 0; h < hands.count(); h++) - { - Hand &hand = hands[h]; - - // controller #0 is supposed to be the left hand, controller #1 the right one. - if (hand.isValid() && (m_nId == LEFT_CONTROLLER && hand.isLeft() || - m_nId == RIGHT_CONTROLLER && hand.isRight())) - { - handFound = true; - - // The "driver" coordinate system is the one that vecPosition is in. This is whatever - // coordinates the driver naturally produces for position and orientation. The "world" - // coordinate system is the one that is presented to vrserver. This should include - // fixing any tilt to the world (caused by a tilted camera, for example) and can include - // any other useful transformation for the driver (e.g. the driver is tracking from a - // secondary camera, but uses this transform to move this object into the primary camera - // coordinate system to be consistent with other objects). - // - // This transform is multiplied on the left of the predicted "driver" pose. That becomes - // the vr::TrackingUniverseRawAndUncalibrated origin, which is then further offset for - // floor height and tracking space center by the chaperone system to produce both the - // vr::TrackingUniverseSeated and vr::TrackingUniverseStanding spaces. - // - // In the leap driver, we use it to unify our coordinate system with the HMD. - m_Pose.qWorldFromDriverRotation = m_hmdRot; - m_Pose.vecWorldFromDriverTranslation[0] = m_hmdPos[0]; - m_Pose.vecWorldFromDriverTranslation[1] = m_hmdPos[1]; - m_Pose.vecWorldFromDriverTranslation[2] = m_hmdPos[2]; - - // The "head" coordinate system defines a natural point for the object. While the "driver" - // space may be chosen for mechanical, eletrical, or mathematical convenience (e.g. being - // the location of the IMU), the "head" should be a point meaningful to the user. For HMDs, - // it's the point directly between the user's eyes. The origin of this coordinate system - // is the origin used for the rendermodel. - // - // This transform is multiplied on the right side of the "driver" pose. - // - // This transform was inadvertently left at identity for the GDC 2015 controllers, creating - // a defacto standard "head" position for controllers at the location of the IMU for that - // particular controller. We will remedy that later by adding other, explicitly named and - // chosen spaces. For now, mimicking that point in this driver lets us run content authored - // for the HTC Vive Developer Edition controller. This was done by loading an existing - // controller rendermodel along side the Leap model and rotating the Leap model to roughly - // align the main features like the handle and trigger. - m_Pose.qDriverFromHeadRotation.w = 1; - m_Pose.qDriverFromHeadRotation.x = 0; // -m_hmdRot.x; this would cancel out the HMD's rotation - m_Pose.qDriverFromHeadRotation.y = 0; // -m_hmdRot.y; but instead we rely on the Leap Motion to - m_Pose.qDriverFromHeadRotation.z = 0; // -m_hmdRot.z; update the hand rotation as the head rotates - m_Pose.vecDriverFromHeadTranslation[0] = 0; - m_Pose.vecDriverFromHeadTranslation[1] = 0; - m_Pose.vecDriverFromHeadTranslation[2] = 0; - - Vector position = hand.palmPosition(); - - m_Pose.vecPosition[0] = -0.001*position.x; - m_Pose.vecPosition[1] = -0.001*position.z; - m_Pose.vecPosition[2] = -0.001*position.y - 0.15; // assume 15 cm offset from midpoint between eys - - Vector velocity = hand.palmVelocity(); - - m_Pose.vecVelocity[0] = -0.001*velocity.x; - m_Pose.vecVelocity[1] = -0.001*velocity.z; - m_Pose.vecVelocity[2] = -0.001*velocity.y; - - // Unmeasured. XXX we currently leave the acceleration at zero - m_Pose.vecAcceleration[0] = 0.0; - m_Pose.vecAcceleration[1] = 0.0; - m_Pose.vecAcceleration[2] = 0.0; - - // get two vectors describing the hand's orientation in space. We need to find a rotation - // matrix that turns the default coordinate system into the hand's coordinate system - Vector direction = hand.direction(); direction /= direction.magnitude(); - Vector normal = hand.palmNormal(); normal /= normal.magnitude(); - Vector side = direction.cross(normal); - -#if 0 - // This code assumes palms are facing downwards. - - // NOTE: y and z are swapped with respect to the Leap Motion's coordinate system and I list - // the vectors in the order in which I expect them to be in the tracking camera's - // coordinates system: X = sideways, - // Y = up/down i.e. palm's normal vector - // Z = front/back i.e. hand's pointing direction - m_Pose.qRotation = CalculateRotation(R); - - float R[3][3] = - { { side.x, side.z, side.y }, - { normal.x, normal.z, normal.y }, - { direction.x, direction.z, direction.y } }; - -#else - // This code assumes palms are facing inwards as if you were holding controllers. - // This is why the left hand and the - // right hands have to use different matrices to compute their rotations. - - float L[3][3] = - { {-normal.x, -normal.z, -normal.y }, - { side.x, side.z, side.y }, - { direction.x, direction.z, direction.y } }; - - float R[3][3] = - { { normal.x, normal.z, normal.y }, - {-side.x, -side.z, -side.y }, - { direction.x, direction.z, direction.y } }; - - // now turn this into a Quaternion and we're done. - if (m_nId == LEFT_CONTROLLER) - m_Pose.qRotation = CalculateRotation(L); - else if (m_nId == RIGHT_CONTROLLER) - m_Pose.qRotation = CalculateRotation(R); - -#endif - // rotate by the specified grip angle (may be useful when using the Vive as a gun grip) - if (m_gripAngleOffset != 0) - m_Pose.qRotation = rotate_around_axis(Vector(1.0, 0.0, 0.0), m_gripAngleOffset) * m_Pose.qRotation; - - // Unmeasured. XXX with no angular velocity, throwing might not work in some games - m_Pose.vecAngularVelocity[0] = 0.0; - m_Pose.vecAngularVelocity[1] = 0.0; - m_Pose.vecAngularVelocity[2] = 0.0; - - // The same argument applies here as to vecAcceleration, and a driver is even - // less likely to have a valid value for it (since gyros measure angular velocity) - m_Pose.vecAngularAcceleration[0] = 0.0; - m_Pose.vecAngularAcceleration[1] = 0.0; - m_Pose.vecAngularAcceleration[2] = 0.0; - - // this results in the controllers being shown on screen - m_Pose.result = vr::TrackingResult_Running_OK; - - // the pose validity also depends on HMD tracking data sent to us by the leap_monitor.exe - m_Pose.poseIsValid = m_bCalibrated; - } - } - - if (!handFound) - { - m_Pose.result = vr::TrackingResult_Running_OutOfRange; - m_Pose.poseIsValid = false; - } - - // This is very hard to know with this driver, but CServerDriver_Leap::ThreadFunc - // tries to reduce latency as much as possible. There is processing in the Leap Motion SDK, - // though, which causes additional unknown latency. This time is used to know how much - // extrapolation (via velocity and angular velocity) should be done when predicting poses. - m_Pose.poseTimeOffset = -0.016f; - - // when we get here, the Leap Motion is connected - m_Pose.deviceIsConnected = true; - - // These should always be false from any modern driver. These are for Oculus DK1-like - // rotation-only tracking. Support for that has likely rotted in vrserver. - m_Pose.willDriftInYaw = false; - m_Pose.shouldApplyHeadModel = false; - - // This call posts this pose to shared memory, where all clients will have access to it the next - // moment they want to predict a pose. - m_pDriverHost->TrackedDevicePoseUpdated(m_unSteamVRTrackedDeviceId, m_Pose); -} - -bool CLeapHmdLatest::IsActivated() const -{ - return m_unSteamVRTrackedDeviceId != vr::k_unTrackedDeviceIndexInvalid; -} - -bool CLeapHmdLatest::HasControllerId( int nBase, int nId ) -{ - return nBase == m_nBase && nId == m_nId; -} - -/** Process sixenseControllerData. Return true if it's new to help caller manage sleep durations */ -bool CLeapHmdLatest::Update(Frame &frame) -{ - UpdateTrackingState(frame); - UpdateControllerState(frame); - - return true; -} - -// Alignment of the coordinate system of driver_leap with the HMD: -void CLeapHmdLatest::RealignCoordinates( CLeapHmdLatest * pLeapA, CLeapHmdLatest * pLeapB ) -{ - if ( pLeapA->m_unSteamVRTrackedDeviceId == vr::k_unTrackedDeviceIndexInvalid ) - return; - - pLeapA->m_pAlignmentPartner = pLeapB; - pLeapB->m_pAlignmentPartner = pLeapA; - - // Ask leap_monitor to tell us HMD pose - static vr::VREvent_Data_t nodata = { 0 }; - pLeapA->m_pDriverHost->VendorSpecificEvent( pLeapA->m_unSteamVRTrackedDeviceId, - (vr::EVREventType) (vr::VREvent_VendorSpecific_Reserved_Start + 0), nodata, - -std::chrono::duration_cast( k_TrackingLatency ).count() ); -} - -// leap_monitor called us back with the HMD information -void CLeapHmdLatest::FinishRealignCoordinates(float(*m)[3], float *v ) -{ - CLeapHmdLatest * pLeapA = this; - CLeapHmdLatest * pLeapB = m_pAlignmentPartner; - - if ( !pLeapA || !pLeapB ) - return; - - vr::HmdQuaternion_t q = CalculateRotation(m); - pLeapA->UpdateHmdPose(v, q); - pLeapB->UpdateHmdPose(v, q); -} - -void CLeapHmdLatest::UpdateHmdPose(float *v, vr::HmdQuaternion_t q) -{ - memcpy(m_hmdPos, &v[0], sizeof(m_hmdPos)); - m_hmdRot = q; - m_bCalibrated = true; -} diff --git a/drivers/driver_leap/driver_leap.h b/drivers/driver_leap/driver_leap.h deleted file mode 100644 index 7669a119..00000000 --- a/drivers/driver_leap/driver_leap.h +++ /dev/null @@ -1,178 +0,0 @@ -#pragma once - -//========= Copyright Valve Corporation ============// - -#include -#include -#include -#include -#include -#include -#include - -#include "Leap.h" -#include "GestureMatcher.h" - -using namespace Leap; - -class CLeapHmdLatest; - -class CServerDriver_Leap : public vr::IServerTrackedDeviceProvider, public Listener -{ -public: - CServerDriver_Leap(); - virtual ~CServerDriver_Leap(); - - // Inherited via IServerTrackedDeviceProvider - virtual vr::EVRInitError Init( vr::IDriverLog * pDriverLog, vr::IServerDriverHost * pDriverHost, const char * pchUserDriverConfigDir, const char * pchDriverInstallDir ) override; - virtual void Cleanup() override; - virtual uint32_t GetTrackedDeviceCount() override; - virtual vr::ITrackedDeviceServerDriver * GetTrackedDeviceDriver( uint32_t unWhich ) override; - virtual vr::ITrackedDeviceServerDriver * FindTrackedDeviceDriver( const char * pchId ) override; - virtual const char * const *GetInterfaceVersions() { return vr::k_InterfaceVersions; } - virtual void RunFrame() override; - - virtual bool ShouldBlockStandbyMode() override; - virtual void EnterStandby() override; - virtual void LeaveStandby() override; - - void LaunchLeapMonitor(); - - // Leap::Listener interface - void onInit(const Controller&); - void onConnect(const Controller&); - void onDisconnect(const Controller&); - void onExit(const Controller&); - void onFrame(const Controller&); - void onFocusGained(const Controller&); - void onFocusLost(const Controller&); - void onServiceConnect(const Controller&); - void onServiceDisconnect(const Controller&); - void onDeviceChange(const Controller&); - void onImages(const Controller&); - void onServiceChange(const Controller&); - void onDeviceFailure(const Controller&); - void onLogMessage(const Controller&, MessageSeverity severity, int64_t timestamp, const char* msg); - - -private: - void ScanForNewControllers( bool bNotifyServer ); - - void LaunchLeapMonitor( const char * pchDriverInstallDir ); - - vr::IServerDriverHost* m_pDriverHost; - std::string m_strDriverInstallDir; - - bool m_bLaunchedLeapMonitor; - PROCESS_INFORMATION m_pInfoStartedProcess; - - // SteamVR's tracked controller objects - std::vector< CLeapHmdLatest * > m_vecControllers; - - // Leap Motion's Controller object - Controller *m_Controller; - - // a mutex for thread safety (Leap::Listener callbacks arrive from different threads) -// std::recursive_mutex m_Mutex; -// typedef std::lock_guard scope_lock; -}; - -class CClientDriver_Leap : public vr::IClientTrackedDeviceProvider -{ -public: - CClientDriver_Leap(); - virtual ~CClientDriver_Leap(); - - // Inherited via IClientTrackedDeviceProvider - virtual vr::EVRInitError Init( vr::IDriverLog * pDriverLog, vr::IClientDriverHost * pDriverHost, const char * pchUserDriverConfigDir, const char * pchDriverInstallDir ) override; - virtual void Cleanup() override; - virtual bool BIsHmdPresent( const char * pchUserConfigDir ) override; - virtual vr::EVRInitError SetDisplayId( const char * pchDisplayId ) override; - virtual vr::HiddenAreaMesh_t GetHiddenAreaMesh( vr::EVREye eEye ) override; - virtual uint32_t GetMCImage( uint32_t *pImgWidth, uint32_t *pImgHeight, uint32_t *pChannels, void *pDataBuffer, uint32_t unBufferLen ) override; - -private: - vr::IClientDriverHost* m_pDriverHost; - -}; - -class CLeapHmdLatest : public vr::ITrackedDeviceServerDriver, public vr::IVRControllerComponent -{ -public: - CLeapHmdLatest( vr::IServerDriverHost * pDriverHost, int base, int n ); - virtual ~CLeapHmdLatest(); - - // Implementation of vr::ITrackedDeviceServerDriver - virtual vr::EVRInitError Activate( uint32_t unObjectId ) override; - virtual void Deactivate() override; - virtual void PowerOff() override; - void *GetComponent( const char *pchComponentNameAndVersion ) override; - virtual void DebugRequest( const char * pchRequest, char * pchResponseBuffer, uint32_t unResponseBufferSize ) override; - virtual vr::DriverPose_t GetPose() override; - virtual bool GetBoolTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError * pError ) override; - virtual float GetFloatTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError * pError ) override; - virtual int32_t GetInt32TrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError * pError ) override; - virtual uint64_t GetUint64TrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError * pError ) override; - virtual vr::HmdMatrix34_t GetMatrix34TrackedDeviceProperty( vr::ETrackedDeviceProperty prop, vr::ETrackedPropertyError *pError ) override; - virtual uint32_t GetStringTrackedDeviceProperty( vr::ETrackedDeviceProperty prop, char * pchValue, uint32_t unBufferSize, vr::ETrackedPropertyError * pError ) override; - - // Implementation of vr::IVRControllerComponent - virtual vr::VRControllerState_t GetControllerState() override; - virtual bool TriggerHapticPulse( uint32_t unAxisId, uint16_t usPulseDurationMicroseconds ) override; - - bool IsActivated() const; - bool HasControllerId( int nBase, int nId ); - bool Update(Frame &frame); - const char *GetSerialNumber(); - - static void RealignCoordinates( CLeapHmdLatest * pLeapA, CLeapHmdLatest * pLeapB ); - void FinishRealignCoordinates( float (*m)[3], float *v ); - void UpdateHmdPose(float *v, vr::HmdQuaternion_t q); - - uint32_t GetDeviceId() { return m_unSteamVRTrackedDeviceId; } - -private: - static const std::chrono::milliseconds k_TrackingLatency; - - typedef void ( vr::IServerDriverHost::*ButtonUpdate )( uint32_t unWhichDevice, vr::EVRButtonId eButtonId, double eventTimeOffset ); - - void SendButtonUpdates( ButtonUpdate ButtonEvent, uint64_t ulMask ); - void UpdateControllerState(Frame &frame); - void UpdateTrackingState(Frame &frame); - - // Handle for calling back into vrserver with events and updates - vr::IServerDriverHost *m_pDriverHost; - - // Which Leap controller - int m_nBase; - int m_nId; - std::string m_strSerialNumber; - - // To main structures for passing state to vrserver - vr::DriverPose_t m_Pose; - vr::VRControllerState_t m_ControllerState; - - // Ancillary tracking state - bool m_bCalibrated; - float m_hmdPos[3]; - vr::HmdQuaternion_t m_hmdRot; - - // Other controller with from the last realignment - CLeapHmdLatest *m_pAlignmentPartner; - - // Cached for answering version queries from vrserver - unsigned short m_firmware_revision; - unsigned short m_hardware_revision; - - // Assigned by vrserver upon Activate(). The same ID visible to clients - uint32_t m_unSteamVRTrackedDeviceId; - - // The rendermodel used by the device. Check the contents of "c:\Program Files (x86)\Steam\steamapps\common\SteamVR\resources\rendermodels" for available models. - std::string m_strRenderModel; - - // with this angle offset you can emulate the angle of a gun grip. Positive values tilt the controller up by N degrees. - float m_gripAngleOffset; - - // a helper object to identify hand poses - GestureMatcher matcher; -}; \ No newline at end of file diff --git a/drivers/driver_leap/driver_leap.vcxproj b/drivers/driver_leap/driver_leap.vcxproj deleted file mode 100644 index fe7c1c20..00000000 --- a/drivers/driver_leap/driver_leap.vcxproj +++ /dev/null @@ -1,264 +0,0 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - {52d3f16d-a7a5-4d6f-8f17-5e4b459a1440} - DynamicLibrary - driver_leap - driver_leap - en-US - 12.0 - 8.1 - 8.1 - - - - DynamicLibrary - true - v140 - - - DynamicLibrary - true - v140 - - - DynamicLibrary - false - true - v140 - - - DynamicLibrary - false - true - v140 - - - - - - - - - - - - - - - - - - - - - - - - - - false - false - - - false - AllRules.ruleset - - - false - false - - - false - AllRules.ruleset - - - false - false - - - false - false - - - - NotUsing - false - $(LeapSDKDir)\include;$(OpenVRDir)\headers;%(AdditionalIncludeDirectories) - false - - - Windows - false - false - $(LeapSDKDir)\lib\x86;$(OpenVRDir)\lib\win32;%(AdditionalLibraryDirectories) - Leap.lib;%(AdditionalDependencies) - - - - - - - - - - - mkdir "$(InstallDir)\bin\Win32" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win32" -copy "$(LeapSDKDir)\lib\x86\Leap.dll" "$(InstallDir)\bin\Win32" -rem "$(SteamVRRuntimeDir)\bin\win32\vrpathreg" adddriver "$(InstallDir)" -xcopy /s /i /y "$(SolutionDir)\resources" "$(InstallDir)\resources" - - - Install Binary - - - - - NotUsing - false - $(LeapSDKDir)\include;$(OpenVRDir)\headers;%(AdditionalIncludeDirectories) - false - - - Windows - false - false - $(LeapSDKDir)\lib\x86;$(OpenVRDir)\lib\win32;%(AdditionalLibraryDirectories) - Leap.lib;%(AdditionalDependencies) - - - - - - - - - - - mkdir "$(InstallDir)\bin\Win32" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win32" -copy "$(LeapSDKDir)\lib\x86\Leap.dll" "$(InstallDir)\bin\Win32" -rem "$(SteamVRRuntimeDir)\bin\win32\vrpathreg" adddriver "$(InstallDir)" -xcopy /s /i /y "$(SolutionDir)\resources" "$(InstallDir)\resources" - - - Install Binary - - - - - Use - false - - - Console - false - false - - - - - Use - false - - - Console - false - false - - - - - Use - false - $(LeapSDKDir)\include;$(OpenVRDir)\headers;%(AdditionalIncludeDirectories) - pch.h - - - Windows - false - false - $(LeapSDKDir)\lib\x64;$(OpenVRDir)\lib\win64;%(AdditionalLibraryDirectories) - Leap.lib;%(AdditionalDependencies) - - - - - - mkdir "$(InstallDir)\bin\Win64" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win64" -copy "$(LeapSDKDir)\lib\x64\Leap.dll" "$(InstallDir)\bin\Win64" -rem "$(SteamVRRuntimeDir)\bin\win32\vrpathreg" adddriver "$(InstallDir)" -xcopy /s /i /y "$(SolutionDir)\resources" "$(InstallDir)\resources" - Install Binary - - - - - NotUsing - false - $(LeapSDKDir)\include;$(OpenVRDir)\headers;%(AdditionalIncludeDirectories) - pch.h - - - Windows - false - false - $(LeapSDKDir)\lib\x64;$(OpenVRDir)\lib\win64;%(AdditionalLibraryDirectories) - Leap.lib;%(AdditionalDependencies) - - - - - - mkdir "$(InstallDir)\bin\Win64" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win64" -copy "$(LeapSDKDir)\lib\x64\Leap.dll" "$(InstallDir)\bin\Win64" -rem "$(SteamVRRuntimeDir)\bin\win32\vrpathreg" adddriver "$(InstallDir)" -xcopy /s /i /y "$(SolutionDir)\resources" "$(InstallDir)\resources" - Install Binary - - - - - - - - - - - - - - NotUsing - NotUsing - Create - Create - - - - - - - - - \ No newline at end of file diff --git a/drivers/driver_leap/driver_leap.vcxproj.filters b/drivers/driver_leap/driver_leap.vcxproj.filters deleted file mode 100644 index 7b0e8589..00000000 --- a/drivers/driver_leap/driver_leap.vcxproj.filters +++ /dev/null @@ -1,26 +0,0 @@ - - - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tga;tiff;tif;png;wav;mfcribbon-ms - - - - - - - - - - - - - - - - - Resource Files - - - \ No newline at end of file diff --git a/drivers/driver_leap/pch.cpp b/drivers/driver_leap/pch.cpp deleted file mode 100644 index bcb5590b..00000000 --- a/drivers/driver_leap/pch.cpp +++ /dev/null @@ -1 +0,0 @@ -#include "pch.h" diff --git a/drivers/driver_leap/pch.h b/drivers/driver_leap/pch.h deleted file mode 100644 index 5f585fb4..00000000 --- a/drivers/driver_leap/pch.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "targetver.h" - -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#endif - -#define NOMINMAX -#include diff --git a/drivers/driver_leap/targetver.h b/drivers/driver_leap/targetver.h deleted file mode 100644 index a66ecb00..00000000 --- a/drivers/driver_leap/targetver.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include diff --git a/leap_control/App.config b/leap_control/App.config new file mode 100644 index 00000000..ecdcf8a5 --- /dev/null +++ b/leap_control/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/leap_control/Core/Core.cs b/leap_control/Core/Core.cs new file mode 100644 index 00000000..c7d6f307 --- /dev/null +++ b/leap_control/Core/Core.cs @@ -0,0 +1,109 @@ +using System; + +namespace leap_control +{ + class Core + { + bool m_initialized = false; + bool m_active = false; + + SfmlManager m_sfmlManager = null; + VRManager m_vrManager = null; + LeapManager m_leapManager = null; + ControlManager m_controlManager = null; + + System.Windows.Forms.NotifyIcon m_trayIcon = null; + + public ControlManager ControlManager + { + get => m_controlManager; + } + + public VRManager VRManager + { + get => m_vrManager; + } + + bool Initialize() + { + if(!m_initialized) + { + m_sfmlManager = new SfmlManager(); + m_vrManager = new VRManager(this); + m_leapManager = new LeapManager(this); + m_controlManager = new ControlManager(this); + + m_trayIcon = new System.Windows.Forms.NotifyIcon(); + try + { + m_trayIcon.Icon = new System.Drawing.Icon("icon.ico"); + } + catch(Exception) { } + m_trayIcon.Text = "Driver Leap Control"; + m_trayIcon.Visible = true; + + m_initialized = (m_vrManager.Initialize() && m_sfmlManager.Initialize() && m_leapManager.Initialize() && m_controlManager.Initialize()); + m_active = m_initialized; + } + + return m_initialized; + } + + void Terminate() + { + if(m_controlManager != null) + { + m_controlManager.Terminate(); + m_controlManager = null; + } + + if(m_leapManager != null) + { + m_leapManager.Terminate(); + m_leapManager = null; + } + + if(m_sfmlManager != null) + { + m_sfmlManager.Terminate(); + m_sfmlManager = null; + } + + if(m_vrManager != null) + { + m_vrManager.Terminate(); + m_vrManager = null; + } + + if(m_trayIcon != null) + { + m_trayIcon.Visible = false; + m_trayIcon.Dispose(); + m_trayIcon = null; + } + + m_initialized = false; + } + + bool DoPulse() + { + m_active |= m_vrManager.DoPulse(); + m_leapManager.DoPulse(); + m_controlManager.DoPulse(); + + m_sfmlManager.DoPulse(); + return m_active; + } + + static void Main(string[] args) + { + Core l_core = new Core(); + if(l_core.Initialize()) + { + while(l_core.DoPulse()) ; + l_core.Terminate(); + } + + } + } +} diff --git a/leap_control/Managers/ControlManager.cs b/leap_control/Managers/ControlManager.cs new file mode 100644 index 00000000..3ed18154 --- /dev/null +++ b/leap_control/Managers/ControlManager.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace leap_control +{ + class ControlManager + { + public enum Hand + { + Left = 0, + Right + }; + + static readonly GlmSharp.vec4 ms_pointMultiplier = new GlmSharp.vec4(0f, 0f, 0f, 1f); + + bool m_initialized = false; + + Core m_core = null; + + HandOverlay m_leftHandOverlay = null; + HandOverlay m_rightHandOverlay = null; + + ulong m_leftFingerOverlay = 0; + ulong m_rightFingerOverlay = 0; + + GlmSharp.mat4 m_headTransform; + + public ControlManager(Core f_core) + { + m_core = f_core; + } + + public bool Initialize() + { + if(!m_initialized) + { + HandOverlay.LoadResources(); + + m_leftHandOverlay = new HandOverlay(HandOverlay.Hand.Left); + m_rightHandOverlay = new HandOverlay(HandOverlay.Hand.Right); + + Valve.VR.OpenVR.Overlay.CreateOverlay("leap.cursor.left", "Left Hand Finger Cursor", ref m_leftFingerOverlay); + Valve.VR.OpenVR.Overlay.SetOverlayFromFile(m_leftFingerOverlay, System.AppDomain.CurrentDomain.BaseDirectory + "resources\\tx_cursor.png"); + Valve.VR.OpenVR.Overlay.SetOverlayColor(m_leftFingerOverlay, 0f, 1f, 0f); + Valve.VR.OpenVR.Overlay.SetOverlayWidthInMeters(m_leftFingerOverlay, 0.006625f); + Valve.VR.OpenVR.Overlay.SetOverlaySortOrder(m_leftFingerOverlay, 1); + Valve.VR.OpenVR.Overlay.ShowOverlay(m_leftFingerOverlay); + + Valve.VR.OpenVR.Overlay.CreateOverlay("leap.cursor.right", "Left Hand Finger Cursor", ref m_rightFingerOverlay); + Valve.VR.OpenVR.Overlay.SetOverlayFromFile(m_rightFingerOverlay, System.AppDomain.CurrentDomain.BaseDirectory + "resources\\tx_cursor.png"); + Console.WriteLine(System.AppDomain.CurrentDomain.BaseDirectory + "resources\\tx_cursor.png"); + Valve.VR.OpenVR.Overlay.SetOverlayColor(m_rightFingerOverlay, 0f, 1f, 0f); + Valve.VR.OpenVR.Overlay.SetOverlaySortOrder(m_rightFingerOverlay, 1); + Valve.VR.OpenVR.Overlay.SetOverlayWidthInMeters(m_rightFingerOverlay, 0.00625f); + Valve.VR.OpenVR.Overlay.ShowOverlay(m_rightFingerOverlay); + + m_initialized = true; + } + + return m_initialized; + } + + public void Terminate() + { + if(m_initialized) + { + m_leftHandOverlay = null; + m_rightHandOverlay = null; + m_initialized = false; + } + } + + public void SetHandTransform(Hand f_hand, GlmSharp.mat4 f_mat) + { + switch(f_hand) + { + case Hand.Left: + m_leftHandOverlay.SetWorldTransform(f_mat); + break; + case Hand.Right: + m_rightHandOverlay.SetWorldTransform(f_mat); + break; + } + } + + public void SetHandPresence(Hand f_hand, bool f_state, GlmSharp.vec3 f_tipPos) + { + switch(f_hand) + { + case Hand.Left: + { + m_leftHandOverlay.SetHandPresence(f_state, f_tipPos); + + Valve.VR.HmdMatrix34_t l_matrix = new Valve.VR.HmdMatrix34_t(); + (m_headTransform * GlmSharp.mat4.Translate(f_tipPos)).Convert(ref l_matrix); + Valve.VR.OpenVR.Overlay.SetOverlayTransformAbsolute(m_leftFingerOverlay, Valve.VR.ETrackingUniverseOrigin.TrackingUniverseRawAndUncalibrated, ref l_matrix); + } + break; + case Hand.Right: + { + + m_rightHandOverlay.SetHandPresence(f_state, f_tipPos); + + Valve.VR.HmdMatrix34_t l_matrix = new Valve.VR.HmdMatrix34_t(); + (m_headTransform * GlmSharp.mat4.Translate(f_tipPos)).Convert(ref l_matrix); + Valve.VR.OpenVR.Overlay.SetOverlayTransformAbsolute(m_rightFingerOverlay, Valve.VR.ETrackingUniverseOrigin.TrackingUniverseRawAndUncalibrated, ref l_matrix); + } + break; + } + } + + public void SetHeadTransform(GlmSharp.mat4 f_transform) + { + m_headTransform = f_transform; + } + + public void DoPulse() + { + m_leftHandOverlay.Update(m_headTransform); + m_rightHandOverlay.Update(m_headTransform); + + ProcessControls(m_leftHandOverlay.GetControlButtons(), Hand.Left); + ProcessControls(m_rightHandOverlay.GetControlButtons(), Hand.Right); + } + + void ProcessControls(List l_buttons, Hand f_hand) + { + foreach(var l_controlButton in l_buttons) + { + if(l_controlButton.IsUpdated()) + { + string l_message = "input "; + l_message += f_hand.ToString().ToLower(); + l_message += ' '; + switch(l_controlButton.GetButtonType()) + { + case ControlButton.ButtonType.Button: + l_message += "button "; + break; + case ControlButton.ButtonType.Axis: + l_message += "axis "; + break; + } + l_message += l_controlButton.GetButtonName(); + l_message += ' '; + + l_message += l_controlButton.GetButtonState().ToString().ToLower(); + + if(l_controlButton.GetButtonType() == ControlButton.ButtonType.Axis) + { + var l_axisValues = l_controlButton.GetAxisValues(); + + l_message += ' '; + l_message += l_axisValues.x.ToString("0.0", System.Globalization.CultureInfo.InvariantCulture); + l_message += ' '; + l_message += l_axisValues.y.ToString("0.0", System.Globalization.CultureInfo.InvariantCulture); + } + + m_core.VRManager.SendMessage(l_message); + } + } + } + } +} diff --git a/leap_control/Managers/LeapManager.cs b/leap_control/Managers/LeapManager.cs new file mode 100644 index 00000000..0bc0e4b8 --- /dev/null +++ b/leap_control/Managers/LeapManager.cs @@ -0,0 +1,121 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace leap_control +{ + class LeapManager + { + static readonly GlmSharp.vec3 ms_zeroPoint = new GlmSharp.vec3(0f); + + bool m_initialized = false; + + readonly Core m_core = null; + + Leap.Controller m_controller = null; + + GlmSharp.vec3 m_leftTipPosition; + GlmSharp.vec3 m_rightTipPosition; + + public LeapManager(Core f_core) + { + m_core = f_core; + } + + public bool Initialize() + { + if(!m_initialized) + { + m_controller = new Leap.Controller(); + m_controller.StartConnection(); + m_controller.PolicyChange += OnControllerPolicyChange; + m_controller.Device += OnControllerConnected; + m_controller.DeviceLost += OnControllerDisconnected; + m_initialized = true; + } + + return m_initialized; + } + + public void Terminate() + { + if(m_initialized) + { + if(m_controller != null) + { + m_controller.StopConnection(); + m_controller.Dispose(); + m_controller = null; + } + + m_initialized = false; + } + } + + void OnControllerPolicyChange(object sender, Leap.PolicyEventArgs e) + { + m_core.VRManager.ShowNotification("Policies changed"); + } + + void OnControllerConnected(object sender, Leap.DeviceEventArgs e) + { + m_core.VRManager.ShowNotification("Controller connected"); + } + + void OnControllerDisconnected(object sender, Leap.DeviceEventArgs e) + { + m_core.VRManager.ShowNotification("Controller disconnected"); + } + + public void DoPulse() + { + if(m_controller.IsConnected) + { + bool l_leftFound = false; + bool l_rightFound = false; + + Leap.Frame l_frame = m_controller.Frame(); + if(l_frame != null) + { + foreach(Leap.Hand l_hand in l_frame.Hands) + { + if(l_hand.IsLeft && !l_leftFound) + { + l_leftFound = true; + foreach(Leap.Finger l_finger in l_hand.Fingers) + { + if(l_finger.Type == Leap.Finger.FingerType.TYPE_INDEX) + { + l_finger.TipPosition.Convert(ref m_leftTipPosition); + ConvertOrientation(ref m_leftTipPosition); + break; + } + } + continue; + } + if(l_hand.IsRight && !l_rightFound) + { + l_rightFound = true; + foreach(Leap.Finger l_finger in l_hand.Fingers) + { + if(l_finger.Type == Leap.Finger.FingerType.TYPE_INDEX) + { + l_finger.TipPosition.Convert(ref m_rightTipPosition); + ConvertOrientation(ref m_rightTipPosition); + break; + } + } + } + } + } + + m_core.ControlManager.SetHandPresence(ControlManager.Hand.Left, l_rightFound, l_rightFound ? m_rightTipPosition : ms_zeroPoint); + m_core.ControlManager.SetHandPresence(ControlManager.Hand.Right, l_leftFound, l_leftFound ? m_leftTipPosition : ms_zeroPoint); + } + } + + void ConvertOrientation(ref GlmSharp.vec3 f_vec) => f_vec = -0.001f * f_vec.swizzle.xzy; + } +} diff --git a/leap_control/Managers/SfmlManager.cs b/leap_control/Managers/SfmlManager.cs new file mode 100644 index 00000000..2fc4b8fc --- /dev/null +++ b/leap_control/Managers/SfmlManager.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace leap_control +{ + class SfmlManager + { + bool m_initialized = false; + + SFML.Window.Context m_context = null; + + public bool Initialize() + { + if(!m_initialized) + { + m_context = new SFML.Window.Context(); + m_initialized = m_context.SetActive(true); + } + + return m_initialized; + } + + public void Terminate() + { + if(m_initialized && (m_context != null)) + { + m_context.SetActive(false); + + m_context = null; + m_initialized = false; + } + } + + public void DoPulse() + { + System.Threading.Thread.Sleep(16); + } + } +} diff --git a/leap_control/Managers/VRManager.cs b/leap_control/Managers/VRManager.cs new file mode 100644 index 00000000..3b20e52d --- /dev/null +++ b/leap_control/Managers/VRManager.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Valve.VR; + +namespace leap_control +{ + class VRManager + { + bool m_initialized = false; + + readonly Core m_core = null; + + CVRSystem m_vrSystem; + VREvent_t m_vrEvent; + static uint ms_eventSize = 0; + bool m_active = false; + + ulong m_notificationOverlay = 0; + uint m_leapDevice = 0; + uint m_leftHandController = 0; + uint m_rightHandController = 0; + + TrackedDevicePose_t[] m_trackedPoses = null; + + public VRManager(Core f_core) + { + m_core = f_core; + + m_trackedPoses = new TrackedDevicePose_t[OpenVR.k_unMaxTrackedDeviceCount]; + } + + public bool Initialize() + { + if(!m_initialized) + { + EVRInitError l_initError = EVRInitError.None; + m_vrSystem = OpenVR.Init(ref l_initError, EVRApplicationType.VRApplication_Overlay); + if(l_initError == EVRInitError.None) + { + OpenVR.Overlay.CreateOverlay("leap.control.notification", "Ultraleap Control", ref m_notificationOverlay); + + // Find fake Leap Motion station device + for(uint i = 0; i < OpenVR.k_unMaxTrackedDeviceCount; i++) + { + ETrackedPropertyError l_propertyError = ETrackedPropertyError.TrackedProp_Success; + ulong l_property = m_vrSystem.GetUint64TrackedDeviceProperty(i, ETrackedDeviceProperty.Prop_VendorSpecific_Reserved_Start, ref l_propertyError); + if((l_propertyError == ETrackedPropertyError.TrackedProp_Success) && (l_property == 0x4C4D6F74696F6E)) + { + m_leapDevice = i; + break; + } + } + + ms_eventSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(m_vrEvent); + m_initialized = true; + m_active = true; + } + + } + + return m_initialized; + } + + public void Terminate() + { + if(m_initialized) + { + + m_initialized = false; + } + } + + public bool DoPulse() + { + m_vrSystem.GetDeviceToAbsoluteTrackingPose(ETrackingUniverseOrigin.TrackingUniverseRawAndUncalibrated, 0f, m_trackedPoses); + + while(m_vrSystem.PollNextEvent(ref m_vrEvent, ms_eventSize)) + { + switch(m_vrEvent.eventType) + { + case (uint)EVREventType.VREvent_Quit: + m_active = false; + break; + case (uint)EVREventType.VREvent_TrackedDeviceDeactivated: + { + if(m_leftHandController == m_vrEvent.trackedDeviceIndex) + m_leftHandController = 0; + if(m_rightHandController == m_vrEvent.trackedDeviceIndex) + m_rightHandController = 0; + } + break; + } + } + + if(m_trackedPoses[OpenVR.k_unTrackedDeviceIndex_Hmd].bPoseIsValid) + { + GlmSharp.mat4 l_matrix = GlmSharp.mat4.Identity; + m_trackedPoses[OpenVR.k_unTrackedDeviceIndex_Hmd].mDeviceToAbsoluteTracking.Convert(ref l_matrix); + m_core.ControlManager.SetHeadTransform(l_matrix); + } + + if(m_leftHandController != 0) + { + GlmSharp.mat4 l_matrix = GlmSharp.mat4.Identity; + m_trackedPoses[m_leftHandController].mDeviceToAbsoluteTracking.Convert(ref l_matrix); + m_core.ControlManager.SetHandTransform(ControlManager.Hand.Left, l_matrix); + } + else + m_leftHandController = m_vrSystem.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.LeftHand); + + if(m_rightHandController != 0) + { + GlmSharp.mat4 l_matrix = GlmSharp.mat4.Identity; + m_trackedPoses[m_rightHandController].mDeviceToAbsoluteTracking.Convert(ref l_matrix); + m_core.ControlManager.SetHandTransform(ControlManager.Hand.Right, l_matrix); + } + else + m_rightHandController = m_vrSystem.GetTrackedDeviceIndexForControllerRole(ETrackedControllerRole.RightHand); + + return m_active; + } + + public void SendMessage(string f_message) + { + Console.WriteLine(f_message); + if(m_leapDevice != 0) + { + StringBuilder l_stringBuilder = new StringBuilder(32); + OpenVR.Debug.DriverDebugRequest(m_leapDevice, f_message, l_stringBuilder, 32); + } + } + + public void ShowNotification(string f_message) + { + // Why is it borked? It worked in C++, ffs + uint l_notification = 0; + NotificationBitmap_t l_bitmap = new NotificationBitmap_t(); + l_bitmap.m_pImageData = (IntPtr)0; + l_bitmap.m_nHeight = 0; + l_bitmap.m_nWidth = 0; + l_bitmap.m_nBytesPerPixel = 0; + Console.WriteLine(OpenVR.Notifications.CreateNotification(m_notificationOverlay, 500, EVRNotificationType.Transient, f_message, EVRNotificationStyle.None, ref l_bitmap, ref l_notification).ToString()); + } + } +} diff --git a/leap_control/Overlay/ControlButton.cs b/leap_control/Overlay/ControlButton.cs new file mode 100644 index 00000000..0065ac4a --- /dev/null +++ b/leap_control/Overlay/ControlButton.cs @@ -0,0 +1,61 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace leap_control +{ + class ControlButton + { + public enum ButtonType + { + Button = 0, + Axis + }; + + public enum ButtonState + { + None = 0, + Touched, + Clicked + } + + string m_name; + ButtonType m_type; + ButtonState m_state; + GlmSharp.vec2 m_axisValues; + bool m_updated = false; + + public ControlButton(ButtonType f_type, string f_name) + { + m_name = f_name; + m_type = f_type; + } + + public void SetState(ButtonState f_state) + { + if(m_state != f_state) + { + m_state = f_state; + m_updated = true; + } + } + + public void SetAxes(GlmSharp.vec2 f_vec) + { + if(m_type == ButtonType.Axis && (m_axisValues != f_vec)) + { + m_axisValues = f_vec; + m_updated = true; + } + } + + public string GetButtonName() => m_name; + public ButtonType GetButtonType() => m_type; + public ButtonState GetButtonState() => m_state; + public GlmSharp.vec2 GetAxisValues() => m_axisValues; + public bool IsUpdated() => m_updated; + public void ResetUpdate() => m_updated = false; + } +} diff --git a/leap_control/Overlay/HandOverlay.cs b/leap_control/Overlay/HandOverlay.cs new file mode 100644 index 00000000..b3996dfd --- /dev/null +++ b/leap_control/Overlay/HandOverlay.cs @@ -0,0 +1,300 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace leap_control +{ + class HandOverlay + { + public enum Hand + { + Left = 0, + Right + }; + + public enum ButtonIndex + { + A = 0, + B, + System, + Thumbstick, + Touchpad + }; + + static readonly string[] ms_overlayNames = { "leap.overlay.handLeft", "leap.overlay.handRight" }; + static readonly SFML.Graphics.Color ms_emptyColor = new SFML.Graphics.Color(0x0, 0x0, 0x0, 0x0); + static readonly SFML.Graphics.Color ms_backgroundColor = new SFML.Graphics.Color(0x4D, 0x4D, 0x4D); + static readonly SFML.Graphics.Color ms_inactiveColor = new SFML.Graphics.Color(0x33, 0x33, 0x33); + static readonly SFML.Graphics.Color ms_activeColor = new SFML.Graphics.Color(0x33, 0x99, 0xFF); + static readonly SFML.Graphics.Color ms_touchColor = new SFML.Graphics.Color(0xFF, 0x00, 0x00); + static readonly SFML.Graphics.Color ms_axisColorTouch = new SFML.Graphics.Color(0x00, 0xFF, 0x00); + static readonly SFML.Graphics.Color ms_axisColorClick = new SFML.Graphics.Color(0xFF, 0xA5, 0x00); + static readonly GlmSharp.vec3 ms_forwardDirection = new GlmSharp.vec3(0f, 0f, -1f); + //static readonly GlmSharp.vec3 ms_backwardDirection = new GlmSharp.vec3(0f, 0f, 1f); + static readonly GlmSharp.vec4 ms_pointMultiplier = new GlmSharp.vec4(0f, 0f, 0f, 1f); + static readonly float ms_overlayWidth = 0.125f; + static readonly float ms_overlayWidthHalf = ms_overlayWidth * 0.5f; + static readonly float ms_touchDistance = ms_overlayWidth * 0.5f * 0.5f; + static readonly float ms_clickDistance = ms_overlayWidth * 0.5f * 0.333333f; + static readonly float ms_radius = (float)Math.Sqrt(2f * Math.Pow(ms_overlayWidth * 0.5f, 2f)); + static readonly GlmSharp.quat ms_rotation = new GlmSharp.quat(new GlmSharp.vec3(-(float)Math.PI / 2f, 0f, 0f)); + static readonly GlmSharp.vec3 ms_displacement = new GlmSharp.vec3(0f, 0f, 0.0625f); + + static Dictionary ms_resources = new Dictionary(); + + ulong m_overlay = 0; + Valve.VR.Texture_t m_overlayTexture; + + SFML.Graphics.RenderTexture m_renderTexture = null; + SFML.Graphics.Sprite m_backgroundSprite = null; + SFML.Graphics.Sprite m_thumbstickShape = null; + SFML.Graphics.Sprite m_touchpadShape = null; + SFML.Graphics.Sprite m_buttonA = null; + SFML.Graphics.Sprite m_buttonB = null; + SFML.Graphics.Sprite m_buttonSystem = null; + SFML.Graphics.CircleShape m_cursorShape = null; + SFML.Graphics.CircleShape m_thumbstickAxisShape = null; + SFML.Graphics.CircleShape m_touchpadAxisShape = null; + SFML.Graphics.RectangleShape m_presureRectangle = null; + SFML.Graphics.RectangleShape m_presureFillRectangle = null; + + GlmSharp.vec3 m_position; + GlmSharp.quat m_rotation; + GlmSharp.vec3 m_direction; + GlmSharp.mat4 m_matrix; + Valve.VR.HmdMatrix34_t m_vrMatrix; + + GlmSharp.vec3 m_tipPositionLocal; + GlmSharp.vec3 m_tipPositionGlobal; + bool m_handPresence = false; + + bool m_inRange = false; + GlmSharp.vec3 m_cursorPosition; + GlmSharp.vec2 m_cursorPlanePosition; + + List m_controlButtons = null; + + public HandOverlay(Hand f_hand) + { + m_renderTexture = new SFML.Graphics.RenderTexture(512, 512); + + m_backgroundSprite = new SFML.Graphics.Sprite(ms_resources["background"]); + m_backgroundSprite.Color = ms_backgroundColor; + + m_thumbstickShape = new SFML.Graphics.Sprite(ms_resources["circle"]); + m_thumbstickShape.Color = ms_inactiveColor; + m_thumbstickShape.Position = new SFML.System.Vector2f(40f, 40f); + + m_touchpadShape = new SFML.Graphics.Sprite(ms_resources["circle"]); + m_touchpadShape.Color = ms_inactiveColor; + m_touchpadShape.Position = new SFML.System.Vector2f(40f, 270f); + + m_buttonB = new SFML.Graphics.Sprite(ms_resources["buttonB"]); + m_buttonB.Color = ms_inactiveColor; + m_buttonB.Position = new SFML.System.Vector2f(310f, 95f); + + m_buttonA = new SFML.Graphics.Sprite(ms_resources["buttonA"]); + m_buttonA.Color = ms_inactiveColor; + m_buttonA.Position = new SFML.System.Vector2f(310f, 210f); + + m_buttonSystem = new SFML.Graphics.Sprite(ms_resources["buttonS"]); + m_buttonSystem.Color = ms_inactiveColor; + m_buttonSystem.Position = new SFML.System.Vector2f(310f, 325f); + + m_cursorShape = new SFML.Graphics.CircleShape(5f); + m_cursorShape.FillColor = ms_activeColor; + + m_thumbstickAxisShape = new SFML.Graphics.CircleShape(7.5f); + m_thumbstickAxisShape.FillColor = ms_axisColorTouch; + + m_touchpadAxisShape = new SFML.Graphics.CircleShape(7.5f); + m_touchpadAxisShape.FillColor = ms_axisColorTouch; + + m_presureRectangle = new SFML.Graphics.RectangleShape(new SFML.System.Vector2f(10f, 320f)); + m_presureRectangle.Position = new SFML.System.Vector2f(480f, 100f); + m_presureRectangle.FillColor = ms_inactiveColor; + + m_presureFillRectangle = new SFML.Graphics.RectangleShape(new SFML.System.Vector2f(10f, -320f)); + m_presureFillRectangle.Position = new SFML.System.Vector2f(480f, 420f); + m_presureFillRectangle.FillColor = ms_inactiveColor; + + // Create overlay + Valve.VR.OpenVR.Overlay.CreateOverlay(ms_overlayNames[(int)f_hand], "Ultraleap hand overlay", ref m_overlay); + Valve.VR.OpenVR.Overlay.SetOverlayWidthInMeters(m_overlay, ms_overlayWidth); + Valve.VR.OpenVR.Overlay.ShowOverlay(m_overlay); + m_overlayTexture.eColorSpace = Valve.VR.EColorSpace.Gamma; + m_overlayTexture.eType = Valve.VR.ETextureType.OpenGL; + m_overlayTexture.handle = (IntPtr)m_renderTexture.Texture.NativeHandle; + + // Controls + m_controlButtons = new List(); + m_controlButtons.Add(new ControlButton(ControlButton.ButtonType.Button, "a")); + m_controlButtons.Add(new ControlButton(ControlButton.ButtonType.Button, "b")); + m_controlButtons.Add(new ControlButton(ControlButton.ButtonType.Button, "system")); + m_controlButtons.Add(new ControlButton(ControlButton.ButtonType.Axis, "thumbstick")); + m_controlButtons.Add(new ControlButton(ControlButton.ButtonType.Axis, "touchpad")); + } + + public void SetWorldTransform(GlmSharp.mat4 f_mat) + { + m_position = (f_mat * ms_pointMultiplier).xyz; + m_rotation = f_mat.ToQuaternion * ms_rotation; + m_direction = m_rotation * ms_forwardDirection; + m_position += m_rotation * ms_displacement; + } + + public void SetHandPresence(bool f_presence, GlmSharp.vec3 f_tipPos) + { + m_handPresence = f_presence; + m_tipPositionLocal = f_tipPos; + } + + public List GetControlButtons() => m_controlButtons; + + public void Update(GlmSharp.mat4 f_headTransform) + { + // Reset controls + foreach(ControlButton l_controlButton in m_controlButtons) + l_controlButton.ResetUpdate(); + + m_tipPositionGlobal = ((f_headTransform * GlmSharp.mat4.Translate(m_tipPositionLocal)) * ms_pointMultiplier).xyz; + + // Update overlays transform + m_matrix = (GlmSharp.mat4.Translate(m_position) * m_rotation.ToMat4); + m_matrix.Convert(ref m_vrMatrix); + Valve.VR.OpenVR.Overlay.SetOverlayTransformAbsolute(m_overlay, Valve.VR.ETrackingUniverseOrigin.TrackingUniverseRawAndUncalibrated, ref m_vrMatrix); + + m_cursorPosition = ((m_matrix.Inverse * GlmSharp.mat4.Translate(m_tipPositionGlobal)) * ms_pointMultiplier).xyz; + if(m_handPresence && m_cursorPosition.IsInRange(-ms_overlayWidthHalf, ms_overlayWidthHalf) && (m_cursorPosition.z > -0.025f)) + { + m_cursorShape.FillColor = ((m_cursorPosition.z <= ms_touchDistance) ? ms_touchColor : ms_activeColor); + m_cursorPlanePosition.x = ((m_cursorPosition.x + ms_overlayWidthHalf) / ms_overlayWidth) * 512f; + m_cursorPlanePosition.y = ((-m_cursorPosition.y + ms_overlayWidthHalf) / ms_overlayWidth) * 512f; + m_cursorShape.Position = new SFML.System.Vector2f(m_cursorPlanePosition.x - 5f, m_cursorPlanePosition.y - 5f); + + if(m_cursorPosition.z <= ms_touchDistance) + { + // Check for axes + if(m_thumbstickShape.GetGlobalBounds().Contains(m_cursorPlanePosition.x, m_cursorPlanePosition.y)) + { + m_thumbstickAxisShape.FillColor = (m_cursorPosition.z <= ms_clickDistance ? ms_axisColorClick : ms_axisColorTouch); + m_thumbstickAxisShape.Position = new SFML.System.Vector2f(m_cursorPlanePosition.x - 7.5f, m_cursorPlanePosition.y - 7.5f); + + GlmSharp.vec2 l_axes = (m_cursorPlanePosition.xy - 145f) / 105f; + l_axes.y *= -1f; + + m_controlButtons[(int)ButtonIndex.Thumbstick].SetState(m_cursorPosition.z <= ms_clickDistance ? ControlButton.ButtonState.Clicked : ControlButton.ButtonState.Touched); + m_controlButtons[(int)ButtonIndex.Thumbstick].SetAxes(l_axes); + } + + if(m_touchpadShape.GetGlobalBounds().Contains(m_cursorPlanePosition.x, m_cursorPlanePosition.y)) + { + m_touchpadAxisShape.FillColor = (m_cursorPosition.z <= ms_clickDistance ? ms_axisColorClick : ms_axisColorTouch); + m_touchpadAxisShape.Position = new SFML.System.Vector2f(m_cursorPlanePosition.x - 7.5f, m_cursorPlanePosition.y - 7.5f); + + GlmSharp.vec2 l_axes = (m_cursorPlanePosition.xy - new GlmSharp.vec2(145f, 375f)) / 105f; + l_axes.y *= -1f; + m_controlButtons[(int)ButtonIndex.Touchpad].SetState(m_cursorPosition.z <= ms_clickDistance ? ControlButton.ButtonState.Clicked : ControlButton.ButtonState.Touched); + m_controlButtons[(int)ButtonIndex.Touchpad].SetAxes(l_axes); + } + + // Check for buttons + if(m_buttonA.GetGlobalBounds().Contains(m_cursorPlanePosition.x, m_cursorPlanePosition.y)) + { + m_buttonA.Color = (m_cursorPosition.z <= ms_clickDistance ? ms_axisColorClick : ms_axisColorTouch); + m_controlButtons[(int)ButtonIndex.A].SetState((m_cursorPosition.z <= ms_clickDistance) ? ControlButton.ButtonState.Clicked : ControlButton.ButtonState.Touched); + } + else + { + m_buttonA.Color = ms_inactiveColor; + m_controlButtons[(int)ButtonIndex.A].SetState(ControlButton.ButtonState.None); + } + + if(m_buttonB.GetGlobalBounds().Contains(m_cursorPlanePosition.x, m_cursorPlanePosition.y)) + { + m_buttonB.Color = (m_cursorPosition.z <= ms_clickDistance ? ms_axisColorClick : ms_axisColorTouch); + m_controlButtons[(int)ButtonIndex.B].SetState((m_cursorPosition.z <= ms_clickDistance) ? ControlButton.ButtonState.Clicked : ControlButton.ButtonState.Touched); + } + else + { + m_buttonB.Color = ms_inactiveColor; + m_controlButtons[(int)ButtonIndex.B].SetState(ControlButton.ButtonState.None); + } + + if(m_buttonSystem.GetGlobalBounds().Contains(m_cursorPlanePosition.x, m_cursorPlanePosition.y)) + { + + m_buttonSystem.Color = (m_cursorPosition.z <= ms_clickDistance ? ms_axisColorClick : ms_axisColorTouch); + m_controlButtons[(int)ButtonIndex.System].SetState((m_cursorPosition.z <= ms_clickDistance) ? ControlButton.ButtonState.Clicked : ControlButton.ButtonState.Touched); + } + else + { + m_buttonSystem.Color = ms_inactiveColor; + m_controlButtons[(int)ButtonIndex.System].SetState(ControlButton.ButtonState.None); + } + } + else + { + m_controlButtons[(int)ButtonIndex.Thumbstick].SetState(ControlButton.ButtonState.None); + m_controlButtons[(int)ButtonIndex.Touchpad].SetState(ControlButton.ButtonState.None); + + m_buttonA.Color = ms_inactiveColor; + m_controlButtons[(int)ButtonIndex.A].SetState(ControlButton.ButtonState.None); + + m_buttonB.Color = ms_inactiveColor; + m_controlButtons[(int)ButtonIndex.B].SetState(ControlButton.ButtonState.None); + + m_buttonSystem.Color = ms_inactiveColor; + m_controlButtons[(int)ButtonIndex.System].SetState(ControlButton.ButtonState.None); + } + + // Presure indicator + float l_presure = 1f - Utils.Clamp(Utils.Clamp(m_cursorPosition.z, 0f, float.MaxValue) / ms_overlayWidthHalf, 0f, 1f); + m_presureFillRectangle.Size = new SFML.System.Vector2f(m_presureFillRectangle.Size.X, -320f * l_presure); + m_presureFillRectangle.FillColor = ((l_presure >= 0.5f) ? ((l_presure >= 0.666667f) ? ms_axisColorClick : ms_axisColorTouch) : ms_activeColor); + + m_inRange = true; + } + else + m_inRange = false; + + // Draw + if(m_renderTexture.SetActive(true)) + { + m_renderTexture.Clear(ms_emptyColor); + m_renderTexture.Draw(m_backgroundSprite); + m_renderTexture.Draw(m_thumbstickShape); + m_renderTexture.Draw(m_touchpadShape); + m_renderTexture.Draw(m_buttonA); + m_renderTexture.Draw(m_buttonB); + m_renderTexture.Draw(m_buttonSystem); + m_renderTexture.Draw(m_presureRectangle); + + if(m_inRange) + { + m_renderTexture.Draw(m_presureFillRectangle); + m_renderTexture.Draw(m_thumbstickAxisShape); + m_renderTexture.Draw(m_touchpadAxisShape); + m_renderTexture.Draw(m_cursorShape); + } + + m_renderTexture.Display(); + m_renderTexture.SetActive(false); + } + + // Update overlay + Valve.VR.OpenVR.Overlay.SetOverlayTexture(m_overlay, ref m_overlayTexture); + } + + public static void LoadResources() + { + ms_resources.Add("background", new SFML.Graphics.Texture(new SFML.Graphics.Image("resources/tx_background.png"))); + ms_resources.Add("circle", new SFML.Graphics.Texture(new SFML.Graphics.Image("resources/tx_circle.png"))); + ms_resources.Add("buttonA", new SFML.Graphics.Texture(new SFML.Graphics.Image("resources/tx_buttonA.png"))); + ms_resources.Add("buttonB", new SFML.Graphics.Texture(new SFML.Graphics.Image("resources/tx_buttonB.png"))); + ms_resources.Add("buttonS", new SFML.Graphics.Texture(new SFML.Graphics.Image("resources/tx_buttonS.png"))); + } + } +} diff --git a/leap_control/Properties/AssemblyInfo.cs b/leap_control/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..a88d655d --- /dev/null +++ b/leap_control/Properties/AssemblyInfo.cs @@ -0,0 +1,5 @@ +using System.Reflection; + +[assembly: AssemblyTitle("Leap Control")] +[assembly: AssemblyVersion("1.3.0")] +[assembly: AssemblyFileVersion("1.3.0")] diff --git a/leap_control/Utils.cs b/leap_control/Utils.cs new file mode 100644 index 00000000..dd5cc402 --- /dev/null +++ b/leap_control/Utils.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace leap_control +{ + static class Utils + { + public static void Convert(this GlmSharp.mat4 f_src, ref Valve.VR.HmdMatrix34_t f_dst) + { + f_dst.m0 = f_src.m00; + f_dst.m1 = f_src.m10; + f_dst.m2 = f_src.m20; + f_dst.m3 = f_src.m30; + + f_dst.m4 = f_src.m01; + f_dst.m5 = f_src.m11; + f_dst.m6 = f_src.m21; + f_dst.m7 = f_src.m31; + + f_dst.m8 = f_src.m02; + f_dst.m9 = f_src.m12; + f_dst.m10 = f_src.m22; + f_dst.m11 = f_src.m32; + } + + public static void Convert(this Valve.VR.HmdMatrix34_t f_src, ref GlmSharp.mat4 f_dst) + { + f_dst.m00 = f_src.m0; + f_dst.m01 = f_src.m4; + f_dst.m02 = f_src.m8; + f_dst.m03 = 0f; + + f_dst.m10 = f_src.m1; + f_dst.m11 = f_src.m5; + f_dst.m12 = f_src.m9; + f_dst.m13 = 0f; + + f_dst.m20 = f_src.m2; + f_dst.m21 = f_src.m6; + f_dst.m22 = f_src.m10; + f_dst.m23 = 0f; + + f_dst.m30 = f_src.m3; + f_dst.m31 = f_src.m7; + f_dst.m32 = f_src.m11; + f_dst.m33 = 1f; + } + + public static void Convert(this Leap.Vector f_src, ref GlmSharp.vec3 f_dst) + { + f_dst.x = f_src.x; + f_dst.y = f_src.y; + f_dst.z = f_src.z; + } + + public static float Clamp(float f_value, float f_min, float f_max) => Math.Min(Math.Max(f_value, f_min), f_max); + + public static bool InRange(float f_value, float f_min, float f_max) + { + return ((f_value >= f_min) && (f_value <= f_max)); + } + public static bool IsInRange(this GlmSharp.vec3 f_vec, float f_min, float f_max) + { + return (InRange(f_vec.x, f_min, f_max) && InRange(f_vec.y, f_min, f_max) && InRange(f_vec.z, f_min, f_max)); + } + } +} diff --git a/leap_control/icon.ico b/leap_control/icon.ico new file mode 100644 index 00000000..eb05ec7c Binary files /dev/null and b/leap_control/icon.ico differ diff --git a/leap_control/leap_control.csproj b/leap_control/leap_control.csproj new file mode 100644 index 00000000..84ac33d5 --- /dev/null +++ b/leap_control/leap_control.csproj @@ -0,0 +1,214 @@ + + + + + Debug + AnyCPU + {B156A0E6-BC15-4987-A1E8-F6D6E69786BC} + Exe + Properties + leap_control + leap_control + v4.7.2 + 512 + + publish\ + true + Disk + false + Foreground + 7 + Days + false + false + true + 0 + 1.0.0.%2a + false + false + true + + + true + ..\bin\win64\ + DEBUG;TRACE + full + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + ..\bin\win64\ + TRACE + true + pdbonly + x64 + prompt + MinimumRecommendedRules.ruleset + true + + + + + + icon.ico + + + + ..\packages\GlmSharp.0.9.8\lib\Net45\GlmSharp.dll + + + ..\packages\SFML.Graphics.2.5.0\lib\netstandard2.0\SFML.Graphics.dll + + + ..\packages\SFML.System.2.5.0\lib\netstandard2.0\SFML.System.dll + + + ..\packages\SFML.Window.2.5.0\lib\netstandard2.0\SFML.Window.dll + + + + + + + + + + + + + + vendor\LeapCSharp\Arm.cs + + + vendor\LeapCSharp\Bone.cs + + + vendor\LeapCSharp\CircularObjectBuffer.cs + + + vendor\LeapCSharp\Config.cs + + + vendor\LeapCSharp\Connection.cs + + + vendor\LeapCSharp\Controller.cs + + + vendor\LeapCSharp\CopyFromLeapCExtensions.cs + + + vendor\LeapCSharp\CopyFromOtherExtensions.cs + + + vendor\LeapCSharp\CSharpExtensions.cs + + + vendor\LeapCSharp\Device.cs + + + vendor\LeapCSharp\DeviceList.cs + + + vendor\LeapCSharp\DistortionData.cs + + + vendor\LeapCSharp\Events.cs + + + vendor\LeapCSharp\FailedDevice.cs + + + vendor\LeapCSharp\FailedDeviceList.cs + + + vendor\LeapCSharp\Finger.cs + + + vendor\LeapCSharp\Frame.cs + + + vendor\LeapCSharp\Hand.cs + + + vendor\LeapCSharp\IController.cs + + + vendor\LeapCSharp\Image.cs + + + vendor\LeapCSharp\ImageData.cs + + + vendor\LeapCSharp\LeapC.cs + + + vendor\LeapCSharp\LeapQuaternion.cs + + + vendor\LeapCSharp\LeapTransform.cs + + + vendor\LeapCSharp\Logger.cs + + + vendor\LeapCSharp\Matrix.cs + + + vendor\LeapCSharp\MemoryManager.cs + + + vendor\LeapCSharp\MessageSeverity.cs + + + vendor\LeapCSharp\PointMapping.cs + + + vendor\LeapCSharp\StructMarshal.cs + + + vendor\LeapCSharp\TransformExtensions.cs + + + vendor\LeapCSharp\Vector.cs + + + vendor\openvr\openvr_api.cs + + + + + + + + + + + + + + + + + + False + .NET Framework 3.5 SP1 Client Profile + false + + + False + .NET Framework 3.5 SP1 + false + + + + + \ No newline at end of file diff --git a/leap_control/packages.config b/leap_control/packages.config new file mode 100644 index 00000000..0961cce1 --- /dev/null +++ b/leap_control/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/leap_control/resources/tx_background.png b/leap_control/resources/tx_background.png new file mode 100644 index 00000000..f72f2dee Binary files /dev/null and b/leap_control/resources/tx_background.png differ diff --git a/leap_control/resources/tx_buttonA.png b/leap_control/resources/tx_buttonA.png new file mode 100644 index 00000000..719b0ee1 Binary files /dev/null and b/leap_control/resources/tx_buttonA.png differ diff --git a/leap_control/resources/tx_buttonB.png b/leap_control/resources/tx_buttonB.png new file mode 100644 index 00000000..09902d8c Binary files /dev/null and b/leap_control/resources/tx_buttonB.png differ diff --git a/leap_control/resources/tx_buttonS.png b/leap_control/resources/tx_buttonS.png new file mode 100644 index 00000000..b86b25ad Binary files /dev/null and b/leap_control/resources/tx_buttonS.png differ diff --git a/leap_control/resources/tx_circle.png b/leap_control/resources/tx_circle.png new file mode 100644 index 00000000..f5b42c26 Binary files /dev/null and b/leap_control/resources/tx_circle.png differ diff --git a/leap_control/resources/tx_cursor.png b/leap_control/resources/tx_cursor.png new file mode 100644 index 00000000..93276b45 Binary files /dev/null and b/leap_control/resources/tx_cursor.png differ diff --git a/resources/icons/base_status_ready.png b/resources/icons/base_status_ready.png new file mode 100644 index 00000000..7d0d785b Binary files /dev/null and b/resources/icons/base_status_ready.png differ diff --git a/resources/icons/base_status_ready@2x.png b/resources/icons/base_status_ready@2x.png new file mode 100644 index 00000000..a416fa09 Binary files /dev/null and b/resources/icons/base_status_ready@2x.png differ diff --git a/resources/icons/base_status_searching.png b/resources/icons/base_status_searching.png new file mode 100644 index 00000000..af5d2b0f Binary files /dev/null and b/resources/icons/base_status_searching.png differ diff --git a/resources/icons/base_status_searching@2x.png b/resources/icons/base_status_searching@2x.png new file mode 100644 index 00000000..11638e18 Binary files /dev/null and b/resources/icons/base_status_searching@2x.png differ diff --git a/resources/rendermodels/leap_motion_1_0/base_diff.png b/resources/rendermodels/leap_motion_1_0/base_diff.png new file mode 100644 index 00000000..f7664b1b Binary files /dev/null and b/resources/rendermodels/leap_motion_1_0/base_diff.png differ diff --git a/resources/rendermodels/leap_motion_1_0/leap_motion_1_0.json b/resources/rendermodels/leap_motion_1_0/leap_motion_1_0.json new file mode 100644 index 00000000..3bc21299 --- /dev/null +++ b/resources/rendermodels/leap_motion_1_0/leap_motion_1_0.json @@ -0,0 +1,12 @@ +{ + "thumbnail" : "thumbnail_leap.png", + "components": { + "body": { + "filename": "leap_motion_1_0.obj", + "component_local" : { + "origin": [0.0, 0.0, 0.0], + "rotate_xyz" : [0.0,0.0,0.0] + } + } + } +} diff --git a/resources/rendermodels/leap_motion_1_0/leap_motion_1_0.mtl b/resources/rendermodels/leap_motion_1_0/leap_motion_1_0.mtl new file mode 100644 index 00000000..faa6d0d0 --- /dev/null +++ b/resources/rendermodels/leap_motion_1_0/leap_motion_1_0.mtl @@ -0,0 +1,10 @@ +# Blender MTL File: 'lmc.blend' +# Material Count: 1 + +newmtl Combined +illum 4 +Kd 0.00 0.00 0.00 +Ka 0.00 0.00 0.00 +Tf 1.00 1.00 1.00 +Ni 1.00 +map_Kd base_diff.png diff --git a/resources/rendermodels/leap_motion_1_0/leap_motion_1_0.obj b/resources/rendermodels/leap_motion_1_0/leap_motion_1_0.obj new file mode 100644 index 00000000..62135b67 --- /dev/null +++ b/resources/rendermodels/leap_motion_1_0/leap_motion_1_0.obj @@ -0,0 +1,1412 @@ +# Blender v2.79 (sub 0) OBJ File: 'lmc.blend' +# www.blender.org +mtllib leap_motion_1_0.mtl +v 0.026018 -0.000719 0.015240 +v 0.026018 -0.001081 0.015240 +v 0.026018 -0.001128 0.015240 +v 0.026018 -0.000672 0.015240 +v 0.026016 -0.000626 0.015240 +v 0.026016 -0.001174 0.015240 +v 0.025999 -0.001261 0.015240 +v 0.026010 -0.000582 0.015240 +v 0.025955 -0.000463 0.015240 +v 0.025981 -0.001300 0.015240 +v 0.026010 -0.001218 0.015240 +v 0.025981 -0.000500 0.015240 +v 0.025999 -0.000539 0.015240 +v 0.021573 -0.001437 0.015240 +v 0.021573 -0.000363 0.015240 +v 0.021670 -0.001448 0.015240 +v 0.021670 -0.000352 0.015240 +v 0.021786 -0.001451 0.015240 +v 0.021786 -0.000349 0.015240 +v 0.025514 -0.001451 0.015240 +v 0.025514 -0.000349 0.015240 +v 0.025630 -0.000352 0.015240 +v 0.025630 -0.001448 0.015240 +v 0.025805 -0.000380 0.015240 +v 0.025727 -0.001437 0.015240 +v 0.025727 -0.000363 0.015240 +v 0.025955 -0.001337 0.015240 +v 0.025805 -0.001420 0.015240 +v 0.025918 -0.000431 0.015240 +v 0.025918 -0.001369 0.015240 +v 0.025869 -0.000403 0.015240 +v 0.025869 -0.001397 0.015240 +v 0.021301 -0.000539 0.015240 +v 0.021495 -0.001420 0.015240 +v 0.021319 -0.000500 0.015240 +v 0.021495 -0.000380 0.015240 +v 0.021431 -0.000403 0.015240 +v 0.021319 -0.001300 0.015240 +v 0.021382 -0.001369 0.015240 +v 0.021284 -0.001174 0.015240 +v 0.021284 -0.000626 0.015240 +v 0.021345 -0.001337 0.015240 +v 0.021301 -0.001261 0.015240 +v 0.021290 -0.001218 0.015240 +v 0.021345 -0.000463 0.015240 +v 0.021282 -0.000672 0.015240 +v 0.021382 -0.000431 0.015240 +v 0.021282 -0.000719 0.015240 +v 0.021282 -0.001081 0.015240 +v 0.021290 -0.000582 0.015240 +v 0.021431 -0.001397 0.015240 +v 0.021282 -0.001128 0.015240 +v -0.038100 -0.006350 -0.005000 +v -0.038095 -0.006350 -0.006295 +v -0.038062 -0.006350 -0.007566 +v -0.037973 -0.006350 -0.008796 +v -0.037800 -0.006350 -0.009969 +v -0.037514 -0.006350 -0.011066 +v -0.037087 -0.006350 -0.012072 +v -0.036492 -0.006350 -0.012970 +v -0.035700 -0.006350 -0.013742 +v -0.034683 -0.006350 -0.014372 +v -0.033412 -0.006350 -0.014843 +v -0.031861 -0.006350 -0.015138 +v -0.030000 -0.006350 -0.015240 +v 0.030000 -0.006350 -0.015240 +v 0.031861 -0.006350 -0.015138 +v 0.033413 -0.006350 -0.014843 +v 0.034683 -0.006350 -0.014372 +v 0.035700 -0.006350 -0.013742 +v 0.036492 -0.006350 -0.012970 +v 0.037088 -0.006350 -0.012072 +v 0.037514 -0.006350 -0.011066 +v 0.037800 -0.006350 -0.009969 +v 0.037973 -0.006350 -0.008796 +v 0.038063 -0.006350 -0.007566 +v 0.038095 -0.006350 -0.006295 +v 0.038100 -0.006350 -0.005000 +v -0.038100 -0.006350 0.005000 +v -0.038095 -0.006350 0.006295 +v -0.038062 -0.006350 0.007566 +v -0.037973 -0.006350 0.008796 +v -0.037800 -0.006350 0.009969 +v -0.037514 -0.006350 0.011066 +v -0.037087 -0.006350 0.012072 +v -0.036492 -0.006350 0.012970 +v -0.035700 -0.006350 0.013742 +v -0.034683 -0.006350 0.014372 +v -0.033412 -0.006350 0.014843 +v -0.031861 -0.006350 0.015138 +v -0.030000 -0.006350 0.015240 +v 0.030000 -0.006350 0.015240 +v 0.031861 -0.006350 0.015138 +v 0.033413 -0.006350 0.014843 +v 0.034683 -0.006350 0.014372 +v 0.035700 -0.006350 0.013742 +v 0.036492 -0.006350 0.012970 +v 0.037088 -0.006350 0.012072 +v 0.037514 -0.006350 0.011066 +v 0.037800 -0.006350 0.009969 +v 0.037973 -0.006350 0.008796 +v 0.038063 -0.006350 0.007566 +v 0.038095 -0.006350 0.006295 +v 0.038100 -0.006350 0.005000 +v -0.038100 0.006350 -0.005000 +v -0.038095 0.006350 -0.006295 +v -0.038062 0.006350 -0.007566 +v -0.037973 0.006350 -0.008796 +v -0.037800 0.006350 -0.009969 +v -0.037514 0.006350 -0.011066 +v -0.037087 0.006350 -0.012072 +v -0.036492 0.006350 -0.012970 +v -0.035700 0.006350 -0.013742 +v -0.034683 0.006350 -0.014372 +v -0.033412 0.006350 -0.014843 +v -0.031861 0.006350 -0.015138 +v -0.030000 0.006350 -0.015240 +v 0.030000 0.006350 -0.015240 +v 0.031861 0.006350 -0.015138 +v 0.033413 0.006350 -0.014843 +v 0.034683 0.006350 -0.014372 +v 0.035700 0.006350 -0.013742 +v 0.036492 0.006350 -0.012970 +v 0.037088 0.006350 -0.012072 +v 0.037514 0.006350 -0.011066 +v 0.037800 0.006350 -0.009969 +v 0.037973 0.006350 -0.008796 +v 0.038063 0.006350 -0.007566 +v 0.038095 0.006350 -0.006295 +v 0.038100 0.006350 -0.005000 +v -0.038100 0.006350 0.005000 +v -0.038095 0.006350 0.006295 +v -0.038062 0.006350 0.007566 +v -0.037973 0.006350 0.008796 +v -0.037800 0.006350 0.009969 +v -0.037514 0.006350 0.011066 +v -0.037087 0.006350 0.012072 +v -0.036492 0.006350 0.012970 +v -0.035700 0.006350 0.013742 +v -0.034683 0.006350 0.014372 +v -0.033412 0.006350 0.014843 +v -0.031861 0.006350 0.015138 +v -0.030000 0.006350 0.015240 +v 0.030000 0.006350 0.015240 +v 0.031861 0.006350 0.015138 +v 0.033413 0.006350 0.014843 +v 0.034683 0.006350 0.014372 +v 0.035700 0.006350 0.013742 +v 0.036492 0.006350 0.012970 +v 0.037088 0.006350 0.012072 +v 0.037514 0.006350 0.011066 +v 0.037800 0.006350 0.009969 +v 0.037973 0.006350 0.008796 +v 0.038063 0.006350 0.007566 +v 0.038095 0.006350 0.006295 +v 0.038100 0.006350 0.005000 +v -0.037350 -0.006350 -0.004999 +v -0.037345 -0.006350 -0.006284 +v -0.037313 -0.006350 -0.007529 +v -0.037228 -0.006350 -0.008714 +v -0.037065 -0.006350 -0.009819 +v -0.036804 -0.006350 -0.010825 +v -0.036427 -0.006350 -0.011717 +v -0.035915 -0.006350 -0.012491 +v -0.035238 -0.006350 -0.013151 +v -0.034353 -0.006350 -0.013698 +v -0.033211 -0.006350 -0.014120 +v -0.031770 -0.006350 -0.014393 +v -0.029979 -0.006350 -0.014490 +v 0.029980 -0.006350 -0.014490 +v 0.031770 -0.006350 -0.014393 +v 0.033211 -0.006350 -0.014120 +v 0.034353 -0.006350 -0.013698 +v 0.035238 -0.006350 -0.013151 +v 0.035915 -0.006350 -0.012491 +v 0.036427 -0.006350 -0.011717 +v 0.036804 -0.006350 -0.010825 +v 0.037065 -0.006350 -0.009819 +v 0.037228 -0.006350 -0.008714 +v 0.037313 -0.006350 -0.007529 +v 0.037345 -0.006350 -0.006284 +v 0.037350 -0.006350 -0.004999 +v -0.037350 -0.006350 0.004999 +v -0.037345 -0.006350 0.006284 +v -0.037313 -0.006350 0.007529 +v -0.037228 -0.006350 0.008714 +v -0.037065 -0.006350 0.009819 +v -0.036804 -0.006350 0.010825 +v -0.036427 -0.006350 0.011717 +v -0.035915 -0.006350 0.012491 +v -0.035238 -0.006350 0.013151 +v -0.034353 -0.006350 0.013698 +v -0.033211 -0.006350 0.014121 +v -0.031770 -0.006350 0.014393 +v -0.029979 -0.006350 0.014490 +v 0.029980 -0.006350 0.014490 +v 0.031770 -0.006350 0.014393 +v 0.033211 -0.006350 0.014121 +v 0.034353 -0.006350 0.013698 +v 0.035238 -0.006350 0.013151 +v 0.035915 -0.006350 0.012491 +v 0.036427 -0.006350 0.011717 +v 0.036804 -0.006350 0.010825 +v 0.037065 -0.006350 0.009819 +v 0.037228 -0.006350 0.008714 +v 0.037313 -0.006350 0.007529 +v 0.037345 -0.006350 0.006284 +v 0.037350 -0.006350 0.004999 +v -0.037350 0.006350 -0.004999 +v -0.037345 0.006350 -0.006284 +v -0.037313 0.006350 -0.007529 +v -0.037228 0.006350 -0.008714 +v -0.037065 0.006350 -0.009819 +v -0.036804 0.006350 -0.010825 +v -0.036427 0.006350 -0.011717 +v -0.035915 0.006350 -0.012491 +v -0.035238 0.006350 -0.013151 +v -0.034353 0.006350 -0.013698 +v -0.033211 0.006350 -0.014120 +v -0.031770 0.006350 -0.014393 +v -0.029979 0.006350 -0.014490 +v 0.029980 0.006350 -0.014490 +v 0.031770 0.006350 -0.014393 +v 0.033211 0.006350 -0.014120 +v 0.034353 0.006350 -0.013698 +v 0.035238 0.006350 -0.013151 +v 0.035915 0.006350 -0.012491 +v 0.036427 0.006350 -0.011717 +v 0.036804 0.006350 -0.010825 +v 0.037065 0.006350 -0.009819 +v 0.037228 0.006350 -0.008714 +v 0.037313 0.006350 -0.007529 +v 0.037345 0.006350 -0.006284 +v 0.037350 0.006350 -0.004999 +v -0.037350 0.006350 0.004999 +v -0.037345 0.006350 0.006284 +v -0.037313 0.006350 0.007529 +v -0.037228 0.006350 0.008714 +v -0.037065 0.006350 0.009819 +v -0.036804 0.006350 0.010825 +v -0.036427 0.006350 0.011717 +v -0.035915 0.006350 0.012491 +v -0.035238 0.006350 0.013151 +v -0.034353 0.006350 0.013698 +v -0.033211 0.006350 0.014121 +v -0.031770 0.006350 0.014393 +v -0.029979 0.006350 0.014490 +v 0.029980 0.006350 0.014490 +v 0.031770 0.006350 0.014393 +v 0.033211 0.006350 0.014121 +v 0.034353 0.006350 0.013698 +v 0.035238 0.006350 0.013151 +v 0.035915 0.006350 0.012491 +v 0.036427 0.006350 0.011717 +v 0.036804 0.006350 0.010825 +v 0.037065 0.006350 0.009819 +v 0.037228 0.006350 0.008714 +v 0.037313 0.006350 0.007529 +v 0.037345 0.006350 0.006284 +v 0.037350 0.006350 0.004999 +v -0.037350 -0.006350 -0.004999 +v -0.037345 -0.006350 -0.006284 +v -0.037313 -0.006350 -0.007529 +v -0.037228 -0.006350 -0.008714 +v -0.037065 -0.006350 -0.009819 +v -0.036804 -0.006350 -0.010825 +v -0.036427 -0.006350 -0.011717 +v -0.035915 -0.006350 -0.012491 +v -0.035238 -0.006350 -0.013151 +v -0.034353 -0.006350 -0.013698 +v -0.033211 -0.006350 -0.014120 +v -0.031770 -0.006350 -0.014393 +v -0.029979 -0.006350 -0.014490 +v 0.029980 -0.006350 -0.014490 +v 0.031770 -0.006350 -0.014393 +v 0.033211 -0.006350 -0.014120 +v 0.034353 -0.006350 -0.013698 +v 0.035238 -0.006350 -0.013151 +v 0.035915 -0.006350 -0.012491 +v 0.036427 -0.006350 -0.011717 +v 0.036804 -0.006350 -0.010825 +v 0.037065 -0.006350 -0.009819 +v 0.037228 -0.006350 -0.008714 +v 0.037313 -0.006350 -0.007529 +v 0.037345 -0.006350 -0.006284 +v 0.037350 -0.006350 -0.004999 +v -0.037350 -0.006350 0.004999 +v -0.037345 -0.006350 0.006284 +v -0.037313 -0.006350 0.007529 +v -0.037228 -0.006350 0.008714 +v -0.037065 -0.006350 0.009819 +v -0.036804 -0.006350 0.010825 +v -0.036427 -0.006350 0.011717 +v -0.035915 -0.006350 0.012491 +v -0.035238 -0.006350 0.013151 +v -0.034353 -0.006350 0.013698 +v -0.033211 -0.006350 0.014121 +v -0.031770 -0.006350 0.014393 +v -0.029979 -0.006350 0.014490 +v 0.029980 -0.006350 0.014490 +v 0.031770 -0.006350 0.014393 +v 0.033211 -0.006350 0.014121 +v 0.034353 -0.006350 0.013698 +v 0.035238 -0.006350 0.013151 +v 0.035915 -0.006350 0.012491 +v 0.036427 -0.006350 0.011717 +v 0.036804 -0.006350 0.010825 +v 0.037065 -0.006350 0.009819 +v 0.037228 -0.006350 0.008714 +v 0.037313 -0.006350 0.007529 +v 0.037345 -0.006350 0.006284 +v 0.037350 -0.006350 0.004999 +v 0.037350 0.006350 0.004999 +v 0.037345 0.006350 0.006284 +v 0.037313 0.006350 0.007529 +v 0.037228 0.006350 0.008714 +v 0.037065 0.006350 0.009819 +v 0.036804 0.006350 0.010825 +v 0.036427 0.006350 0.011717 +v 0.035915 0.006350 0.012491 +v 0.035238 0.006350 0.013151 +v 0.034353 0.006350 0.013698 +v 0.033211 0.006350 0.014121 +v 0.031770 0.006350 0.014393 +v 0.029980 0.006350 0.014490 +v -0.029979 0.006350 0.014490 +v -0.031770 0.006350 0.014393 +v -0.033211 0.006350 0.014121 +v -0.034353 0.006350 0.013698 +v -0.035238 0.006350 0.013151 +v -0.035915 0.006350 0.012491 +v -0.036427 0.006350 0.011717 +v -0.036804 0.006350 0.010825 +v -0.037065 0.006350 0.009819 +v -0.037228 0.006350 0.008714 +v -0.037313 0.006350 0.007529 +v -0.037345 0.006350 0.006284 +v -0.037350 0.006350 0.004999 +v 0.037350 0.006350 -0.004999 +v 0.037345 0.006350 -0.006284 +v 0.037313 0.006350 -0.007529 +v 0.037228 0.006350 -0.008714 +v 0.037065 0.006350 -0.009819 +v 0.036804 0.006350 -0.010825 +v 0.036427 0.006350 -0.011717 +v 0.035915 0.006350 -0.012491 +v 0.035238 0.006350 -0.013151 +v 0.034353 0.006350 -0.013698 +v 0.033211 0.006350 -0.014120 +v 0.031770 0.006350 -0.014393 +v 0.029980 0.006350 -0.014490 +v -0.029979 0.006350 -0.014490 +v -0.031770 0.006350 -0.014393 +v -0.033211 0.006350 -0.014120 +v -0.034353 0.006350 -0.013698 +v -0.035238 0.006350 -0.013151 +v -0.035915 0.006350 -0.012491 +v -0.036427 0.006350 -0.011717 +v -0.036804 0.006350 -0.010825 +v -0.037065 0.006350 -0.009819 +v -0.037228 0.006350 -0.008714 +v -0.037313 0.006350 -0.007529 +v -0.037345 0.006350 -0.006284 +v -0.037350 0.006350 -0.004999 +v 0.021282 -0.001128 0.015240 +v 0.021431 -0.001397 0.015240 +v 0.021290 -0.000582 0.015240 +v 0.021282 -0.001081 0.015240 +v 0.021282 -0.000719 0.015240 +v 0.021382 -0.000431 0.015240 +v 0.021282 -0.000672 0.015240 +v 0.021345 -0.000463 0.015240 +v 0.021290 -0.001218 0.015240 +v 0.021301 -0.001261 0.015240 +v 0.021345 -0.001337 0.015240 +v 0.021284 -0.000626 0.015240 +v 0.021284 -0.001174 0.015240 +v 0.021382 -0.001369 0.015240 +v 0.021319 -0.001300 0.015240 +v 0.021431 -0.000403 0.015240 +v 0.021495 -0.000380 0.015240 +v 0.021319 -0.000500 0.015240 +v 0.021495 -0.001420 0.015240 +v 0.021301 -0.000539 0.015240 +v 0.025869 -0.001397 0.015240 +v 0.025869 -0.000403 0.015240 +v 0.025918 -0.001369 0.015240 +v 0.025918 -0.000431 0.015240 +v 0.025805 -0.001420 0.015240 +v 0.025955 -0.001337 0.015240 +v 0.025727 -0.000363 0.015240 +v 0.025727 -0.001437 0.015240 +v 0.025805 -0.000380 0.015240 +v 0.025630 -0.001448 0.015240 +v 0.025630 -0.000352 0.015240 +v 0.025514 -0.000349 0.015240 +v 0.025514 -0.001451 0.015240 +v 0.021786 -0.000349 0.015240 +v 0.021786 -0.001451 0.015240 +v 0.021670 -0.000352 0.015240 +v 0.021670 -0.001448 0.015240 +v 0.021573 -0.000363 0.015240 +v 0.021573 -0.001437 0.015240 +v 0.025999 -0.000539 0.015240 +v 0.025981 -0.000500 0.015240 +v 0.026010 -0.001218 0.015240 +v 0.025981 -0.001300 0.015240 +v 0.025955 -0.000463 0.015240 +v 0.026010 -0.000582 0.015240 +v 0.025999 -0.001261 0.015240 +v 0.026016 -0.001174 0.015240 +v 0.026016 -0.000626 0.015240 +v 0.026018 -0.000672 0.015240 +v 0.026018 -0.001128 0.015240 +v 0.026018 -0.001081 0.015240 +v 0.026018 -0.000719 0.015240 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.750000 0.750000 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.250000 0.750000 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vt 0.500001 0.249994 +vn 0.0000 0.0000 1.0000 +vn 0.9892 0.0000 -0.1463 +vn -0.9974 0.0000 -0.0722 +vn 0.9997 0.0000 0.0258 +vn -1.0000 0.0000 -0.0036 +vn 0.9892 0.0000 0.1463 +vn -1.0000 0.0000 0.0036 +vn -0.8334 0.0000 -0.5527 +vn -0.9677 0.0000 -0.2521 +vn -0.9677 0.0000 0.2521 +vn -0.9974 0.0000 0.0722 +vn -0.1867 0.0000 -0.9824 +vn -0.5266 0.0000 -0.8501 +vn -0.5266 0.0000 0.8501 +vn -0.8334 0.0000 0.5527 +vn 0.1867 0.0000 -0.9824 +vn -0.1867 0.0000 0.9824 +vn 0.8334 0.0000 -0.5527 +vn 0.5266 0.0000 -0.8501 +vn 0.5266 0.0000 0.8501 +vn 0.1867 0.0000 0.9824 +vn 0.9974 0.0000 -0.0722 +vn 0.9677 0.0000 -0.2521 +vn 0.9677 0.0000 0.2521 +vn 0.8334 0.0000 0.5527 +vn 0.0000 0.0000 -1.0000 +vn 1.0000 0.0000 -0.0036 +vn -0.9892 0.0000 -0.1464 +vn 1.0000 0.0000 0.0036 +vn -0.9997 0.0000 -0.0258 +vn 0.9974 0.0000 0.0722 +vn -0.9892 0.0000 0.1464 +vn -0.9997 0.0000 0.0258 +vn -0.6980 0.0000 -0.7161 +vn -0.9207 0.0000 -0.3904 +vn -1.0000 0.0000 0.0000 +vn -0.6980 0.0000 0.7161 +vn -0.9207 0.0000 0.3904 +vn -0.0548 0.0000 -0.9985 +vn -0.3476 0.0000 -0.9376 +vn -0.0548 0.0000 0.9985 +vn -0.3476 0.0000 0.9376 +vn 0.3476 0.0000 -0.9376 +vn 0.0548 0.0000 -0.9985 +vn 0.3476 0.0000 0.9376 +vn 0.0548 0.0000 0.9985 +vn 0.9207 0.0000 -0.3904 +vn 0.6980 0.0000 -0.7161 +vn 0.9207 0.0000 0.3904 +vn 0.6980 0.0000 0.7161 +vn 0.9997 0.0000 -0.0258 +vn 1.0000 0.0000 0.0000 +vn 0.0000 -1.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn -0.0001 0.0000 1.0000 +vn 0.0001 0.0000 1.0000 +vn -0.0002 0.0000 1.0000 +vn 0.0002 0.0000 1.0000 +vn -0.0003 0.0000 1.0000 +usemtl Combined +s off +f 19/1/1 48/2/1 18/3/1 +f 74/4/2 127/5/2 75/6/2 +f 107/7/3 56/8/3 55/9/3 +f 155/10/4 102/11/4 103/12/4 +f 105/13/5 54/14/5 53/15/5 +f 153/16/6 100/17/6 101/18/6 +f 80/19/7 131/20/7 79/21/7 +f 111/22/8 60/23/8 59/24/8 +f 109/25/9 58/26/9 57/27/9 +f 398/28/1 396/29/1 144/30/1 +f 84/31/10 135/32/10 83/33/10 +f 82/34/11 133/35/11 81/36/11 +f 115/37/12 64/38/12 63/39/12 +f 113/40/13 62/41/13 61/42/13 +f 88/43/14 139/44/14 87/45/14 +f 86/46/15 137/47/15 85/48/15 +f 67/49/16 120/50/16 68/51/16 +f 90/52/17 141/53/17 89/54/17 +f 71/55/18 124/56/18 72/57/18 +f 69/58/19 122/59/19 70/60/19 +f 148/61/20 95/62/20 96/63/20 +f 146/64/21 93/65/21 94/66/21 +f 75/6/22 128/67/22 76/68/22 +f 73/69/23 126/70/23 74/4/23 +f 152/71/24 99/72/24 100/17/24 +f 150/73/25 97/74/25 98/75/25 +f 65/76/26 118/77/26 66/78/26 +f 77/79/27 130/80/27 78/81/27 +f 108/82/28 57/27/28 56/8/28 +f 156/83/29 103/12/29 104/84/29 +f 106/85/30 55/9/30 54/14/30 +f 154/86/31 101/18/31 102/11/31 +f 83/33/32 134/87/32 82/34/32 +f 81/36/33 132/88/33 80/19/33 +f 112/89/34 61/42/34 60/23/34 +f 110/90/35 59/24/35 58/26/35 +f 131/20/36 53/15/36 79/21/36 +f 87/45/37 138/91/37 86/46/37 +f 85/48/38 136/92/38 84/31/38 +f 116/93/39 65/76/39 64/38/39 +f 114/94/40 63/39/40 62/41/40 +f 91/95/41 142/96/41 90/52/41 +f 89/54/42 140/97/42 88/43/42 +f 68/51/43 121/98/43 69/58/43 +f 66/78/44 119/99/44 67/49/44 +f 147/100/45 94/66/45 95/62/45 +f 145/101/46 92/102/46 93/65/46 +f 72/57/47 125/103/47 73/69/47 +f 70/60/48 123/104/48 71/55/48 +f 151/105/49 98/75/49 99/72/49 +f 149/106/50 96/63/50 97/74/50 +f 76/68/51 129/107/51 77/79/51 +f 156/83/52 78/81/52 130/80/52 +f 158/108/53 53/15/53 54/14/53 +f 159/109/53 54/14/53 55/9/53 +f 160/110/53 55/9/53 56/8/53 +f 161/111/53 56/8/53 57/27/53 +f 162/112/53 57/27/53 58/26/53 +f 163/113/53 58/26/53 59/24/53 +f 164/114/53 59/24/53 60/23/53 +f 165/115/53 60/23/53 61/42/53 +f 62/41/53 165/115/53 61/42/53 +f 63/39/53 166/116/53 62/41/53 +f 64/38/53 167/117/53 63/39/53 +f 65/76/53 168/118/53 64/38/53 +f 170/119/53 65/76/53 66/78/53 +f 66/78/53 171/120/53 170/119/53 +f 67/49/53 172/121/53 171/120/53 +f 68/51/53 173/122/53 172/121/53 +f 69/58/53 174/123/53 173/122/53 +f 71/55/53 174/123/53 70/60/53 +f 72/57/53 175/124/53 71/55/53 +f 73/69/53 176/125/53 72/57/53 +f 74/4/53 177/126/53 73/69/53 +f 75/6/53 178/127/53 74/4/53 +f 76/68/53 179/128/53 75/6/53 +f 77/79/53 180/129/53 76/68/53 +f 78/81/53 181/130/53 77/79/53 +f 208/131/53 78/81/53 104/84/53 +f 207/132/53 104/84/53 103/12/53 +f 206/133/53 103/12/53 102/11/53 +f 110/90/54 215/134/54 111/22/54 +f 233/135/54 130/80/54 129/107/54 +f 205/136/53 102/11/53 101/18/53 +f 155/10/54 258/137/54 154/86/54 +f 203/138/53 100/17/53 99/72/53 +f 53/15/53 183/139/53 79/21/53 +f 119/99/54 224/140/54 120/50/54 +f 229/141/54 126/70/54 125/103/54 +f 231/142/54 128/67/54 127/5/54 +f 156/83/54 259/143/54 155/10/54 +f 82/34/53 187/144/53 83/33/53 +f 80/19/53 185/145/53 81/36/53 +f 121/98/54 226/146/54 122/59/54 +f 227/147/54 124/56/54 123/104/54 +f 86/46/53 191/148/53 87/45/53 +f 84/31/53 189/149/53 85/48/53 +f 117/150/54 222/151/54 118/77/54 +f 91/95/53 194/152/53 195/153/53 +f 89/54/53 192/154/53 193/155/53 +f 114/94/54 217/156/54 218/157/54 +f 116/93/54 219/158/54 220/159/54 +f 106/85/54 211/160/54 107/7/54 +f 94/66/53 199/161/53 95/62/53 +f 92/102/53 197/162/53 93/65/53 +f 109/25/54 214/163/54 110/90/54 +f 111/22/54 216/164/54 112/89/54 +f 202/165/53 99/72/53 98/75/53 +f 200/166/53 97/74/53 96/63/53 +f 105/13/54 210/167/54 106/85/54 +f 107/7/54 212/168/54 108/82/54 +f 232/169/54 129/107/54 128/67/54 +f 130/80/54 260/170/54 156/83/54 +f 204/171/53 101/18/53 100/17/53 +f 81/36/53 186/172/53 82/34/53 +f 79/21/53 184/173/53 80/19/53 +f 228/174/54 125/103/54 124/56/54 +f 230/175/54 127/5/54 126/70/54 +f 85/48/53 190/176/53 86/46/53 +f 83/33/53 188/177/53 84/31/53 +f 120/50/54 225/178/54 121/98/54 +f 226/146/54 123/104/54 122/59/54 +f 90/52/53 193/155/53 194/152/53 +f 88/43/53 191/148/53 192/154/53 +f 117/150/54 220/159/54 221/179/54 +f 118/77/54 223/180/54 119/99/54 +f 93/65/53 198/181/53 94/66/53 +f 195/153/53 92/102/53 91/95/53 +f 112/89/54 217/156/54 113/40/54 +f 115/37/54 218/157/54 219/158/54 +f 201/182/53 98/75/53 97/74/53 +f 95/62/53 200/166/53 96/63/53 +f 108/82/54 213/183/54 109/25/54 +f 154/86/54 257/184/54 153/16/54 +f 153/16/54 256/185/54 152/71/54 +f 152/71/54 255/186/54 151/105/54 +f 151/105/54 254/187/54 150/73/54 +f 150/73/54 253/188/54 149/106/54 +f 149/106/54 252/189/54 148/61/54 +f 147/100/54 252/189/54 251/190/54 +f 146/64/54 251/190/54 250/191/54 +f 145/101/54 250/191/54 249/192/54 +f 144/30/54 249/192/54 248/193/54 +f 144/30/54 247/194/54 143/195/54 +f 143/195/54 246/196/54 142/96/54 +f 142/96/54 245/197/54 141/53/54 +f 141/53/54 244/198/54 140/97/54 +f 140/97/54 243/199/54 139/44/54 +f 243/199/54 138/91/54 139/44/54 +f 242/200/54 137/47/54 138/91/54 +f 241/201/54 136/92/54 137/47/54 +f 240/202/54 135/32/54 136/92/54 +f 239/203/54 134/87/54 135/32/54 +f 238/204/54 133/35/54 134/87/54 +f 237/205/54 132/88/54 133/35/54 +f 236/206/54 131/20/54 132/88/54 +f 235/207/54 105/13/54 131/20/54 +f 339/208/54 351/209/54 325/210/54 +f 274/211/54 300/212/54 312/213/54 +f 92/102/1 397/214/1 399/215/1 +f 2/216/1 1/217/1 21/218/1 +f 1/217/1 4/219/1 26/220/1 +f 22/221/1 1/217/1 26/220/1 +f 4/219/1 5/222/1 24/223/1 +f 5/222/55 8/224/55 31/225/55 +f 24/223/1 5/222/1 31/225/1 +f 8/224/1 13/226/1 29/227/1 +f 13/226/1 12/228/1 29/227/1 +f 12/228/1 9/229/1 29/227/1 +f 29/227/1 31/225/1 8/224/1 +f 24/223/1 26/220/1 4/219/1 +f 22/221/1 21/218/1 1/217/1 +f 21/218/1 19/1/1 20/230/1 +f 19/1/1 17/231/1 48/2/1 +f 17/231/1 15/232/1 48/2/1 +f 48/2/1 15/232/1 46/233/1 +f 15/232/1 36/234/1 46/233/1 +f 36/234/1 37/235/1 41/236/1 +f 37/235/1 47/237/1 50/238/1 +f 47/237/1 45/239/1 33/240/1 +f 45/239/1 35/241/1 33/240/1 +f 33/240/1 50/238/1 47/237/1 +f 50/238/56 41/236/56 37/235/56 +f 41/236/56 46/233/56 36/234/56 +f 48/2/1 49/242/1 18/3/1 +f 49/242/1 52/243/1 14/244/1 +f 16/245/1 49/242/1 14/244/1 +f 52/243/1 40/246/1 34/247/1 +f 40/246/1 44/248/1 51/249/1 +f 34/247/1 40/246/1 51/249/1 +f 44/248/56 43/250/56 39/251/56 +f 43/250/57 38/252/57 39/251/57 +f 38/252/58 42/253/58 39/251/58 +f 39/251/55 51/249/55 44/248/55 +f 34/247/1 14/244/1 52/243/1 +f 16/245/1 18/3/1 49/242/1 +f 18/3/1 20/230/1 19/1/1 +f 20/230/1 23/254/1 2/216/1 +f 23/254/1 25/255/1 2/216/1 +f 25/255/1 28/256/1 3/257/1 +f 28/256/1 32/258/1 6/259/1 +f 32/258/56 30/260/56 11/261/56 +f 30/260/58 27/262/58 7/263/58 +f 27/262/59 10/264/59 7/263/59 +f 7/263/1 11/261/1 30/260/1 +f 11/261/1 6/259/1 32/258/1 +f 6/259/55 3/257/55 28/256/55 +f 3/257/1 2/216/1 25/255/1 +f 21/218/1 20/230/1 2/216/1 +f 74/4/2 126/70/2 127/5/2 +f 107/7/3 108/82/3 56/8/3 +f 155/10/4 154/86/4 102/11/4 +f 105/13/5 106/85/5 54/14/5 +f 153/16/6 152/71/6 100/17/6 +f 80/19/7 132/88/7 131/20/7 +f 111/22/8 112/89/8 60/23/8 +f 109/25/9 110/90/9 58/26/9 +f 144/30/1 143/195/1 370/265/1 +f 143/195/1 91/95/1 371/266/1 +f 370/265/1 143/195/1 372/267/1 +f 91/95/1 368/268/1 369/269/1 +f 91/95/1 369/269/1 371/266/1 +f 416/270/56 92/102/56 413/271/56 +f 92/102/1 144/30/1 412/272/1 +f 413/271/1 92/102/1 412/272/1 +f 371/266/1 376/273/1 143/195/1 +f 376/273/1 367/274/1 143/195/1 +f 409/275/1 412/272/1 144/30/1 +f 367/274/1 384/276/1 143/195/1 +f 384/276/1 382/277/1 143/195/1 +f 404/278/1 409/275/1 144/30/1 +f 405/279/55 404/278/55 144/30/55 +f 382/277/1 372/267/1 143/195/1 +f 408/280/1 405/279/1 144/30/1 +f 388/281/1 408/280/1 144/30/1 +f 144/30/1 370/265/1 380/282/1 +f 386/283/1 388/281/1 144/30/1 +f 393/284/1 386/283/1 144/30/1 +f 144/30/1 380/282/1 381/285/1 +f 144/30/1 381/285/1 402/286/1 +f 391/287/1 393/284/1 144/30/1 +f 395/288/1 391/287/1 144/30/1 +f 144/30/1 402/286/1 400/289/1 +f 144/30/1 400/289/1 398/28/1 +f 396/29/1 395/288/1 144/30/1 +f 84/31/10 136/92/10 135/32/10 +f 82/34/11 134/87/11 133/35/11 +f 115/37/12 116/93/12 64/38/12 +f 113/40/13 114/94/13 62/41/13 +f 88/43/14 140/97/14 139/44/14 +f 86/46/15 138/91/15 137/47/15 +f 67/49/16 119/99/16 120/50/16 +f 90/52/17 142/96/17 141/53/17 +f 71/55/18 123/104/18 124/56/18 +f 69/58/19 121/98/19 122/59/19 +f 148/61/20 147/100/20 95/62/20 +f 146/64/21 145/101/21 93/65/21 +f 75/6/22 127/5/22 128/67/22 +f 73/69/23 125/103/23 126/70/23 +f 152/71/24 151/105/24 99/72/24 +f 150/73/25 149/106/25 97/74/25 +f 65/76/26 117/150/26 118/77/26 +f 77/79/27 129/107/27 130/80/27 +f 108/82/28 109/25/28 57/27/28 +f 156/83/29 155/10/29 103/12/29 +f 106/85/30 107/7/30 55/9/30 +f 154/86/31 153/16/31 101/18/31 +f 83/33/32 135/32/32 134/87/32 +f 81/36/33 133/35/33 132/88/33 +f 112/89/34 113/40/34 61/42/34 +f 110/90/35 111/22/35 59/24/35 +f 131/20/36 105/13/36 53/15/36 +f 87/45/37 139/44/37 138/91/37 +f 85/48/38 137/47/38 136/92/38 +f 116/93/39 117/150/39 65/76/39 +f 114/94/40 115/37/40 63/39/40 +f 91/95/41 143/195/41 142/96/41 +f 89/54/42 141/53/42 140/97/42 +f 68/51/43 120/50/43 121/98/43 +f 66/78/44 118/77/44 119/99/44 +f 147/100/45 146/64/45 94/66/45 +f 145/101/46 144/30/46 92/102/46 +f 72/57/47 124/56/47 125/103/47 +f 70/60/48 122/59/48 123/104/48 +f 151/105/49 150/73/49 98/75/49 +f 149/106/50 148/61/50 96/63/50 +f 76/68/51 128/67/51 129/107/51 +f 156/83/52 104/84/52 78/81/52 +f 158/108/53 157/290/53 53/15/53 +f 159/109/53 158/108/53 54/14/53 +f 160/110/53 159/109/53 55/9/53 +f 161/111/53 160/110/53 56/8/53 +f 162/112/53 161/111/53 57/27/53 +f 163/113/53 162/112/53 58/26/53 +f 164/114/53 163/113/53 59/24/53 +f 165/115/53 164/114/53 60/23/53 +f 62/41/53 166/116/53 165/115/53 +f 63/39/53 167/117/53 166/116/53 +f 64/38/53 168/118/53 167/117/53 +f 65/76/53 169/291/53 168/118/53 +f 170/119/53 169/291/53 65/76/53 +f 66/78/53 67/49/53 171/120/53 +f 67/49/53 68/51/53 172/121/53 +f 68/51/53 69/58/53 173/122/53 +f 69/58/53 70/60/53 174/123/53 +f 71/55/53 175/124/53 174/123/53 +f 72/57/53 176/125/53 175/124/53 +f 73/69/53 177/126/53 176/125/53 +f 74/4/53 178/127/53 177/126/53 +f 75/6/53 179/128/53 178/127/53 +f 76/68/53 180/129/53 179/128/53 +f 77/79/53 181/130/53 180/129/53 +f 78/81/53 182/292/53 181/130/53 +f 208/131/53 182/292/53 78/81/53 +f 207/132/53 208/131/53 104/84/53 +f 206/133/53 207/132/53 103/12/53 +f 110/90/54 214/163/54 215/134/54 +f 233/135/54 234/293/54 130/80/54 +f 205/136/53 206/133/53 102/11/53 +f 155/10/54 259/143/54 258/137/54 +f 203/138/53 204/171/53 100/17/53 +f 53/15/53 157/290/53 183/139/53 +f 119/99/54 223/180/54 224/140/54 +f 229/141/54 230/175/54 126/70/54 +f 231/142/54 232/169/54 128/67/54 +f 156/83/54 260/170/54 259/143/54 +f 82/34/53 186/172/53 187/144/53 +f 80/19/53 184/173/53 185/145/53 +f 121/98/54 225/178/54 226/146/54 +f 227/147/54 228/174/54 124/56/54 +f 86/46/53 190/176/53 191/148/53 +f 84/31/53 188/177/53 189/149/53 +f 117/150/54 221/179/54 222/151/54 +f 91/95/53 90/52/53 194/152/53 +f 89/54/53 88/43/53 192/154/53 +f 114/94/54 113/40/54 217/156/54 +f 116/93/54 115/37/54 219/158/54 +f 106/85/54 210/167/54 211/160/54 +f 94/66/53 198/181/53 199/161/53 +f 92/102/53 196/294/53 197/162/53 +f 109/25/54 213/183/54 214/163/54 +f 111/22/54 215/134/54 216/164/54 +f 202/165/53 203/138/53 99/72/53 +f 200/166/53 201/182/53 97/74/53 +f 105/13/54 209/295/54 210/167/54 +f 107/7/54 211/160/54 212/168/54 +f 232/169/54 233/135/54 129/107/54 +f 130/80/54 234/293/54 260/170/54 +f 204/171/53 205/136/53 101/18/53 +f 81/36/53 185/145/53 186/172/53 +f 79/21/53 183/139/53 184/173/53 +f 228/174/54 229/141/54 125/103/54 +f 230/175/54 231/142/54 127/5/54 +f 85/48/53 189/149/53 190/176/53 +f 83/33/53 187/144/53 188/177/53 +f 120/50/54 224/140/54 225/178/54 +f 226/146/54 227/147/54 123/104/54 +f 90/52/53 89/54/53 193/155/53 +f 88/43/53 87/45/53 191/148/53 +f 117/150/54 116/93/54 220/159/54 +f 118/77/54 222/151/54 223/180/54 +f 93/65/53 197/162/53 198/181/53 +f 195/153/53 196/294/53 92/102/53 +f 112/89/54 216/164/54 217/156/54 +f 115/37/54 114/94/54 218/157/54 +f 201/182/53 202/165/53 98/75/53 +f 95/62/53 199/161/53 200/166/53 +f 108/82/54 212/168/54 213/183/54 +f 154/86/54 258/137/54 257/184/54 +f 153/16/54 257/184/54 256/185/54 +f 152/71/54 256/185/54 255/186/54 +f 151/105/54 255/186/54 254/187/54 +f 150/73/54 254/187/54 253/188/54 +f 149/106/54 253/188/54 252/189/54 +f 147/100/54 148/61/54 252/189/54 +f 146/64/54 147/100/54 251/190/54 +f 145/101/54 146/64/54 250/191/54 +f 144/30/54 145/101/54 249/192/54 +f 144/30/54 248/193/54 247/194/54 +f 143/195/54 247/194/54 246/196/54 +f 142/96/54 246/196/54 245/197/54 +f 141/53/54 245/197/54 244/198/54 +f 140/97/54 244/198/54 243/199/54 +f 243/199/54 242/200/54 138/91/54 +f 242/200/54 241/201/54 137/47/54 +f 241/201/54 240/202/54 136/92/54 +f 240/202/54 239/203/54 135/32/54 +f 239/203/54 238/204/54 134/87/54 +f 238/204/54 237/205/54 133/35/54 +f 237/205/54 236/206/54 132/88/54 +f 236/206/54 235/207/54 131/20/54 +f 235/207/54 209/295/54 105/13/54 +f 326/296/54 325/210/54 351/209/54 +f 325/210/54 324/297/54 316/298/54 +f 351/209/54 339/208/54 340/299/54 +f 324/297/54 323/300/54 317/301/54 +f 323/300/54 322/302/54 318/303/54 +f 322/302/54 321/304/54 319/305/54 +f 321/304/54 320/306/54 319/305/54 +f 319/305/54 318/303/54 322/302/54 +f 318/303/54 317/301/54 323/300/54 +f 317/301/54 316/298/54 324/297/54 +f 316/298/54 315/307/54 325/210/54 +f 315/307/54 314/308/54 325/210/54 +f 314/308/54 313/309/54 325/210/54 +f 313/309/54 339/208/54 325/210/54 +f 340/299/54 341/310/54 351/209/54 +f 341/310/54 342/311/54 351/209/54 +f 342/311/54 343/312/54 350/313/54 +f 350/313/54 343/312/54 349/314/54 +f 343/312/54 344/315/54 349/314/54 +f 344/315/54 345/316/54 348/317/54 +f 349/314/54 344/315/54 348/317/54 +f 345/316/54 346/318/54 347/319/54 +f 347/319/54 348/317/54 345/316/54 +f 350/313/54 351/209/54 342/311/54 +f 351/209/54 352/320/54 326/296/54 +f 352/320/54 353/321/54 361/322/54 +f 326/296/54 352/320/54 338/323/54 +f 353/321/54 354/324/54 360/325/54 +f 354/324/54 355/326/54 359/327/54 +f 355/326/54 356/328/54 358/329/54 +f 356/328/54 357/330/54 358/329/54 +f 358/329/54 359/327/54 355/326/54 +f 359/327/54 360/325/54 354/324/54 +f 360/325/54 361/322/54 353/321/54 +f 361/322/54 362/331/54 352/320/54 +f 362/331/54 363/332/54 352/320/54 +f 363/332/54 364/333/54 352/320/54 +f 364/333/54 338/323/54 352/320/54 +f 338/323/54 337/334/54 326/296/54 +f 337/334/54 336/335/54 326/296/54 +f 336/335/54 335/336/54 326/296/54 +f 335/336/54 334/337/54 327/338/54 +f 326/296/54 335/336/54 327/338/54 +f 334/337/54 333/339/54 328/340/54 +f 333/339/54 332/341/54 329/342/54 +f 329/342/54 332/341/54 330/343/54 +f 332/341/54 331/344/54 330/343/54 +f 329/342/54 328/340/54 333/339/54 +f 328/340/54 327/338/54 334/337/54 +f 263/345/54 262/346/54 273/347/54 +f 262/346/54 261/348/54 273/347/54 +f 261/348/54 287/349/54 299/350/54 +f 287/349/54 288/351/54 299/350/54 +f 288/351/54 289/352/54 299/350/54 +f 289/352/54 290/353/54 299/350/54 +f 299/350/54 290/353/54 298/354/54 +f 290/353/54 291/355/54 298/354/54 +f 291/355/54 292/356/54 297/357/54 +f 297/357/54 292/356/54 296/358/54 +f 292/356/54 293/359/54 296/358/54 +f 293/359/54 294/360/54 295/361/54 +f 296/358/54 293/359/54 295/361/54 +f 297/357/54 298/354/54 291/355/54 +f 299/350/54 300/212/54 273/347/54 +f 300/212/54 301/362/54 309/363/54 +f 301/362/54 302/364/54 308/365/54 +f 302/364/54 303/366/54 307/367/54 +f 303/366/54 304/368/54 306/369/54 +f 307/367/54 303/366/54 306/369/54 +f 304/368/54 305/370/54 306/369/54 +f 307/367/54 308/365/54 302/364/54 +f 308/365/54 309/363/54 301/362/54 +f 309/363/54 310/371/54 300/212/54 +f 310/371/54 311/372/54 300/212/54 +f 311/372/54 312/213/54 300/212/54 +f 312/213/54 286/373/54 274/211/54 +f 286/373/54 285/374/54 274/211/54 +f 285/374/54 284/375/54 274/211/54 +f 284/375/54 283/376/54 274/211/54 +f 274/211/54 283/376/54 275/377/54 +f 283/376/54 282/378/54 275/377/54 +f 282/378/54 281/379/54 276/380/54 +f 275/377/54 282/378/54 276/380/54 +f 281/379/54 280/381/54 277/382/54 +f 280/381/54 279/383/54 278/384/54 +f 277/382/54 280/381/54 278/384/54 +f 277/382/54 276/380/54 281/379/54 +f 274/211/54 273/347/54 300/212/54 +f 273/347/54 272/385/54 264/386/54 +f 272/385/54 271/387/54 265/388/54 +f 273/347/54 264/386/54 263/345/54 +f 271/387/54 270/389/54 266/390/54 +f 270/389/54 269/391/54 267/392/54 +f 269/391/54 268/393/54 267/392/54 +f 267/392/54 266/390/54 270/389/54 +f 266/390/54 265/388/54 271/387/54 +f 265/388/54 264/386/54 272/385/54 +f 273/347/54 261/348/54 299/350/54 +f 92/102/1 416/270/1 415/394/1 +f 92/102/1 415/394/1 414/395/1 +f 365/396/1 368/268/1 91/95/1 +f 377/397/1 365/396/1 91/95/1 +f 92/102/1 414/395/1 411/398/1 +f 92/102/1 411/398/1 406/399/1 +f 373/400/1 377/397/1 91/95/1 +f 374/401/1 373/400/1 91/95/1 +f 92/102/1 406/399/1 410/402/1 +f 92/102/1 410/402/1 407/403/1 +f 379/404/1 374/401/1 91/95/1 +f 375/405/1 379/404/1 91/95/1 +f 92/102/1 407/403/1 390/406/1 +f 92/102/1 390/406/1 387/407/1 +f 378/408/1 375/405/1 91/95/1 +f 366/409/1 378/408/1 91/95/1 +f 92/102/1 387/407/1 385/410/1 +f 92/102/1 385/410/1 389/411/1 +f 366/409/1 91/95/1 92/102/1 +f 383/412/56 366/409/56 92/102/56 +f 92/102/1 389/411/1 392/413/1 +f 92/102/1 392/413/1 394/414/1 +f 403/415/1 383/412/1 92/102/1 +f 401/416/1 403/415/1 92/102/1 +f 92/102/1 394/414/1 397/214/1 +f 399/215/1 401/416/1 92/102/1 diff --git a/resources/rendermodels/leap_motion_1_0/thumbnail_leap.png b/resources/rendermodels/leap_motion_1_0/thumbnail_leap.png new file mode 100644 index 00000000..6257014e Binary files /dev/null and b/resources/rendermodels/leap_motion_1_0/thumbnail_leap.png differ diff --git a/resources/settings.xml b/resources/settings.xml new file mode 100644 index 00000000..65a3422e --- /dev/null +++ b/resources/settings.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/tools/config_tool/config_tool.cpp b/tools/config_tool/config_tool.cpp deleted file mode 100644 index 228ac6de..00000000 --- a/tools/config_tool/config_tool.cpp +++ /dev/null @@ -1,426 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -#include "rapidjson/document.h" -#include "rapidjson/filereadstream.h" -#include "rapidjson/filewritestream.h" -#include "rapidjson/prettywriter.h" - -using namespace std; - -// execute a command and return its output -wstring exec(const wstring &cmd) { - - // escape the command to run in double quotes - // and send it to a command shell - wchar_t tmp[1024]; - wsprintf(tmp, L"cmd.exe /S /C \"%s\"", cmd.c_str()); - - wchar_t buffer[128]; - wstring result = L""; - shared_ptr pipe(_wpopen(tmp, L"r"), _pclose); - if (!pipe) throw runtime_error("popen() failed!"); - while (!feof(pipe.get())) { - if (fgetws(buffer, 128, pipe.get()) != NULL) - result += buffer; - } - return result; -} - -// read a registry key value of type REG_SZ -bool ReadRegValue(HKEY root, wstring key, wstring name, wstring &value) -{ - HKEY hKey; - if (RegOpenKeyEx(root, key.c_str(), 0, KEY_READ, &hKey) != ERROR_SUCCESS) - return false; - - DWORD type; - DWORD cbData; - if (RegQueryValueEx(hKey, name.c_str(), NULL, &type, NULL, &cbData) != ERROR_SUCCESS) - { - RegCloseKey(hKey); - return false; - } - - if (type != REG_SZ) - { - RegCloseKey(hKey); - return false; - } - - value = wstring(cbData / sizeof(wchar_t), L'\0'); - if (RegQueryValueEx(hKey, name.c_str(), NULL, NULL, reinterpret_cast(&value[0]), &cbData) != ERROR_SUCCESS) - { - RegCloseKey(hKey); - return false; - } - - RegCloseKey(hKey); - - size_t firstNull = value.find_first_of(L'\0'); - if (firstNull != string::npos) - value.resize(firstNull); - - return true; -} - -// check if a directory exists -bool dirExists(const std::wstring& dirName_in) -{ - DWORD ftyp = GetFileAttributes(dirName_in.c_str()); - if (ftyp == INVALID_FILE_ATTRIBUTES) - return false; //something is wrong with your path! - - if (ftyp & FILE_ATTRIBUTE_DIRECTORY) - return true; // this is a directory! - - return false; // this is not a directory! -} - -// get the SteamVR installation path -// TODO: I just learnt about %LOCALAPPDATA%\OpenVR\openvrpaths.vrpath. Let's make use of it. -bool SteamVRInstallLocation(wstring &location) -{ - // guess where streamVR is located from its uninstall entry. Is there a better way? - if (!ReadRegValue(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Steam App 250820", L"InstallLocation", location)) - { - // otherwise assume it's in the default Steam library - if (ReadRegValue(HKEY_CURRENT_USER, L"SOFTWARE\\Valve\\Steam", L"SteamPath", location)) - { - replace(location.begin(), location.end(), L'/', L'\\'); - - if (dirExists(location + L"\\steamapps\\common\\SteamVR")) - { - location.append(L"\\steamapps\\common\\SteamVR"); - return true; - } - else if (dirExists(location + L"\\steamapps\\common\\OpenVR")) - { - location.append(L"\\steamapps\\common\\OpenVR"); - return true; - } - return false; - } - } - else - { - return true; - } - return false; -} - -// get the path to the vrpathreg utility (32bit) -// (this will be enclosed in double quotes if path contains a space character) -bool SteamVRPathReg(wstring &location) -{ - if (SteamVRInstallLocation(location)) - { - location.append(L"\\bin\\win32\\vrpathreg.exe"); - - if (location.find(L' ') != wstring::npos) - location = L"\"" + location + L"\""; - - return true; - } - return false; -} - -// get the SteamVR config path from the vrpathreg utility -bool SteamVRConfigPath(wstring &configpath) -{ - wstring location; - if (SteamVRPathReg(location)) - { - wstring result = exec(location); - size_t pos = result.find(L"Config path = ", 0); - if (pos != wstring::npos) - { - pos += 14; - size_t pos2 = result.find(L"\n", pos); - configpath = result.substr(pos, pos2 - pos); - return true; - } - } - return false; -} - -// get the SteamVR log path from the vrpathreg utility -bool SteamVRLogPath(wstring &logpath) -{ - wstring location; - if (SteamVRPathReg(location)) - { - wstring result = exec(location); - size_t pos = result.find(L"Log path = ", 0); - if (pos != wstring::npos) - { - pos += 11; - size_t pos2 = result.find(L"\n", pos); - logpath = result.substr(pos, pos2 - pos); - return true; - } - return true; - } - return false; -} - -// get full path to steamvr.vrconfig file -bool SteamVRVRSettingsFile(wstring &configfile) -{ - if (SteamVRConfigPath(configfile)) - { - configfile.append(L"\\steamvr.vrsettings"); - return true; - } - return false; -} - -#include - -void MergeObject(rapidjson::Value& target, rapidjson::Value& source, rapidjson::Value::AllocatorType& allocator, rapidjson::Value& backup) { - if (target.GetType() == source.GetType() || - target.GetType() == rapidjson::kTrueType && source.GetType() == rapidjson::kFalseType || - target.GetType() == rapidjson::kFalseType && source.GetType() == rapidjson::kTrueType) - { - if (target.GetType() == rapidjson::kObjectType || target.GetType() == rapidjson::kArrayType) - { - std::vector toremove; - - // if the backup copy of the original document has members that are NOT in the source document - // we delete them from the backup copy - for (rapidjson::Value::MemberIterator itr = backup.MemberBegin(); itr != backup.MemberEnd(); ++itr) - if (source.FindMember((*itr).name) == source.MemberEnd()) - toremove.push_back(itr); - - // erase in reverse order to keep the iterators sane - for (int i = toremove.size()-1; i >= 0; i--) - backup.RemoveMember(toremove[i]); - - // add or merge members found in the source document into the target document - for (rapidjson::Value::MemberIterator itr = source.MemberBegin(); itr != source.MemberEnd(); ++itr) - { - rapidjson::Value::MemberIterator dest; - if ((dest = target.FindMember((*itr).name)) == target.MemberEnd()) - target.AddMember(itr->name, itr->value, allocator); - else - MergeObject((*dest).value, (*itr).value, allocator, (*backup.FindMember((*itr).name)).value); - } - } - // string, number, boolean and null types simply get replaced by the source - else if (target.GetType() == rapidjson::kStringType || - target.GetType() == rapidjson::kNumberType || - target.GetType() == rapidjson::kFalseType || - target.GetType() == rapidjson::kTrueType || - target.GetType() == rapidjson::kNullType) - target = source; - } -} - -bool SubtractObject(rapidjson::Value& target, rapidjson::Value& source) -{ - if (target.GetType() == source.GetType() || - target.GetType() == rapidjson::kTrueType && source.GetType() == rapidjson::kFalseType || - target.GetType() == rapidjson::kFalseType && source.GetType() == rapidjson::kTrueType) - { - if (target.GetType() == rapidjson::kObjectType || target.GetType() == rapidjson::kArrayType) - { - std::vector toremove; - - // subtract members found in the source document from the target document - for (rapidjson::Value::MemberIterator itr = source.MemberBegin(); itr != source.MemberEnd(); ++itr) - { - rapidjson::Value::MemberIterator dest; - if ((dest = target.FindMember((*itr).name)) != target.MemberEnd()) - if (SubtractObject((*dest).value, (*itr).value)) - toremove.push_back(dest); - } - - // erase in reverse order to keep the iterators sane - for (int i = toremove.size() - 1; i >= 0; i--) - target.RemoveMember(toremove[i]); - - // empty parent members should be deleted - if (target.MemberCount() == 0) return true; - } - // string, number, boolean and null types simply get removed - else if (target.GetType() == rapidjson::kStringType || - target.GetType() == rapidjson::kNumberType || - target.GetType() == rapidjson::kFalseType || - target.GetType() == rapidjson::kTrueType || - target.GetType() == rapidjson::kNullType) - return true; - } - return false; -} - -bool MergeJSON(const wstring &targetfile, const wstring &tobemergedin, const wstring &backupfile) -{ - char buffer[65536]; - - FILE * pFile = _wfopen(targetfile.c_str(), L"rt"); - if (pFile == NULL) - { - // create an empty JSON config file if we did not find an existing file. - pFile = _wfopen(targetfile.c_str(), L"wt"); - if (pFile != NULL) - { - fprintf(pFile, "{\n}\n"); - fclose(pFile); - } - - pFile = _wfopen(targetfile.c_str(), L"rt"); - } - rapidjson::Document document; - { - rapidjson::FileReadStream is(pFile, buffer, sizeof(buffer)); - document.ParseStream<0>(is); - } - fclose(pFile); - - FILE * pFile2 = _wfopen(tobemergedin.c_str(), L"rt"); - rapidjson::Document document2; - { - rapidjson::FileReadStream is2(pFile2, buffer, sizeof(buffer)); - document2.ParseStream<0>(is2); - } - fclose(pFile2); - - rapidjson::Document backup; - backup.CopyFrom(document, backup.GetAllocator()); - - MergeObject(document, document2, document.GetAllocator(), backup); - - FILE * pFile3 = _wfopen(targetfile.c_str(), L"wt"); - { - rapidjson::FileWriteStream os(pFile3, buffer, sizeof(buffer)); - rapidjson::PrettyWriter writer(os); - document.Accept(writer); - } - fclose(pFile3); - - FILE * pFile4 = _wfopen(backupfile.c_str(), L"wt"); - { - rapidjson::FileWriteStream os(pFile4, buffer, sizeof(buffer)); - rapidjson::PrettyWriter writer(os); - backup.Accept(writer); - } - fclose(pFile4); - - return true; -} - -bool UnmergeJSON(const wstring &targetfile, const wstring &tobeunmerged, const wstring &backupfile) -{ - char buffer[65536]; - - FILE * pFile = _wfopen(targetfile.c_str(), L"rt"); - rapidjson::Document document; - { - rapidjson::FileReadStream is(pFile, buffer, sizeof(buffer)); - document.ParseStream<0>(is); - } - fclose(pFile); - - FILE * pFile2 = _wfopen(tobeunmerged.c_str(), L"rt"); - rapidjson::Document document2; - { - rapidjson::FileReadStream is2(pFile2, buffer, sizeof(buffer)); - document2.ParseStream<0>(is2); - } - fclose(pFile2); - - FILE * pFile3 = _wfopen(backupfile.c_str(), L"rt"); - rapidjson::Document document3; - { - rapidjson::FileReadStream is3(pFile3, buffer, sizeof(buffer)); - document3.ParseStream<0>(is3); - } - fclose(pFile3); - - SubtractObject(document, document2); - rapidjson::Document backup; - backup.CopyFrom(document, backup.GetAllocator()); - MergeObject(document, document3, document.GetAllocator(), backup); - - FILE * pFile4 = _wfopen(targetfile.c_str(), L"wt"); - { - rapidjson::FileWriteStream os(pFile4, buffer, sizeof(buffer)); - rapidjson::PrettyWriter writer(os); - document.Accept(writer); - } - fclose(pFile4); - - return true; -} - -// main program -int wmain(int argc, wchar_t* argv[]) -{ - if (argc == 4) - { - // default to current working directory as the driver path - wchar_t wcwd[512]; - wchar_t *cwd = _wgetcwd(wcwd, sizeof(wcwd) / sizeof(wchar_t)); - - // if the path to the source JSON file contains a backslash, - // prefer this path over the current working directory for - // registering the driver path. - wchar_t *tmp; - if ((tmp = wcsrchr(argv[2], L'\\')) != NULL) - { - cwd = wcsncpy(wcwd, argv[2], tmp - argv[2]); - wcwd[tmp - argv[2]] = L'\0'; - } - - if (cwd != NULL) - { - wstring configfile; - if (SteamVRVRSettingsFile(configfile)) - { - if (!wcsicmp(argv[1], L"install")) - { - MergeJSON(configfile, argv[2], argv[3]); - - wstring location; - if (SteamVRPathReg(location)) - { - location.append(L" adddriver \""); - location.append(cwd); - location.append(L"\\leap"); - location.append(L"\""); - wstring result = exec(location); - wcout << result << endl; - } - } - else if (!wcsicmp(argv[1], L"uninstall")) - { - UnmergeJSON(configfile, argv[2], argv[3]); - - wstring location; - if (SteamVRPathReg(location)) - { - location.append(L" removedriver \""); - location.append(cwd); - location.append(L"\\leap"); - location.append(L"\""); - wstring result = exec(location); - wcout << result << endl; - } - } - } - else - wcout << L"Unable to determine location of steamvr.vrsettings file!" << endl; - } - } - else - { - wcout << L"Usage: config_tool.exe [un]install jsonfile backupfile" << endl; - } - return 0; -} diff --git a/tools/config_tool/config_tool.vcxproj b/tools/config_tool/config_tool.vcxproj deleted file mode 100644 index faed0ed7..00000000 --- a/tools/config_tool/config_tool.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {FD2D3DBF-C82D-4333-9710-7DD2C51FA8E1} - Win32Proj - config_tool - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../../../rapidjson-1.0.2/include - - - Console - true - RequireAdministrator - - - mkdir "$(InstallDir)\bin\Win32" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win32" - - - - - - - Level3 - Disabled - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../../../rapidjson-1.0.2/include - - - Console - true - RequireAdministrator - - - mkdir "$(InstallDir)\bin\Win64" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win64" - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../../../rapidjson-1.0.2/include - - - Console - true - true - true - RequireAdministrator - - - mkdir "$(InstallDir)\bin\Win32" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win32" - - - - - Level3 - - - MaxSpeed - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - ../../../rapidjson-1.0.2/include - - - Console - true - true - true - RequireAdministrator - - - mkdir "$(InstallDir)\bin\Win64" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win64" - - - - - - - - - \ No newline at end of file diff --git a/tools/config_tool/config_tool.vcxproj.filters b/tools/config_tool/config_tool.vcxproj.filters deleted file mode 100644 index 025a3cd6..00000000 --- a/tools/config_tool/config_tool.vcxproj.filters +++ /dev/null @@ -1,22 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - \ No newline at end of file diff --git a/tools/gesture_checker/gesture_checker.cpp b/tools/gesture_checker/gesture_checker.cpp deleted file mode 100644 index d4b094ae..00000000 --- a/tools/gesture_checker/gesture_checker.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/******************************************************************************\ -* Copyright (C) 2012-2016 Leap Motion, Inc. All rights reserved. * -* Leap Motion proprietary and confidential. Not for distribution. * -* Use subject to the terms of the Leap Motion SDK Agreement available at * -* https://developer.leapmotion.com/sdk_agreement, or another agreement * -* between Leap Motion and you, your company or other organization. * -\******************************************************************************/ - -#include -#include -#include -#include "GestureMatcher.h" - -using namespace Leap; - -class SampleListener : public Listener { -public: - virtual void onInit(const Controller&); - virtual void onConnect(const Controller&); - virtual void onDisconnect(const Controller&); - virtual void onExit(const Controller&); - virtual void onFrame(const Controller&); - virtual void onFocusGained(const Controller&); - virtual void onFocusLost(const Controller&); - virtual void onDeviceChange(const Controller&); - virtual void onServiceConnect(const Controller&); - virtual void onServiceDisconnect(const Controller&); - virtual void onServiceChange(const Controller&); - virtual void onDeviceFailure(const Controller&); - virtual void onLogMessage(const Controller&, MessageSeverity severity, int64_t timestamp, const char* msg); -}; - -const std::string fingerNames[] = { "Thumb", "Index", "Middle", "Ring", "Pinky" }; -const std::string boneNames[] = { "Metacarpal", "Proximal", "Middle", "Distal" }; - -void SampleListener::onInit(const Controller& controller) { - std::cout << "Initialized" << std::endl; -} - -void SampleListener::onConnect(const Controller& controller) { - std::cout << "Connected" << std::endl; -} - -void SampleListener::onDisconnect(const Controller& controller) { - // Note: not dispatched when running in a debugger. - std::cout << "Disconnected" << std::endl; -} - -void SampleListener::onExit(const Controller& controller) { - std::cout << "Exited" << std::endl; -} - -static float maprange(float input, float minimum, float maximum) -{ - float mapped = (input - minimum) / (maximum - minimum); - return std::max(std::min(mapped, 1.0f), 0.0f); -} - -#include - -void cls(HANDLE hConsole) -{ - COORD coordScreen = { 0, 0 }; // home for the cursor - DWORD cCharsWritten; - CONSOLE_SCREEN_BUFFER_INFO csbi; - DWORD dwConSize; - - // Get the number of character cells in the current buffer. - - if (!GetConsoleScreenBufferInfo(hConsole, &csbi)) - { - return; - } - - dwConSize = csbi.dwSize.X * csbi.dwSize.Y; - - // Fill the entire screen with blanks. - - if (!FillConsoleOutputCharacter(hConsole, // Handle to console screen buffer - (TCHAR) ' ', // Character to write to the buffer - dwConSize, // Number of cells to write - coordScreen, // Coordinates of first cell - &cCharsWritten))// Receive number of characters written - { - return; - } - - // Get the current text attribute. - - if (!GetConsoleScreenBufferInfo(hConsole, &csbi)) - { - return; - } - - // Set the buffer's attributes accordingly. - - if (!FillConsoleOutputAttribute(hConsole, // Handle to console screen buffer - csbi.wAttributes, // Character attributes to use - dwConSize, // Number of cells to set attribute - coordScreen, // Coordinates of first cell - &cCharsWritten)) // Receive number of characters written - { - return; - } - - // Put the cursor at its home coordinates. - - SetConsoleCursorPosition(hConsole, coordScreen); -} -void SampleListener::onFrame(const Controller& controller) { - // Get the most recent frame and report some basic information - const Frame frame = controller.frame(); - - cls(GetStdHandle(STD_OUTPUT_HANDLE)); - - static GestureMatcher matcher; - - for (int i = 0; i < 2; i++) - { - float scores[GestureMatcher::NUM_GESTURES]; - bool handFound = matcher.MatchGestures(frame, (GestureMatcher::WhichHand)(i + 1), scores); - if (handFound) - { - for (int j = 0; j < GestureMatcher::NUM_GESTURES; j++) - { - std::string tmp = GestureMatcher::GestureNameFromType((GestureMatcher::GestureType)j); - if (!tmp.empty()) - fprintf(stderr, "%-10s %-30s - %4.2f\n", i ? "Right Hand" : "Left Hand", tmp.c_str(), scores[j]); - } - - // Go through the hands in the dataset - HandList &hands = frame.hands(); - for (int h = 0; h < hands.count(); h++) - { - Hand &hand = hands[h]; - } - } - } - - Sleep(50); -} - -void SampleListener::onFocusGained(const Controller& controller) { - std::cout << "Focus Gained" << std::endl; -} - -void SampleListener::onFocusLost(const Controller& controller) { - std::cout << "Focus Lost" << std::endl; -} - -void SampleListener::onDeviceChange(const Controller& controller) { -#if 0 - std::cout << "Device Changed" << std::endl; - const DeviceList devices = controller.devices(); - - for (int i = 0; i < devices.count(); ++i) { - std::cout << "id: " << devices[i].toString() << std::endl; - std::cout << " isStreaming: " << (devices[i].isStreaming() ? "true" : "false") << std::endl; - std::cout << " isSmudged:" << (devices[i].isSmudged() ? "true" : "false") << std::endl; - std::cout << " isLightingBad:" << (devices[i].isLightingBad() ? "true" : "false") << std::endl; - } -#endif -} - -void SampleListener::onServiceConnect(const Controller& controller) { - std::cout << "Service Connected" << std::endl; -} - -void SampleListener::onServiceDisconnect(const Controller& controller) { - std::cout << "Service Disconnected" << std::endl; -} - -void SampleListener::onServiceChange(const Controller& controller) { - std::cout << "Service Changed" << std::endl; -} - -void SampleListener::onDeviceFailure(const Controller& controller) { - std::cout << "Device Error" << std::endl; - const Leap::FailedDeviceList devices = controller.failedDevices(); - - for (FailedDeviceList::const_iterator dl = devices.begin(); dl != devices.end(); ++dl) { - const FailedDevice device = *dl; - std::cout << " PNP ID:" << device.pnpId(); - std::cout << " Failure type:" << device.failure(); - } -} - -void SampleListener::onLogMessage(const Controller&, MessageSeverity s, int64_t t, const char* msg) { - switch (s) { - case Leap::MESSAGE_CRITICAL: - std::cout << "[Critical]"; - break; - case Leap::MESSAGE_WARNING: - std::cout << "[Warning]"; - break; - case Leap::MESSAGE_INFORMATION: - std::cout << "[Info]"; - break; - case Leap::MESSAGE_UNKNOWN: - std::cout << "[Unknown]"; - } - std::cout << "[" << t << "] "; - std::cout << msg << std::endl; -} - -int main(int argc, char** argv) { - // Create a sample listener and controller - SampleListener listener; - Controller controller; - - // Have the sample listener receive events from the controller - controller.addListener(listener); - - controller.setPolicy(Leap::Controller::POLICY_BACKGROUND_FRAMES); - - controller.setPolicy(Leap::Controller::POLICY_ALLOW_PAUSE_RESUME); - - // Keep this process running until Enter is pressed - std::cout << "Press Enter to quit, or enter 'p' to pause or unpause the service..." << std::endl; - - bool paused = false; - while (true) { - char c = std::cin.get(); - if (c == 'p') { - paused = !paused; - controller.setPaused(paused); - std::cin.get(); //skip the newline - } - else - break; - } - - // Remove the sample listener when done - controller.removeListener(listener); - - return 0; -} diff --git a/tools/gesture_checker/gesture_checker.vcxproj b/tools/gesture_checker/gesture_checker.vcxproj deleted file mode 100644 index 78238734..00000000 --- a/tools/gesture_checker/gesture_checker.vcxproj +++ /dev/null @@ -1,191 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {9C28E205-C4CD-43D4-91BC-4852D7A588EC} - Win32Proj - gesture_checker - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(LeapSDKDir)\include;$(OpenVRDir)\headers;..\..\drivers\driver_leap;%(AdditionalIncludeDirectories) - - - Console - true - $(OpenVRDir)\lib\win32;$(LeapSDKDir)\lib\x86;%(AdditionalLibraryDirectories) - Leap.lib;%(AdditionalDependencies) - - - mkdir "$(InstallDir)\bin\Win32" -copy "$(LeapSDKDir)\lib\x86\Leap.dll" "$(TargetDir)" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win32" -copy "$(LeapSDKDir)\lib\x86\Leap.dll" "$(InstallDir)\bin\Win32" - - - - - - - Level3 - Disabled - _DEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(LeapSDKDir)\include;$(OpenVRDir)\headers;..\..\drivers\driver_leap;%(AdditionalIncludeDirectories) - - - Console - true - $(OpenVRDir)\lib\win32;$(LeapSDKDir)\lib\x64;%(AdditionalLibraryDirectories) - Leap.lib;%(AdditionalDependencies) - - - mkdir "$(InstallDir)\bin\Win64" -copy "$(LeapSDKDir)\lib\x64\Leap.dll" "$(TargetDir)" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win64" -copy "$(LeapSDKDir)\lib\x64\Leap.dll" "$(InstallDir)\bin\Win64" - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(LeapSDKDir)\include;$(OpenVRDir)\headers;..\..\drivers\driver_leap;%(AdditionalIncludeDirectories) - - - Console - true - true - true - $(OpenVRDir)\lib\win32;$(LeapSDKDir)\lib\x86;%(AdditionalLibraryDirectories) - Leap.lib;%(AdditionalDependencies) - - - mkdir "$(InstallDir)\bin\Win32" -copy "$(LeapSDKDir)\lib\x86\Leap.dll" "$(TargetDir)" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win32" -copy "$(LeapSDKDir)\lib\x86\Leap.dll" "$(InstallDir)\bin\Win32" - - - - - Level3 - - - MaxSpeed - true - true - NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - $(LeapSDKDir)\include;$(OpenVRDir)\headers;..\..\drivers\driver_leap;%(AdditionalIncludeDirectories) - - - Console - true - true - true - $(OpenVRDir)\lib\win32;$(LeapSDKDir)\lib\x64;%(AdditionalLibraryDirectories) - Leap.lib;%(AdditionalDependencies) - - - mkdir "$(InstallDir)\bin\Win64" -copy "$(LeapSDKDir)\lib\x64\Leap.dll" "$(TargetDir)" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win64" -copy "$(LeapSDKDir)\lib\x64\Leap.dll" "$(InstallDir)\bin\Win64" - - - - - - - - - - \ No newline at end of file diff --git a/tools/gesture_checker/gesture_checker.vcxproj.filters b/tools/gesture_checker/gesture_checker.vcxproj.filters deleted file mode 100644 index c761ad88..00000000 --- a/tools/gesture_checker/gesture_checker.vcxproj.filters +++ /dev/null @@ -1,25 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - \ No newline at end of file diff --git a/tools/leap_installer/leap.vrsettings b/tools/leap_installer/leap.vrsettings deleted file mode 100644 index 40f869ce..00000000 --- a/tools/leap_installer/leap.vrsettings +++ /dev/null @@ -1,23 +0,0 @@ -{ - "leap" : { - "gripAngleOffset_lefthand" : 0, - "gripAngleOffset_righthand" : 0, - "renderModel_lefthand" : "vr_controller_vive_1_5", - "renderModel_righthand" : "vr_controller_vive_1_5" - }, - "leap_gestures" : { - "GrabPressed" : "GestureWithin:LowerFist[0.5,1.0]", - "MenuPressed" : "GestureWithin:FlatHandPalmTowards[0.5,1.0]", - "SystemPressed" : "GestureWithin:FlatHandPalmAway[0.5,1.0]", - "TouchpadAxis[0]" : "GestureAxis:ThumbPositionX[-1.0,-1.0]", - "TouchpadAxis[1]" : "GestureAxis:ThumbPositionY[-1.0,-1.0]", - "TouchpadPressed" : "GestureWithin:Thumbpress[0.5,1.0]", - "TouchpadTouched" : "GestureWithin:Thumbpress[0.0,0.5]", - "TriggerAxis[0]" : "GestureAxis:TriggerFinger[0.0,1.0]", - "TriggerAxis[1]" : 0, - "TriggerPressed" : "GestureWithin:TriggerFinger[0.5,1.0]" - }, - "steamvr" : { - "activateMultipleDrivers" : true - } -} diff --git a/tools/leap_installer/leap_installer.vdproj b/tools/leap_installer/leap_installer.vdproj deleted file mode 100644 index 4af18280..00000000 --- a/tools/leap_installer/leap_installer.vdproj +++ /dev/null @@ -1,1189 +0,0 @@ -"DeployProject" -{ -"VSVersion" = "3:800" -"ProjectType" = "8:{978C614F-708E-4E1A-B201-565925725DBA}" -"IsWebType" = "8:FALSE" -"ProjectName" = "8:leap_installer" -"LanguageId" = "3:1033" -"CodePage" = "3:1252" -"UILanguageId" = "3:1033" -"SccProjectName" = "8:" -"SccLocalPath" = "8:" -"SccAuxPath" = "8:" -"SccProvider" = "8:" - "Hierarchy" - { - "Entry" - { - "MsmKey" = "8:_0706FE0AAD41417BB58D9F50183271F0" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_08484652CC1245A58577AC6214844E8B" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_12BC84684BA747049533A98FB0D1806F" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_14E9E2A61C664A739BF672BD6497A5EB" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_2587F2D86A504AF4BC2863A08AD7050D" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_3132EE2D101044AC95074C6A67780183" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_3CA0FAC059694A78AC308168A9264E6B" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_3CDF1064A59443B5972EA70C40B6274E" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_46AFAD8EB71F4726B3C40C0631089D22" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_46D86E1EF46C45B291C7DFF0D05FEC5C" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_49761FE2D46C46CCABACAE1F484155E0" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_4A8E359CD3C640D6846A188FDB1303E2" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_5D2E8844BFC146EE8A48925D279754C7" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_5FA3B681B7C647769FCA9766EC8C7D5C" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_695E8F66CB1C459BB36C5CCBD37BDB71" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_70139AB9A2FB446CA7C8DDF56DDC1604" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_73089C7E2B7C4F008B43C8C898345CB2" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_880EDDBD2BDA486D8F835BEDCC35A3F1" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_983A7D1646F9483AA2D164DCF999E52A" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_A29A6B60034147968A5DA4F1C159D78C" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_A86A20EAE6A54E1182E623BEF1B0149D" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_AB090313E193434C85A8FA759CB6BE2C" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_BF8304C89F504814B6D214CBB097DD02" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_C419CDF73F0A4CC7B3BB7585A2CB5919" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_CFBCE41F6CBB497AAC174637F0027B36" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_D1A7B7704A7949AE959BEEECB56D10D8" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - "Entry" - { - "MsmKey" = "8:_F8AEF392AE0B43289FFBB2E89EDF8E3C" - "OwnerKey" = "8:_UNDEFINED" - "MsmSig" = "8:_UNDEFINED" - } - } - "Configurations" - { - "Debug" - { - "DisplayName" = "8:Debug" - "IsDebugOnly" = "11:TRUE" - "IsReleaseOnly" = "11:FALSE" - "OutputFilename" = "8:Debug\\steamvr_leap_driver.msi" - "PackageFilesAs" = "3:2" - "PackageFileSize" = "3:-2147483648" - "CabType" = "3:1" - "Compression" = "3:2" - "SignOutput" = "11:FALSE" - "CertificateFile" = "8:" - "PrivateKeyFile" = "8:" - "TimeStampServer" = "8:" - "InstallerBootstrapper" = "3:2" - "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" - { - "Enabled" = "11:TRUE" - "PromptEnabled" = "11:TRUE" - "PrerequisitesLocation" = "2:2" - "Url" = "8:" - "ComponentsUrl" = "8:" - "Items" - { - } - } - } - "Release" - { - "DisplayName" = "8:Release" - "IsDebugOnly" = "11:FALSE" - "IsReleaseOnly" = "11:TRUE" - "OutputFilename" = "8:Release\\steamvr_leap_driver.msi" - "PackageFilesAs" = "3:2" - "PackageFileSize" = "3:-2147483648" - "CabType" = "3:1" - "Compression" = "3:2" - "SignOutput" = "11:FALSE" - "CertificateFile" = "8:" - "PrivateKeyFile" = "8:" - "TimeStampServer" = "8:" - "InstallerBootstrapper" = "3:2" - "BootstrapperCfg:{63ACBE69-63AA-4F98-B2B6-99F9E24495F2}" - { - "Enabled" = "11:TRUE" - "PromptEnabled" = "11:TRUE" - "PrerequisitesLocation" = "2:1" - "Url" = "8:" - "ComponentsUrl" = "8:" - "Items" - { - } - } - } - } - "Deployable" - { - "CustomAction" - { - "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_253F674ABF3249DC9576155B0199A3D7" - { - "Name" = "8:config_tool.exe install" - "Condition" = "8:" - "Object" = "8:_3132EE2D101044AC95074C6A67780183" - "FileType" = "3:2" - "InstallAction" = "3:1" - "Arguments" = "8:install \"[TARGETDIR]leap.vrsettings\" \"[TARGETDIR]leap_backup.vrsettings\"" - "EntryPoint" = "8:" - "Sequence" = "3:1" - "Identifier" = "8:_B86DB632_9571_4BDF_A4E3_A281907D22C3" - "InstallerClass" = "11:FALSE" - "CustomActionData" = "8:" - } - "{4AA51A2D-7D85-4A59-BA75-B0809FC8B380}:_3934F57E01254B1CADD0A47252A9279B" - { - "Name" = "8:config_tool.exe uninstall" - "Condition" = "8:" - "Object" = "8:_3132EE2D101044AC95074C6A67780183" - "FileType" = "3:2" - "InstallAction" = "3:4" - "Arguments" = "8:uninstall \"[TARGETDIR]leap.vrsettings\" \"[TARGETDIR]leap_backup.vrsettings\"" - "EntryPoint" = "8:" - "Sequence" = "3:1" - "Identifier" = "8:_5D6D59E0_F6EF_4391_9594_415554BC7308" - "InstallerClass" = "11:FALSE" - "CustomActionData" = "8:" - } - } - "DefaultFeature" - { - "Name" = "8:DefaultFeature" - "Title" = "8:" - "Description" = "8:" - } - "ExternalPersistence" - { - "LaunchCondition" - { - } - } - "File" - { - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_0706FE0AAD41417BB58D9F50183271F0" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win32\\Leap.dll" - "TargetName" = "8:Leap.dll" - "Tag" = "8:" - "Folder" = "8:_63ACE570CFFD4D6A9853F4B6B90E0B8C" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_12BC84684BA747049533A98FB0D1806F" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win32\\leap_monitor.exe" - "TargetName" = "8:leap_monitor.exe" - "Tag" = "8:" - "Folder" = "8:_63ACE570CFFD4D6A9853F4B6B90E0B8C" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_14E9E2A61C664A739BF672BD6497A5EB" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win64\\leap_monitor.exe" - "TargetName" = "8:leap_monitor.exe" - "Tag" = "8:" - "Folder" = "8:_6E55793820964E8FAF968D498761B3E3" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_3132EE2D101044AC95074C6A67780183" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win64\\config_tool.exe" - "TargetName" = "8:config_tool.exe" - "Tag" = "8:" - "Folder" = "8:_B572C0F62C374CA0A6C66D010BE1A374" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_46D86E1EF46C45B291C7DFF0D05FEC5C" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win64\\gesture_checker.exe" - "TargetName" = "8:gesture_checker.exe" - "Tag" = "8:" - "Folder" = "8:_6E55793820964E8FAF968D498761B3E3" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_49761FE2D46C46CCABACAE1F484155E0" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win32\\driver_leap.dll" - "TargetName" = "8:driver_leap.dll" - "Tag" = "8:" - "Folder" = "8:_63ACE570CFFD4D6A9853F4B6B90E0B8C" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_5D2E8844BFC146EE8A48925D279754C7" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win64\\openvr_api.dll" - "TargetName" = "8:openvr_api.dll" - "Tag" = "8:" - "Folder" = "8:_6E55793820964E8FAF968D498761B3E3" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_70139AB9A2FB446CA7C8DDF56DDC1604" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win64\\driver_leap.dll" - "TargetName" = "8:driver_leap.dll" - "Tag" = "8:" - "Folder" = "8:_6E55793820964E8FAF968D498761B3E3" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_73089C7E2B7C4F008B43C8C898345CB2" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win32\\openvr_api.dll" - "TargetName" = "8:openvr_api.dll" - "Tag" = "8:" - "Folder" = "8:_63ACE570CFFD4D6A9853F4B6B90E0B8C" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_983A7D1646F9483AA2D164DCF999E52A" - { - "SourcePath" = "8:leap.vrsettings" - "TargetName" = "8:leap.vrsettings" - "Tag" = "8:" - "Folder" = "8:_B572C0F62C374CA0A6C66D010BE1A374" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_C419CDF73F0A4CC7B3BB7585A2CB5919" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win64\\Leap.dll" - "TargetName" = "8:Leap.dll" - "Tag" = "8:" - "Folder" = "8:_6E55793820964E8FAF968D498761B3E3" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - "{1FB2D0AE-D3B9-43D4-B9DD-F88EC61E35DE}:_D1A7B7704A7949AE959BEEECB56D10D8" - { - "SourcePath" = "8:D:\\Steam\\steamapps\\common\\SteamVR\\drivers\\leap\\bin\\Win32\\gesture_checker.exe" - "TargetName" = "8:gesture_checker.exe" - "Tag" = "8:" - "Folder" = "8:_63ACE570CFFD4D6A9853F4B6B90E0B8C" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Vital" = "11:TRUE" - "ReadOnly" = "11:FALSE" - "Hidden" = "11:FALSE" - "System" = "11:FALSE" - "Permanent" = "11:FALSE" - "SharedLegacy" = "11:FALSE" - "PackageAs" = "3:1" - "Register" = "3:1" - "Exclude" = "11:FALSE" - "IsDependency" = "11:FALSE" - "IsolateTo" = "8:" - } - } - "FileType" - { - } - "Folder" - { - "{3C67513D-01DD-4637-8A68-80971EB9504F}:_B572C0F62C374CA0A6C66D010BE1A374" - { - "DefaultLocation" = "8:c:\\Program Files\\SteamVR Leap Motion driver" - "Name" = "8:#1925" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:TARGETDIR" - "Folders" - { - "{9EF0B969-E518-4E46-987F-47570745A589}:_612B6353C7A34055B1F60607C3F3C0EA" - { - "Name" = "8:leap" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_B76C8E7B76134394BA854D344FACCAC0" - "Folders" - { - "{9EF0B969-E518-4E46-987F-47570745A589}:_443D9E912CDA437A99AA51722DDC713A" - { - "Name" = "8:resources" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_D85FCBA1B88545E3B2B7BAE881284A8F" - "Folders" - { - "{9EF0B969-E518-4E46-987F-47570745A589}:_579FDD1847A64CF1B5DCC9425B60BB30" - { - "Name" = "8:overlays" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_173FDA6832F44E668BF8C19581FF2336" - "Folders" - { - } - } - "{9EF0B969-E518-4E46-987F-47570745A589}:_830A36686C4B41FAA5C260125503B907" - { - "Name" = "8:rendermodels" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_FA1AFC43078A40B2A050FA0B02ED1D21" - "Folders" - { - "{9EF0B969-E518-4E46-987F-47570745A589}:_89792514000845C992963B269A395956" - { - "Name" = "8:leap_controller" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_F919CF26BBF8458587EE678E2FF9DDB8" - "Folders" - { - } - } - } - } - } - } - "{9EF0B969-E518-4E46-987F-47570745A589}:_9449B2F9163A4584830E19AACAD71EFC" - { - "Name" = "8:bin" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_AC65A2107E4B4BA8805F889F0F049AC8" - "Folders" - { - "{9EF0B969-E518-4E46-987F-47570745A589}:_63ACE570CFFD4D6A9853F4B6B90E0B8C" - { - "Name" = "8:Win32" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_DB679BDED51148F2A32F8E582D9D4E61" - "Folders" - { - } - } - "{9EF0B969-E518-4E46-987F-47570745A589}:_6E55793820964E8FAF968D498761B3E3" - { - "Name" = "8:Win64" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_0868F43C1375413D815C73AA49BBA0D4" - "Folders" - { - } - } - } - } - } - } - } - } - "{1525181F-901A-416C-8A58-119130FE478E}:_C723A1043DE14841B8C7302C11B8AA18" - { - "Name" = "8:#1924" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:WindowsFolder" - "Folders" - { - "{9EF0B969-E518-4E46-987F-47570745A589}:_9B448EAA375D496EB84FE5D58D8442DE" - { - "Name" = "8:System32" - "AlwaysCreate" = "11:FALSE" - "Condition" = "8:" - "Transitive" = "11:FALSE" - "Property" = "8:_0561C50F43E240A79C6986353BC3754A" - "Folders" - { - } - } - } - } - } - "LaunchCondition" - { - } - "Locator" - { - } - "MsiBootstrapper" - { - "LangId" = "3:1033" - "RequiresElevation" = "11:FALSE" - } - "Product" - { - "Name" = "8:Microsoft Visual Studio" - "ProductName" = "8:SteamVR Leap Motion driver" - "ProductCode" = "8:{1001FC44-A16C-4F4B-86E3-CD824B17D921}" - "PackageCode" = "8:{9346F0D1-5197-4097-B449-85A02F527053}" - "UpgradeCode" = "8:{76F38173-D6FE-4221-B110-E68665ACD1AD}" - "AspNetVersion" = "8:4.0.30319.0" - "RestartWWWService" = "11:FALSE" - "RemovePreviousVersions" = "11:FALSE" - "DetectNewerInstalledVersion" = "11:FALSE" - "InstallAllUsers" = "11:FALSE" - "ProductVersion" = "8:1.0.2" - "Manufacturer" = "8:cbuchner1" - "ARPHELPTELEPHONE" = "8:" - "ARPHELPLINK" = "8:https://github.com/cbuchner1/driver_leap/wiki" - "Title" = "8:SteamVR Leap Motion driver" - "Subject" = "8:" - "ARPCONTACT" = "8:Valve" - "Keywords" = "8:" - "ARPCOMMENTS" = "8:SteamVR Leap Motion driver" - "ARPURLINFOABOUT" = "8:https://github.com/cbuchner1/driver_leap/" - "ARPPRODUCTICON" = "8:" - "ARPIconIndex" = "3:0" - "SearchPath" = "8:" - "UseSystemSearchPath" = "11:TRUE" - "TargetPlatform" = "3:1" - "PreBuildEvent" = "8:" - "PostBuildEvent" = "8:" - "RunPostBuildEvent" = "3:0" - } - "Registry" - { - "HKLM" - { - "Keys" - { - } - } - "HKCU" - { - "Keys" - { - } - } - "HKCR" - { - "Keys" - { - } - } - "HKU" - { - "Keys" - { - } - } - "HKPU" - { - "Keys" - { - } - } - } - "Sequences" - { - } - "Shortcut" - { - } - "UserInterface" - { - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_1079ADBB887E449491045AA4852274DA" - { - "Name" = "8:#1902" - "Sequence" = "3:2" - "Attributes" = "3:3" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_81157913913040A89F871D4A7E5F8F46" - { - "Sequence" = "3:100" - "DisplayName" = "8:Finished" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminFinishedDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_1FF49CE54B7344CE9841BFA90E543B2F" - { - "Name" = "8:#1901" - "Sequence" = "3:2" - "Attributes" = "3:2" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_9943A35DB5654FB1A25AE3F4617D8526" - { - "Sequence" = "3:100" - "DisplayName" = "8:Progress" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminProgressDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - "ShowProgress" - { - "Name" = "8:ShowProgress" - "DisplayName" = "8:#1009" - "Description" = "8:#1109" - "Type" = "3:5" - "ContextData" = "8:1;True=1;False=0" - "Attributes" = "3:0" - "Setting" = "3:0" - "Value" = "3:1" - "DefaultValue" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_5A5348ED771E41FE97AEF5D265E4A125" - { - "Name" = "8:#1901" - "Sequence" = "3:1" - "Attributes" = "3:2" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_9C869C8C222F4BB98DD4ADF63295C31E" - { - "Sequence" = "3:100" - "DisplayName" = "8:Progress" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdProgressDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - "ShowProgress" - { - "Name" = "8:ShowProgress" - "DisplayName" = "8:#1009" - "Description" = "8:#1109" - "Type" = "3:5" - "ContextData" = "8:1;True=1;False=0" - "Attributes" = "3:0" - "Setting" = "3:0" - "Value" = "3:1" - "DefaultValue" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_84EC53F7BEF4469AB897466360DBD122" - { - "UseDynamicProperties" = "11:FALSE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdUserInterface.wim" - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_8904FC89D57B49EDA1F74A9434D88CF8" - { - "Name" = "8:#1900" - "Sequence" = "3:1" - "Attributes" = "3:1" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_1C977E6F7E3442968D0C232FFC986FE1" - { - "Sequence" = "3:100" - "DisplayName" = "8:Welcome" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdWelcomeDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - "CopyrightWarning" - { - "Name" = "8:CopyrightWarning" - "DisplayName" = "8:#1002" - "Description" = "8:#1102" - "Type" = "3:3" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:2" - "Value" = "8:Copyright (c) 2015, Valve Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." - "DefaultValue" = "8:#1202" - "UsePlugInResources" = "11:TRUE" - } - "Welcome" - { - "Name" = "8:Welcome" - "DisplayName" = "8:#1003" - "Description" = "8:#1103" - "Type" = "3:3" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:1" - "Value" = "8:#1203" - "DefaultValue" = "8:#1203" - "UsePlugInResources" = "11:TRUE" - } - } - } - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_A43AFDA484EF4E9AB0ECD5D0929AB511" - { - "Sequence" = "3:300" - "DisplayName" = "8:Confirm Installation" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdConfirmDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_F431AFDFA21F42CC8D9BF5B9BE3AE640" - { - "Sequence" = "3:200" - "DisplayName" = "8:Installation Folder" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdFolderDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - "InstallAllUsersVisible" - { - "Name" = "8:InstallAllUsersVisible" - "DisplayName" = "8:#1059" - "Description" = "8:#1159" - "Type" = "3:5" - "ContextData" = "8:1;True=1;False=0" - "Attributes" = "3:0" - "Setting" = "3:0" - "Value" = "3:1" - "DefaultValue" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_E6FB0F77DE974246B4417A714941A9DD" - { - "Name" = "8:#1900" - "Sequence" = "3:2" - "Attributes" = "3:1" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_54F294E6BCE444B383BE4DE372FC22D6" - { - "Sequence" = "3:100" - "DisplayName" = "8:Welcome" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminWelcomeDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - "CopyrightWarning" - { - "Name" = "8:CopyrightWarning" - "DisplayName" = "8:#1002" - "Description" = "8:#1102" - "Type" = "3:3" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:2" - "Value" = "8:Copyright (c) 2015, Valve Corporation All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." - "DefaultValue" = "8:#1202" - "UsePlugInResources" = "11:TRUE" - } - "Welcome" - { - "Name" = "8:Welcome" - "DisplayName" = "8:#1003" - "Description" = "8:#1103" - "Type" = "3:3" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:1" - "Value" = "8:#1203" - "DefaultValue" = "8:#1203" - "UsePlugInResources" = "11:TRUE" - } - } - } - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_69A710D59D91472B8B6863A4CC4884DA" - { - "Sequence" = "3:200" - "DisplayName" = "8:Installation Folder" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminFolderDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_8AD0839CE5EF4258840A82C183A5B7F5" - { - "Sequence" = "3:300" - "DisplayName" = "8:Confirm Installation" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdAdminConfirmDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - "{2479F3F5-0309-486D-8047-8187E2CE5BA0}:_F335AAAF85754F3C983D3C33B27029D1" - { - "UseDynamicProperties" = "11:FALSE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdBasicDialogs.wim" - } - "{DF760B10-853B-4699-99F2-AFF7185B4A62}:_F769A743BCB54D839A1EC51AA15D5C59" - { - "Name" = "8:#1902" - "Sequence" = "3:1" - "Attributes" = "3:3" - "Dialogs" - { - "{688940B3-5CA9-4162-8DEE-2993FA9D8CBC}:_E711C4B7E2534AC6963FBE1D5462CB5A" - { - "Sequence" = "3:100" - "DisplayName" = "8:Finished" - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:\\VsdFinishedDlg.wid" - "Properties" - { - "BannerBitmap" - { - "Name" = "8:BannerBitmap" - "DisplayName" = "8:#1001" - "Description" = "8:#1101" - "Type" = "3:8" - "ContextData" = "8:Bitmap" - "Attributes" = "3:4" - "Setting" = "3:1" - "UsePlugInResources" = "11:TRUE" - } - "UpdateText" - { - "Name" = "8:UpdateText" - "DisplayName" = "8:#1058" - "Description" = "8:#1158" - "Type" = "3:15" - "ContextData" = "8:" - "Attributes" = "3:0" - "Setting" = "3:1" - "Value" = "8:#1258" - "DefaultValue" = "8:#1258" - "UsePlugInResources" = "11:TRUE" - } - } - } - } - } - } - "MergeModule" - { - "{CEE29DC0-9FBA-4B99-8D47-5BC643D9B626}:_5FA3B681B7C647769FCA9766EC8C7D5C" - { - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:C:\\Program Files (x86)\\Common Files\\Merge Modules\\Microsoft_VC120_CRT_x86.msm" - "Properties" - { - } - "LanguageId" = "3:0" - "Exclude" = "11:FALSE" - "Folder" = "8:" - "Feature" = "8:" - "IsolateTo" = "8:" - } - "{CEE29DC0-9FBA-4B99-8D47-5BC643D9B626}:_A29A6B60034147968A5DA4F1C159D78C" - { - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:C:\\Program Files (x86)\\Common Files\\Merge Modules\\Microsoft_VC140_CRT_x86.msm" - "Properties" - { - } - "LanguageId" = "3:0" - "Exclude" = "11:FALSE" - "Folder" = "8:" - "Feature" = "8:" - "IsolateTo" = "8:" - } - "{CEE29DC0-9FBA-4B99-8D47-5BC643D9B626}:_AB090313E193434C85A8FA759CB6BE2C" - { - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:C:\\Program Files (x86)\\Common Files\\Merge Modules\\Microsoft_VC120_CRT_x64.msm" - "Properties" - { - } - "LanguageId" = "3:0" - "Exclude" = "11:FALSE" - "Folder" = "8:" - "Feature" = "8:" - "IsolateTo" = "8:" - } - "{CEE29DC0-9FBA-4B99-8D47-5BC643D9B626}:_BF8304C89F504814B6D214CBB097DD02" - { - "UseDynamicProperties" = "11:TRUE" - "IsDependency" = "11:FALSE" - "SourcePath" = "8:C:\\Program Files (x86)\\Common Files\\Merge Modules\\Microsoft_VC140_CRT_x64.msm" - "Properties" - { - } - "LanguageId" = "3:0" - "Exclude" = "11:FALSE" - "Folder" = "8:" - "Feature" = "8:" - "IsolateTo" = "8:" - } - } - "ProjectOutput" - { - } - } -} diff --git a/tools/leap_monitor/Resource.h b/tools/leap_monitor/Resource.h deleted file mode 100644 index d7fb1e38..00000000 --- a/tools/leap_monitor/Resource.h +++ /dev/null @@ -1,31 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by leap_monitor.rc -// - -#define IDS_APP_TITLE 103 - -#define IDR_MAINFRAME 128 -#define IDD_LEAP_MONITOR_DIALOG 102 -#define IDD_ABOUTBOX 103 -#define IDM_ABOUT 104 -#define IDM_EXIT 105 -#define IDI_LEAP_MONITOR 107 -#define IDI_SMALL 108 -#define IDC_LEAP_MONITOR 109 -#define IDC_MYICON 2 -#ifndef IDC_STATIC -#define IDC_STATIC -1 -#endif -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS - -#define _APS_NO_MFC 130 -#define _APS_NEXT_RESOURCE_VALUE 129 -#define _APS_NEXT_COMMAND_VALUE 32771 -#define _APS_NEXT_CONTROL_VALUE 1000 -#define _APS_NEXT_SYMED_VALUE 110 -#endif -#endif diff --git a/tools/leap_monitor/leap_monitor.cpp b/tools/leap_monitor/leap_monitor.cpp deleted file mode 100644 index 0d3edea3..00000000 --- a/tools/leap_monitor/leap_monitor.cpp +++ /dev/null @@ -1,321 +0,0 @@ -//========= Copyright Valve Corporation ============// -// -// leap_monitor.cpp : Interacts with driver_leap to provide overlay instructions at startup -// - -#include "stdafx.h" -#include "leap_monitor.h" -#include - -#include -#include -#include -#include - -const std::chrono::milliseconds k_MonitorInterval( 10 ); - -class CLeapMonitor -{ -public: - CLeapMonitor( const std::string & path ) - : m_strOverlayImagePath( path ) - , m_OverlayHandle( vr::k_ulOverlayHandleInvalid ) - , m_eCurrentOverlay( k_eNone ) - {} - - ~CLeapMonitor() {} - - void Run() - { - if ( Init() ) - { - MainLoop(); - } - - Shutdown(); - } - -protected: - - enum EOverlayToDisplay { k_eNone, k_ePointAtBaseForHemisphereTracking, k_eHoldAtShouldersForCoordinateAlignment }; - - bool Init() - { - // Start as "background" application. This prevents vrserver from being started - // on our behalf, and prevents us from keeping vrserver alive when everything else - // exits. This is very important because we're spawning from a driver, and any - // class besides "background" would keep vrserver running forever - vr::EVRInitError eVRInitError; - vr::VR_Init( &eVRInitError, vr::VRApplication_Background ); - if ( !vr::VRSystem() || eVRInitError != vr::VRInitError_None ) - return false; - - // Keep track of which devices use driver_leap - for ( int i = 0; i < vr::k_unMaxTrackedDeviceCount; ++i ) - { - UpdateTrackedDevice( i ); - } - - return true; - } - - void MainLoop() - { - while ( true ) - { - std::this_thread::sleep_for( k_MonitorInterval ); - -#if defined( WIN32 ) - MSG msg = { 0 }; - while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) - { - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } - - if ( msg.message == WM_QUIT ) - break; -#endif - - // Display instructions for user if we find any devices that need them - ShowOverlay( BestOverlayForLeapDevices() ); - - vr::VREvent_t Event; - while ( vr::VRSystem()->PollNextEvent( &Event, sizeof( Event ) ) ) - { - switch ( Event.eventType ) - { - case vr::VREvent_Quit: - exit( 0 ); - // NOTREAHED - - case vr::VREvent_TrackedDeviceActivated: - case vr::VREvent_TrackedDeviceUpdated: - UpdateTrackedDevice( Event.trackedDeviceIndex ); - break; - - case vr::VREvent_VendorSpecific_Reserved_Start + 0: - // User has made the "align" gesture. The driver can't see the HMD - // coordinates, so we forward those from our client view. - if ( IsLeapDevice( Event.trackedDeviceIndex ) ) - { -// printf("received event vr::VREvent_VendorSpecific_Reserved_Start + 0 for device %d\n", Event.trackedDeviceIndex); - TriggerRealignCoordinates( Event ); - } - break; - } - } - } - } - - /** Create and show an overlay nailed to the user's face */ - bool ShowOverlay( EOverlayToDisplay eOverlay ) - { - if ( m_eCurrentOverlay == eOverlay && m_OverlayHandle != vr::k_ulOverlayHandleInvalid ) - return true; - - // Hiding or changing, so destroy old overlay - HideOverlay(); - - if ( eOverlay == k_eNone ) - { - m_eCurrentOverlay = eOverlay; - return true; - } - - // Compositor must be initialized to create overlays - if ( !vr::VRCompositor() ) - return false; - - vr::EVROverlayError eOverlayError = vr::VROverlay()->CreateOverlay( "leap_monitor", "Leap Monitor", &m_OverlayHandle ); - if ( eOverlayError != vr::VROverlayError_None ) - return false; - - vr::HmdMatrix34_t matInFrontOfHead; - memset( &matInFrontOfHead, 0, sizeof( matInFrontOfHead ) ); - float scale = 1.4f; - matInFrontOfHead.m[0][0] = matInFrontOfHead.m[1][1] = matInFrontOfHead.m[2][2] = scale; - matInFrontOfHead.m[2][3] = -2.0f; - eOverlayError = vr::VROverlay()->SetOverlayTransformTrackedDeviceRelative( m_OverlayHandle, vr::k_unTrackedDeviceIndex_Hmd, &matInFrontOfHead ); - if ( eOverlayError != vr::VROverlayError_None ) - return false; - - std::string image; - switch ( eOverlay ) - { - case k_ePointAtBaseForHemisphereTracking: - image = m_strOverlayImagePath + "need_hemisphere_tracking.png"; - break; - - case k_eHoldAtShouldersForCoordinateAlignment: - image = m_strOverlayImagePath + "need_alignment_gesture.png"; - break; - - default: - HideOverlay(); - return false; - } - - eOverlayError = vr::VROverlay()->SetOverlayFromFile( m_OverlayHandle, image.c_str() ); - if ( eOverlayError != vr::VROverlayError_None ) - return false; - - eOverlayError = vr::VROverlay()->ShowOverlay( m_OverlayHandle ); - if ( eOverlayError != vr::VROverlayError_None ) - return false; - - m_eCurrentOverlay = eOverlay; - - return true; - } - - void HideOverlay() - { - if ( m_OverlayHandle == vr::k_ulOverlayHandleInvalid ) - return; - - vr::VRCompositor(); // Required to call overlays... - vr::VROverlay()->HideOverlay( m_OverlayHandle ); - vr::VROverlay()->DestroyOverlay( m_OverlayHandle ); - m_OverlayHandle = vr::k_ulOverlayHandleInvalid; - } - - /** Send a message to the driver with the HMD coordinates (which are not available to the server side) */ - bool TriggerRealignCoordinates( const vr::VREvent_t & Event ) - { - vr::TrackedDevicePose_t hmdPose; - vr::VRSystem()->GetDeviceToAbsoluteTrackingPose( vr::TrackingUniverseRawAndUncalibrated, -Event.eventAgeSeconds, &hmdPose, 1 ); - if ( !hmdPose.bPoseIsValid ) - return false; - - std::ostringstream ss; - char rgchReplyBuf[256]; - - ss << "leap:realign_coordinates"; - for ( int i = 0; i < 3; ++i ) - { - for ( int j = 0; j < 4; ++j ) - { - ss << " " << hmdPose.mDeviceToAbsoluteTracking.m[i][j]; - } - } -// printf("%s\n", ss.str().c_str()); - vr::VRSystem()->DriverDebugRequest( Event.trackedDeviceIndex, ss.str().c_str(), rgchReplyBuf, sizeof( rgchReplyBuf ) ); - return true; - } - - void Shutdown() - { - vr::VR_Shutdown(); - } - - /** Keep track of which devices are using driver_leap */ - void UpdateTrackedDevice( uint32_t unTrackedDeviceIndex ) - { - char rgchTrackingSystemName[vr::k_unTrackingStringSize]; - vr::ETrackedPropertyError eError; - - uint32_t size = vr::VRSystem()->GetStringTrackedDeviceProperty( unTrackedDeviceIndex, vr::Prop_TrackingSystemName_String, rgchTrackingSystemName, sizeof( rgchTrackingSystemName ), &eError ); - if ( eError == vr::TrackedProp_Success ) - { - if ( strcmp( rgchTrackingSystemName, "leap" ) == 0 ) - { - m_setLeapDevices.insert( unTrackedDeviceIndex ); - } - } - } - - /** If any Leap devices need automatic hemisphere tracking enabled, prompt the user to do that. - * Otherwise, if any devices do not know how to transform into the global coordinate system, show - * instructions for that. */ - EOverlayToDisplay BestOverlayForLeapDevices() - { - bool bNeedCoordinateAlignment = false; - vr::TrackedDevicePose_t poses[vr::k_unMaxTrackedDeviceCount]; - - // The "raw and uncalibrated" universe gives us coordinates in the HMD's native tracking space. - // Adjustments like room setup and seated zero position will be applied equally to the HMD and - // the coordinates we return, so the "raw" space is what we want our driver to match. - vr::VRSystem()->GetDeviceToAbsoluteTrackingPose( vr::TrackingUniverseRawAndUncalibrated, 0, poses, vr::k_unMaxTrackedDeviceCount ); - for ( auto it = m_setLeapDevices.begin(); it != m_setLeapDevices.end(); ++it ) - { - if ( poses[*it].bDeviceIsConnected ) - { - switch ( poses[*it].eTrackingResult ) - { - case vr::TrackingResult_Uninitialized: - // Getting all devices to have hemisphere tracking is high priority - return k_ePointAtBaseForHemisphereTracking; - - case vr::TrackingResult_Calibrating_InProgress: - bNeedCoordinateAlignment = true; - break; - } - } - } - - if ( bNeedCoordinateAlignment ) - return k_eHoldAtShouldersForCoordinateAlignment; - - return k_eNone; - } - - bool IsLeapDevice( uint32_t unTrackedDeviceIndex ) - { - return ( m_setLeapDevices.count( unTrackedDeviceIndex ) != 0 ); - } - -private: - std::string m_strOverlayImagePath; - vr::VROverlayHandle_t m_OverlayHandle; - EOverlayToDisplay m_eCurrentOverlay; - std::set m_setLeapDevices; -}; - -#if 0 -int main(int argc, char **argv) -{ - // Find resource path - HMODULE hModule = GetModuleHandleA(NULL); - char path[MAX_PATH]; - GetModuleFileNameA(hModule, path, MAX_PATH); - - char *snip = strstr(path, "\\bin\\"); - if (snip) - { - *snip = '\0'; - } - - std::string resources = std::string(path) + "\\resources\\overlays\\"; - - CLeapMonitor LeapMonitor(resources); - - LeapMonitor.Run(); -} -#else -int APIENTRY wWinMain(_In_ HINSTANCE hInstance, - _In_opt_ HINSTANCE hPrevInstance, - _In_ LPWSTR lpCmdLine, - _In_ int nCmdShow) -{ - UNREFERENCED_PARAMETER(hPrevInstance); - UNREFERENCED_PARAMETER(lpCmdLine); - - // Find resource path - HMODULE hModule = GetModuleHandleA( NULL ); - char path[MAX_PATH]; - GetModuleFileNameA( hModule, path, MAX_PATH ); - - char *snip = strstr( path, "\\bin\\" ); - if ( snip ) - { - *snip = '\0'; - } - - std::string resources = std::string( path ) + "\\resources\\overlays\\"; - - CLeapMonitor LeapMonitor( resources ); - - LeapMonitor.Run(); -} -#endif diff --git a/tools/leap_monitor/leap_monitor.h b/tools/leap_monitor/leap_monitor.h deleted file mode 100644 index d859326c..00000000 --- a/tools/leap_monitor/leap_monitor.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -//========= Copyright Valve Corporation ============// - -#include "resource.h" diff --git a/tools/leap_monitor/leap_monitor.ico b/tools/leap_monitor/leap_monitor.ico deleted file mode 100644 index b3ec03bd..00000000 Binary files a/tools/leap_monitor/leap_monitor.ico and /dev/null differ diff --git a/tools/leap_monitor/leap_monitor.rc b/tools/leap_monitor/leap_monitor.rc deleted file mode 100644 index 8507e61f..00000000 Binary files a/tools/leap_monitor/leap_monitor.rc and /dev/null differ diff --git a/tools/leap_monitor/leap_monitor.vcxproj b/tools/leap_monitor/leap_monitor.vcxproj deleted file mode 100644 index cfc67d94..00000000 --- a/tools/leap_monitor/leap_monitor.vcxproj +++ /dev/null @@ -1,206 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {BC06AF9C-36D6-455A-B421-00A9635684AD} - Win32Proj - leap_monitor - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - false - - - false - - - - Use - Level3 - Disabled - WIN32;_DEBUG;_WINDOWS;%(PreprocessorDefinitions) - $(LeapSDKDir)\include;$(OpenVRDir)\headers;%(AdditionalIncludeDirectories) - - - Windows - true - $(OpenVRDir)\lib\win32;$(LeapSDKDir)\lib\x86;%(AdditionalLibraryDirectories) - openvr_api.lib;%(AdditionalDependencies) - - - mkdir "$(InstallDir)\bin\Win32" -copy "$(OpenVRDir)\bin\Win32\openvr_api.dll" "$(TargetDir)" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win32" -copy "$(OpenVRDir)\bin\Win32\openvr_api.dll" "$(InstallDir)\bin\Win32" - - - - - Use - Level3 - Disabled - _DEBUG;_WINDOWS;%(PreprocessorDefinitions) - $(LeapSDKDir)\include;$(OpenVRDir)\headers;%(AdditionalIncludeDirectories) - - - Windows - true - openvr_api.lib;%(AdditionalDependencies) - $(OpenVRDir)\lib\win64;$(LeapSDKDir)\lib\x64;%(AdditionalLibraryDirectories) - - - mkdir "$(InstallDir)\bin\Win64" -copy "$(OpenVRDir)\bin\Win64\openvr_api.dll" "$(TargetDir)" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win64" -copy "$(OpenVRDir)\bin\Win64\openvr_api.dll" "$(InstallDir)\bin\Win64" - - - - - Level3 - Use - MaxSpeed - true - true - WIN32;NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - $(LeapSDKDir)\include;$(OpenVRDir)\headers;%(AdditionalIncludeDirectories) - - - Windows - true - true - true - $(OpenVRDir)\lib\win32;$(LeapSDKDir)\lib\x86;%(AdditionalLibraryDirectories) - openvr_api.lib;%(AdditionalDependencies) - - - mkdir "$(InstallDir)\bin\Win32" -copy "$(OpenVRDir)\bin\Win32\openvr_api.dll" "$(TargetDir)" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win32" -copy "$(OpenVRDir)\bin\Win32\openvr_api.dll" "$(InstallDir)\bin\Win32" - - - - - Level3 - NotUsing - MaxSpeed - true - true - NDEBUG;_WINDOWS;%(PreprocessorDefinitions) - $(LeapSDKDir)\include;$(OpenVRDir)\headers;%(AdditionalIncludeDirectories) - stdafx.h - - - Windows - true - true - true - openvr_api.lib;%(AdditionalDependencies) - $(OpenVRDir)\lib\win64;$(LeapSDKDir)\lib\x64;%(AdditionalLibraryDirectories) - - - mkdir "$(InstallDir)\bin\Win64" -copy "$(OpenVRDir)\bin\Win64\openvr_api.dll" "$(TargetDir)" -copy "$(OutDir)$(TargetName)$(TargetExt)" "$(InstallDir)\bin\Win64" -copy "$(OpenVRDir)\bin\Win64\openvr_api.dll" "$(InstallDir)\bin\Win64" - - - - - - - - - - - - Create - Create - Create - Create - - - - - - - - - - - - - \ No newline at end of file diff --git a/tools/leap_monitor/leap_monitor.vcxproj.filters b/tools/leap_monitor/leap_monitor.vcxproj.filters deleted file mode 100644 index f03edbce..00000000 --- a/tools/leap_monitor/leap_monitor.vcxproj.filters +++ /dev/null @@ -1,52 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - - - Source Files - - - Source Files - - - - - Resource Files - - - - - Resource Files - - - Resource Files - - - \ No newline at end of file diff --git a/tools/leap_monitor/small.ico b/tools/leap_monitor/small.ico deleted file mode 100644 index b3ec03bd..00000000 Binary files a/tools/leap_monitor/small.ico and /dev/null differ diff --git a/tools/leap_monitor/stdafx.cpp b/tools/leap_monitor/stdafx.cpp deleted file mode 100644 index 2a8e00d9..00000000 --- a/tools/leap_monitor/stdafx.cpp +++ /dev/null @@ -1,8 +0,0 @@ -// stdafx.cpp : source file that includes just the standard includes -// leap_monitor.pch will be the pre-compiled header -// stdafx.obj will contain the pre-compiled type information - -#include "stdafx.h" - -// TODO: reference any additional headers you need in STDAFX.H -// and not in this file diff --git a/tools/leap_monitor/stdafx.h b/tools/leap_monitor/stdafx.h deleted file mode 100644 index bb80440e..00000000 --- a/tools/leap_monitor/stdafx.h +++ /dev/null @@ -1,21 +0,0 @@ -// stdafx.h : include file for standard system include files, -// or project specific include files that are used frequently, but -// are changed infrequently -// - -#pragma once - -#include "targetver.h" - -#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers -// Windows Header Files: -#include - -// C RunTime Header Files -#include -#include -#include -#include - - -// TODO: reference additional headers your program requires here diff --git a/tools/leap_monitor/targetver.h b/tools/leap_monitor/targetver.h deleted file mode 100644 index 87c0086d..00000000 --- a/tools/leap_monitor/targetver.h +++ /dev/null @@ -1,8 +0,0 @@ -#pragma once - -// Including SDKDDKVer.h defines the highest available Windows platform. - -// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and -// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. - -#include diff --git a/vendor/LeapCSharp/Arm.cs b/vendor/LeapCSharp/Arm.cs new file mode 100644 index 00000000..7769bf80 --- /dev/null +++ b/vendor/LeapCSharp/Arm.cs @@ -0,0 +1,101 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + + /// + /// The Arm class represents the forearm. + /// + [Serializable] + public class Arm : Bone, IEquatable + { + + /// + /// Constructs a default Arm object. + /// Get valid Arm objects from a Hand object. + /// + /// @since 2.0.3 + /// + public Arm() : base() { } + + /// + /// Constructs a new Arm object. + /// @since 3.0 + /// + public Arm(Vector elbow, + Vector wrist, + Vector center, + Vector direction, + float length, + float width, + LeapQuaternion rotation) + : base(elbow, + wrist, + center, + direction, + length, + width, + BoneType.TYPE_METACARPAL, //ignored for arms + rotation) + { } + + /// + /// Compare Arm object equality. + /// Two Arm objects are equal if and only if both Arm objects represent the + /// exact same physical arm in the same frame and both Arm objects are valid. + /// @since 2.0.3 + /// + public bool Equals(Arm other) + { + return Equals(other as Bone); + } + + /// + /// A string containing a brief, human readable description of the Arm object. + /// @since 2.0.3 + /// + public override string ToString() + { + return "Arm"; + } + + /// + /// The position of the elbow. + /// If not in view, the elbow position is estimated based on typical human + /// anatomical proportions. + /// + /// @since 2.0.3 + /// + public Vector ElbowPosition + { + get + { + return base.PrevJoint; + } + } + + /// + /// The position of the wrist. + /// + /// Note that the wrist position is not collocated with the end of any bone in + /// the hand. There is a gap of a few centimeters since the carpal bones are + /// not included in the skeleton model. + /// + /// @since 2.0.3 + /// + public Vector WristPosition + { + get + { + return base.NextJoint; + } + } + } +} diff --git a/vendor/LeapCSharp/Bone.cs b/vendor/LeapCSharp/Bone.cs new file mode 100644 index 00000000..5537c384 --- /dev/null +++ b/vendor/LeapCSharp/Bone.cs @@ -0,0 +1,183 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + + /// + /// The Bone class represents a tracked bone. + /// + /// All fingers contain 4 bones that make up the anatomy of the finger. + /// Get valid Bone objects from a Finger object. + /// + /// Bones are ordered from base to tip, indexed from 0 to 3. Additionally, the + /// bone's Type enum may be used to index a specific bone anatomically. + /// + /// The thumb does not have a base metacarpal bone and therefore contains a valid, + /// zero length bone at that location. + /// @since 2.0 + /// + [Serializable] + public class Bone : IEquatable + { + + /// + /// Constructs a default invalid Bone object. + /// + /// @since 2.0 + /// + public Bone() + { + Type = BoneType.TYPE_INVALID; + } + + /// + /// Constructs a new Bone object. + /// @since 3.0 + /// + public Bone(Vector prevJoint, + Vector nextJoint, + Vector center, + Vector direction, + float length, + float width, + Bone.BoneType type, + LeapQuaternion rotation) + { + PrevJoint = prevJoint; + NextJoint = nextJoint; + Center = center; + Direction = direction; + Rotation = rotation; + Length = length; + Width = width; + Type = type; + } + + /// + /// Compare Bone object equality. + /// + /// Two Bone objects are equal if and only if both Bone objects represent the + /// exact same physical bone in the same frame and both Bone objects are valid. + /// @since 2.0 + /// + public bool Equals(Bone other) + { + return Center == other.Center && Direction == other.Direction && Length == other.Length; + } + + /// + /// A string containing a brief, human readable description of the Bone object. + /// @since 2.0 + /// + public override string ToString() + { + return Enum.GetName(typeof(BoneType), this.Type) + " bone"; + } + + /// + /// The base of the bone, closest to the wrist. + /// In anatomical terms, this is the proximal end of the bone. + /// @since 2.0 + /// + public Vector PrevJoint; + + /// + /// The end of the bone, closest to the finger tip. + /// In anatomical terms, this is the distal end of the bone. + /// @since 2.0 + /// + public Vector NextJoint; + + /// + /// The midpoint of the bone. + /// @since 2.0 + /// + public Vector Center; + + /// + /// The normalized direction of the bone from base to tip. + /// @since 2.0 + /// + public Vector Direction; + + /// + /// The estimated length of the bone. + /// @since 2.0 + /// + public float Length; + + /// + /// The average width of the flesh around the bone. + /// @since 2.0 + /// + public float Width; + + /// + /// The type of this bone. + /// @since 2.0 + /// + public BoneType Type; + + /// + /// The orientation of this Bone as a Quaternion. + /// @since 2.0 + /// + public LeapQuaternion Rotation; + + /// + /// The orthonormal basis vectors for this Bone as a Matrix. + /// The orientation of this Bone as a Quaternion. + /// + /// Basis vectors specify the orientation of a bone. + /// + /// **xBasis** Perpendicular to the longitudinal axis of the + /// bone; exits the sides of the finger. + /// + /// **yBasis or up vector** Perpendicular to the longitudinal + /// axis of the bone; exits the top and bottom of the finger. More positive + /// in the upward direction. + /// + /// **zBasis** Aligned with the longitudinal axis of the bone. + /// More positive toward the base of the finger. + /// + /// The bases provided for the right hand use the right-hand rule; those for + /// the left hand use the left-hand rule. Thus, the positive direction of the + /// x-basis is to the right for the right hand and to the left for the left + /// hand. You can change from right-hand to left-hand rule by multiplying the + /// z basis vector by -1. + /// + /// You can use the basis vectors for such purposes as measuring complex + /// finger poses and skeletal animation. + /// + /// Note that converting the basis vectors directly into a quaternion + /// representation is not mathematically valid. If you use quaternions, + /// create them from the derived rotation matrix not directly from the bases. + /// + /// @since 2.0 + /// + public LeapTransform Basis { get { return new LeapTransform(PrevJoint, Rotation); } } + + /// + /// Enumerates the type of bones. + /// + /// Members of this enumeration are returned by Bone.Type() to identify a + /// Bone object. + /// @since 2.0 + /// + public enum BoneType + { + TYPE_INVALID = -1, + TYPE_METACARPAL = 0, + TYPE_PROXIMAL = 1, + TYPE_INTERMEDIATE = 2, + TYPE_DISTAL = 3 + } + } +} diff --git a/vendor/LeapCSharp/CSharpExtensions.cs b/vendor/LeapCSharp/CSharpExtensions.cs new file mode 100644 index 00000000..c4c53956 --- /dev/null +++ b/vendor/LeapCSharp/CSharpExtensions.cs @@ -0,0 +1,106 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +using System; +namespace Leap +{ + /// + /// Various C# extensions used by the Leap C# classes. + /// + /// @since 3.0 + /// + public static class CSharpExtensions + { + /// + /// Compares whether two floating point numbers are within an epsilon value of each other. + /// @since 3.0 + /// + public static bool NearlyEquals(this float a, float b, float epsilon = Constants.EPSILON) + { + float absA = Math.Abs(a); + float absB = Math.Abs(b); + float diff = Math.Abs(a - b); + + if (a == b) + { // shortcut, handles infinities + return true; + } + else if (a == 0 || b == 0 || diff < float.MinValue) + { + // a or b is zero or both are extremely close to it + // relative error is less meaningful here + return diff < (epsilon * float.MinValue); + } + else + { // use relative error + return diff / (absA + absB) < epsilon; + } + } + + /// + /// Reports whether this object has the specified method. + /// @since 3.0 + /// + public static bool HasMethod(this object objectToCheck, string methodName) + { + var type = objectToCheck.GetType(); + return type.GetMethod(methodName) != null; + } + + /// + /// Returns the ordinal index of this enumeration item. + /// @since 3.0 + /// + public static int indexOf(this Enum enumItem) + { + return Array.IndexOf(Enum.GetValues(enumItem.GetType()), enumItem); + } + + /// + /// Gets the item at the ordinal position in this enumeration. + /// @since 3.0 + /// + public static T itemFor(this int ordinal) + { + T[] values = (T[])Enum.GetValues(typeof(T)); + return values[ordinal]; + } + + /// + /// Convenience function to consolidate event dispatching boilerplate code. + /// @since 3.0 + /// + public static void Dispatch(this EventHandler handler, + object sender, T eventArgs) where T : EventArgs + { + if (handler != null) handler(sender, eventArgs); + } + + /// + /// Convenience function to consolidate event dispatching boilerplate code. + /// Events are dispatched on the message queue of a threads' synchronization + /// context, if possible. + /// @since 3.0 + /// + public static void DispatchOnContext(this EventHandler handler, object sender, + System.Threading.SynchronizationContext context, + T eventArgs) where T : EventArgs + { + if (handler != null) + { + if (context != null) + { + System.Threading.SendOrPostCallback evt = (spc_args) => { handler(sender, spc_args as T); }; + context.Post(evt, eventArgs); + } + else + handler(sender, eventArgs); + } + } + } +} diff --git a/vendor/LeapCSharp/CircularObjectBuffer.cs b/vendor/LeapCSharp/CircularObjectBuffer.cs new file mode 100644 index 00000000..b56f082f --- /dev/null +++ b/vendor/LeapCSharp/CircularObjectBuffer.cs @@ -0,0 +1,110 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace LeapInternal +{ + //TODO add test for thread safety + + /** + * A Limited capacity, circular LIFO buffer that wraps around + * when full. Supports indexing to get older items. Array-backed. + * * + * Unlike many collections, objects are never removed, just overwritten when + * the buffer cycles back to their array location. + * + * Object types used must have default parameterless constructor. It should be obvious that + * such default objects are invalid. I.e. for Leap API objects, the IsValid property should be false. + */ + public class CircularObjectBuffer where T : new() + { + private T[] array; + private int current = 0; + private object locker = new object(); + public int Count { get; private set; } + public int Capacity { get; private set; } + public bool IsEmpty { get; private set; } + + public CircularObjectBuffer(int capacity) + { + Capacity = capacity; + array = new T[this.Capacity]; + current = 0; + Count = 0; + IsEmpty = true; + } + + /** Put an item at the head of the list. Once full, this will overwrite the oldest item. */ + public virtual void Put(ref T item) + { + lock (locker) + { + if (!IsEmpty) + { + current++; + if (current >= Capacity) + { + current = 0; + } + } + if (Count < Capacity) + Count++; + + lock (array) + { + array[current] = item; + } + IsEmpty = false; + } + } + + /** Get the item indexed backward from the head of the list */ + public void Get(out T t, int index = 0) + { + lock (locker) + { + if (IsEmpty || (index > Count - 1) || index < 0) + { + t = new T(); //default(T); + } + else + { + int effectiveIndex = current - index; + if (effectiveIndex < 0) + { + effectiveIndex += Capacity; + } + + t = array[effectiveIndex]; + } + } + } + + /** Increase */ + public void Resize(int newCapacity) + { + lock (locker) + { + if (newCapacity <= Capacity) + { + return; + } + + T[] newArray = new T[newCapacity]; + int j = 0; + for (int i = Count - 1; i >= 0; i--) + { + T t; + Get(out t, i); + newArray[j++] = t; + } + this.array = newArray; + this.Capacity = newCapacity; + } + } + } +} diff --git a/vendor/LeapCSharp/Config.cs b/vendor/LeapCSharp/Config.cs new file mode 100644 index 00000000..4af16a7a --- /dev/null +++ b/vendor/LeapCSharp/Config.cs @@ -0,0 +1,195 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + + using LeapInternal; + using System; + using System.Collections.Generic; + + /// + /// The Config class provides access to Leap Motion system configuration information. + /// + /// @since 1.0 + /// + public class Config + { + private Connection _connection; + private Dictionary _transactions = new Dictionary(); + + /// + /// Creates a new Config object for setting runtime configuration settings. + /// + /// Note that the Controller.Config provides a properly initialized Config object already. + /// @since 3.0 + /// + public Config(Connection.Key connectionKey) + { + _connection = Connection.GetConnection(connectionKey); + _connection.LeapConfigChange += handleConfigChange; + _connection.LeapConfigResponse += handleConfigResponse; + } + public Config(int connectionId) : this(new Connection.Key(connectionId)) { } + + private void handleConfigChange(object sender, ConfigChangeEventArgs eventArgs) + { + object actionDelegate; + if (_transactions.TryGetValue(eventArgs.RequestId, out actionDelegate)) + { + Action changeAction = actionDelegate as Action; + changeAction(eventArgs.Succeeded); + _transactions.Remove(eventArgs.RequestId); + } + } + + private void handleConfigResponse(object sender, SetConfigResponseEventArgs eventArgs) + { + object actionDelegate = new object(); + if (_transactions.TryGetValue(eventArgs.RequestId, out actionDelegate)) + { + switch (eventArgs.DataType) + { + case ValueType.TYPE_BOOLEAN: + Action boolAction = actionDelegate as Action; + boolAction((int)eventArgs.Value != 0); + break; + case ValueType.TYPE_FLOAT: + Action floatAction = actionDelegate as Action; + floatAction((float)eventArgs.Value); + break; + case ValueType.TYPE_INT32: + Action intAction = actionDelegate as Action; + intAction((Int32)eventArgs.Value); + break; + case ValueType.TYPE_STRING: + Action stringAction = actionDelegate as Action; + stringAction((string)eventArgs.Value); + break; + default: + break; + } + _transactions.Remove(eventArgs.RequestId); + } + } + + /// + /// Requests a configuration value. + /// + /// You must provide an action to take when the Leap service returns the config value. + /// The Action delegate must take a parameter matching the config value type. The current + /// value of the setting is passed to this delegate. + /// + /// @since 3.0 + /// + public bool Get(string key, Action onResult) + { + uint requestId = _connection.GetConfigValue(key); + if (requestId > 0) + { + _transactions.Add(requestId, onResult); + return true; + } + return false; + } + + /// + /// Sets a configuration value. + /// + /// You must provide an action to take when the Leap service sets the config value. + /// The Action delegate must take a boolean parameter. The service calls this delegate + /// with the value true if the setting was changed successfully and false, otherwise. + /// + /// @since 3.0 + /// + public bool Set(string key, T value, Action onResult) where T : IConvertible + { + uint requestId = _connection.SetConfigValue(key, value); + + if (requestId > 0) + { + _transactions.Add(requestId, onResult); + return true; + } + return false; + } + + [Obsolete("Use the generic Set method instead.")] + public ValueType Type(string key) + { + return ValueType.TYPE_UNKNOWN; + } + + [Obsolete("Use the generic Get method instead.")] + public bool GetBool(string key) + { + return false; + } + + [Obsolete("Use the generic Set method instead.")] + public bool SetBool(string key, bool value) + { + return false; + } + + [Obsolete("Use the generic Get method instead.")] + public bool GetInt32(string key) + { + return false; + } + + [Obsolete("Use the generic Set method instead.")] + public bool SetInt32(string key, int value) + { + return false; + } + + [Obsolete("Use the generic Get method instead.")] + public bool GetFloat(string key) + { + return false; + } + + [Obsolete("Use the generic Set method instead.")] + public bool SetFloat(string key, float value) + { + return false; + } + + [Obsolete("Use the generic Get method instead.")] + public bool GetString(string key) + { + return false; + } + + [Obsolete("Use the generic Set method instead.")] + public bool SetString(string key, string value) + { + return false; + } + + [Obsolete] + public bool Save() + { + return false; + } + + /// + /// Enumerates the possible data types for configuration values. + /// @since 1.0 + /// + public enum ValueType + { + TYPE_UNKNOWN = 0, + TYPE_BOOLEAN = 1, + TYPE_INT32 = 2, + TYPE_FLOAT = 6, + TYPE_STRING = 8, + } + } +} diff --git a/vendor/LeapCSharp/Connection.cs b/vendor/LeapCSharp/Connection.cs new file mode 100644 index 00000000..a6dde683 --- /dev/null +++ b/vendor/LeapCSharp/Connection.cs @@ -0,0 +1,1044 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace LeapInternal +{ + using Leap; + using System; + using System.Collections.Generic; + using System.Runtime.InteropServices; + using System.Threading; + + public class Connection + { + public struct Key + { + public readonly int connectionId; + public readonly string serverNamespace; + + public Key(int connectionId, string serverNamespace = null) + { + this.connectionId = connectionId; + this.serverNamespace = serverNamespace; + } + } + + private static Dictionary connectionDictionary = new Dictionary(); + + public static Connection GetConnection(int connectionId = 0) + { + return GetConnection(new Key(connectionId)); + } + + public static Connection GetConnection(Key connectionKey) + { + Connection conn; + if (!Connection.connectionDictionary.TryGetValue(connectionKey, out conn)) + { + conn = new Connection(connectionKey); + connectionDictionary.Add(connectionKey, conn); + } + return conn; + } + + //Left-right precalculated offsets + private static long _handIdOffset; + private static long _handPositionOffset; + private static long _handOrientationOffset; + + static Connection() + { + _handIdOffset = Marshal.OffsetOf(typeof(LEAP_HAND), "id").ToInt64(); + + long palmOffset = Marshal.OffsetOf(typeof(LEAP_HAND), "palm").ToInt64(); + _handPositionOffset = Marshal.OffsetOf(typeof(LEAP_PALM), "position").ToInt64() + palmOffset; + _handOrientationOffset = Marshal.OffsetOf(typeof(LEAP_PALM), "orientation").ToInt64() + palmOffset; + } + + public Key ConnectionKey { get; private set; } + public CircularObjectBuffer Frames { get; set; } + + private DeviceList _devices = new DeviceList(); + private FailedDeviceList _failedDevices; + + private DistortionData _currentLeftDistortionData = new DistortionData(); + private DistortionData _currentRightDistortionData = new DistortionData(); + private int _frameBufferLength = 60; //TODO, surface this value in LeapC, currently hardcoded! + + private IntPtr _leapConnection; + private bool _isRunning = false; + private Thread _polster; + + //Policy and enabled features + private UInt64 _requestedPolicies = 0; + private UInt64 _activePolicies = 0; + + //Config change status + private Dictionary _configRequests = new Dictionary(); + + //Connection events + public SynchronizationContext EventContext { get; set; } + + private EventHandler _leapInit; + public event EventHandler LeapInit + { + add + { + _leapInit += value; + if (_leapConnection != IntPtr.Zero) + value(this, new LeapEventArgs(LeapEvent.EVENT_INIT)); + } + remove { _leapInit -= value; } + } + + private EventHandler _leapConnectionEvent; + public event EventHandler LeapConnection + { + add + { + _leapConnectionEvent += value; + if (IsServiceConnected) + value(this, new ConnectionEventArgs()); + } + remove { _leapConnectionEvent -= value; } + } + public EventHandler LeapConnectionLost; + public EventHandler LeapDevice; + public EventHandler LeapDeviceLost; + public EventHandler LeapDeviceFailure; + public EventHandler LeapPolicyChange; + public EventHandler LeapFrame; + public EventHandler LeapInternalFrame; + public EventHandler LeapLogEvent; + public EventHandler LeapConfigResponse; + public EventHandler LeapConfigChange; + public EventHandler LeapDistortionChange; + public EventHandler LeapDroppedFrame; + public EventHandler LeapImage; + public EventHandler LeapPointMappingChange; + public EventHandler LeapHeadPoseChange; + + public Action LeapBeginProfilingForThread; + public Action LeapEndProfilingForThread; + public Action LeapBeginProfilingBlock; + public Action LeapEndProfilingBlock; + + private bool _disposed = false; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // Protected implementation of Dispose pattern. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + if (disposing) + { + } + + Stop(); + LeapC.DestroyConnection(_leapConnection); + _leapConnection = IntPtr.Zero; + + _disposed = true; + } + + ~Connection() + { + Dispose(false); + } + + private Connection(Key connectionKey) + { + ConnectionKey = connectionKey; + _leapConnection = IntPtr.Zero; + + Frames = new CircularObjectBuffer(_frameBufferLength); + } + + private LEAP_ALLOCATOR _pLeapAllocator = new LEAP_ALLOCATOR(); + + public void Start() + { + if (_isRunning) + return; + + eLeapRS result; + if (_leapConnection == IntPtr.Zero) + { + if (ConnectionKey.serverNamespace == null) + { + result = LeapC.CreateConnection(out _leapConnection); + } + else + { + LEAP_CONNECTION_CONFIG config = new LEAP_CONNECTION_CONFIG(); + config.size = (uint)Marshal.SizeOf(config); + config.flags = 0; + config.server_namespace = Marshal.StringToHGlobalAnsi(ConnectionKey.serverNamespace); + result = LeapC.CreateConnection(ref config, out _leapConnection); + Marshal.FreeHGlobal(config.server_namespace); + } + + if (result != eLeapRS.eLeapRS_Success || _leapConnection == IntPtr.Zero) + { + reportAbnormalResults("LeapC CreateConnection call was ", result); + return; + } + } + result = LeapC.OpenConnection(_leapConnection); + if (result != eLeapRS.eLeapRS_Success) + { + reportAbnormalResults("LeapC OpenConnection call was ", result); + return; + } + // The Allocator must persist the lifetime of the connection + if (_pLeapAllocator.allocate == null) + { + _pLeapAllocator.allocate = MemoryManager.Pin; + } + if (_pLeapAllocator.deallocate == null) + { + _pLeapAllocator.deallocate = MemoryManager.Unpin; + } + LeapC.SetAllocator(_leapConnection, ref _pLeapAllocator); + + _isRunning = true; + AppDomain.CurrentDomain.DomainUnload += (arg1, arg2) => Dispose(true); + + _polster = new Thread(new ThreadStart(this.processMessages)); + _polster.Name = "LeapC Worker"; + _polster.IsBackground = true; + _polster.Start(); + } + + public void Stop() + { + if (!_isRunning) + return; + + _isRunning = false; + + //Very important to close the connection before we try to join the + //worker thread! The call to PollConnection can sometimes block, + //despite the timeout, causing an attempt to join the thread waiting + //forever and preventing the connection from stopping. + // + //It seems that closing the connection causes PollConnection to + //unblock in these cases, so just make sure to close the connection + //before trying to join the worker thread. + LeapC.CloseConnection(_leapConnection); + + _polster.Join(); + } + + //Run in Polster thread, fills in object queues + private void processMessages() + { + //Only profiling block currently is the Handle Event block + const string HANDLE_EVENT_PROFILER_BLOCK = "Handle Event"; + bool hasBegunProfilingForThread = false; + + try + { + eLeapRS result; + _leapInit.DispatchOnContext(this, EventContext, new LeapEventArgs(LeapEvent.EVENT_INIT)); + while (_isRunning) + { + if (LeapBeginProfilingForThread != null && !hasBegunProfilingForThread) + { + LeapBeginProfilingForThread(new BeginProfilingForThreadArgs("Worker Thread", + HANDLE_EVENT_PROFILER_BLOCK)); + hasBegunProfilingForThread = true; + } + + LEAP_CONNECTION_MESSAGE _msg = new LEAP_CONNECTION_MESSAGE(); + uint timeout = 150; + result = LeapC.PollConnection(_leapConnection, timeout, ref _msg); + + if (result != eLeapRS.eLeapRS_Success) + { + reportAbnormalResults("LeapC PollConnection call was ", result); + continue; + } + + if (LeapBeginProfilingBlock != null && hasBegunProfilingForThread) + { + LeapBeginProfilingBlock(new BeginProfilingBlockArgs(HANDLE_EVENT_PROFILER_BLOCK)); + } + + switch (_msg.type) + { + case eLeapEventType.eLeapEventType_None: + break; + + case eLeapEventType.eLeapEventType_Connection: + LEAP_CONNECTION_EVENT connection_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out connection_evt); + handleConnection(ref connection_evt); + break; + case eLeapEventType.eLeapEventType_ConnectionLost: + LEAP_CONNECTION_LOST_EVENT connection_lost_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out connection_lost_evt); + handleConnectionLost(ref connection_lost_evt); + break; + + case eLeapEventType.eLeapEventType_Device: + LEAP_DEVICE_EVENT device_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out device_evt); + handleDevice(ref device_evt); + break; + + // Note that unplugging a device generates an eLeapEventType_DeviceLost event + // message, not a failure message. DeviceLost is further down. + case eLeapEventType.eLeapEventType_DeviceFailure: + LEAP_DEVICE_FAILURE_EVENT device_failure_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out device_failure_evt); + handleFailedDevice(ref device_failure_evt); + break; + + case eLeapEventType.eLeapEventType_Policy: + LEAP_POLICY_EVENT policy_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out policy_evt); + handlePolicyChange(ref policy_evt); + break; + + case eLeapEventType.eLeapEventType_Tracking: + LEAP_TRACKING_EVENT tracking_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out tracking_evt); + handleTrackingMessage(ref tracking_evt); + break; + case eLeapEventType.eLeapEventType_LogEvent: + LEAP_LOG_EVENT log_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out log_evt); + reportLogMessage(ref log_evt); + break; + case eLeapEventType.eLeapEventType_DeviceLost: + LEAP_DEVICE_EVENT device_lost_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out device_lost_evt); + handleLostDevice(ref device_lost_evt); + break; + case eLeapEventType.eLeapEventType_ConfigChange: + LEAP_CONFIG_CHANGE_EVENT config_change_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out config_change_evt); + handleConfigChange(ref config_change_evt); + break; + case eLeapEventType.eLeapEventType_ConfigResponse: + handleConfigResponse(ref _msg); + break; + case eLeapEventType.eLeapEventType_DroppedFrame: + LEAP_DROPPED_FRAME_EVENT dropped_frame_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out dropped_frame_evt); + handleDroppedFrame(ref dropped_frame_evt); + break; + case eLeapEventType.eLeapEventType_Image: + LEAP_IMAGE_EVENT image_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out image_evt); + handleImage(ref image_evt); + break; + case eLeapEventType.eLeapEventType_PointMappingChange: + LEAP_POINT_MAPPING_CHANGE_EVENT point_mapping_change_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out point_mapping_change_evt); + handlePointMappingChange(ref point_mapping_change_evt); + break; + case eLeapEventType.eLeapEventType_HeadPose: + LEAP_HEAD_POSE_EVENT head_pose_event; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out head_pose_event); + handleHeadPoseChange(ref head_pose_event); + break; + case eLeapEventType.eLeapEventType_DeviceStatusChange: + LEAP_DEVICE_STATUS_CHANGE_EVENT status_evt; + StructMarshal.PtrToStruct(_msg.eventStructPtr, out status_evt); + handleDeviceStatusEvent(ref status_evt); + break; + } //switch on _msg.type + + if (LeapEndProfilingBlock != null && hasBegunProfilingForThread) + { + LeapEndProfilingBlock(new EndProfilingBlockArgs(HANDLE_EVENT_PROFILER_BLOCK)); + } + } //while running + } + catch (Exception e) + { + Logger.Log("Exception: " + e); + _isRunning = false; + } + finally + { + if (LeapEndProfilingForThread != null && hasBegunProfilingForThread) + { + LeapEndProfilingForThread(new EndProfilingForThreadArgs()); + } + } + } + + private void handleTrackingMessage(ref LEAP_TRACKING_EVENT trackingMsg) + { + Frames.Put(ref trackingMsg); + + if (LeapFrame != null) + { + LeapFrame.DispatchOnContext(this, EventContext, new FrameEventArgs(new Frame().CopyFrom(ref trackingMsg))); + } + } + + public UInt64 GetInterpolatedFrameSize(Int64 time) + { + UInt64 size = 0; + eLeapRS result = LeapC.GetFrameSize(_leapConnection, time, out size); + reportAbnormalResults("LeapC get interpolated frame call was ", result); + return size; + } + + public void GetInterpolatedFrame(Frame toFill, Int64 time) + { + UInt64 size = GetInterpolatedFrameSize(time); + IntPtr trackingBuffer = Marshal.AllocHGlobal((Int32)size); + eLeapRS result = LeapC.InterpolateFrame(_leapConnection, time, trackingBuffer, size); + reportAbnormalResults("LeapC get interpolated frame call was ", result); + if (result == eLeapRS.eLeapRS_Success) + { + LEAP_TRACKING_EVENT tracking_evt; + StructMarshal.PtrToStruct(trackingBuffer, out tracking_evt); + toFill.CopyFrom(ref tracking_evt); + } + Marshal.FreeHGlobal(trackingBuffer); + } + + public void GetInterpolatedFrameFromTime(Frame toFill, Int64 time, Int64 sourceTime) + { + UInt64 size = GetInterpolatedFrameSize(time); + IntPtr trackingBuffer = Marshal.AllocHGlobal((Int32)size); + eLeapRS result = LeapC.InterpolateFrameFromTime(_leapConnection, time, sourceTime, trackingBuffer, size); + reportAbnormalResults("LeapC get interpolated frame from time call was ", result); + if (result == eLeapRS.eLeapRS_Success) + { + LEAP_TRACKING_EVENT tracking_evt; + StructMarshal.PtrToStruct(trackingBuffer, out tracking_evt); + toFill.CopyFrom(ref tracking_evt); + } + Marshal.FreeHGlobal(trackingBuffer); + } + + public Frame GetInterpolatedFrame(Int64 time) + { + Frame frame = new Frame(); + GetInterpolatedFrame(frame, time); + return frame; + } + + public void GetInterpolatedHeadPose(ref LEAP_HEAD_POSE_EVENT toFill, Int64 time) + { + eLeapRS result = LeapC.InterpolateHeadPose(_leapConnection, time, ref toFill); + reportAbnormalResults("LeapC get interpolated head pose call was ", result); + } + + public LEAP_HEAD_POSE_EVENT GetInterpolatedHeadPose(Int64 time) + { + LEAP_HEAD_POSE_EVENT headPoseEvent = new LEAP_HEAD_POSE_EVENT(); + GetInterpolatedHeadPose(ref headPoseEvent, time); + return headPoseEvent; + } + + public void GetInterpolatedLeftRightTransform(Int64 time, + Int64 sourceTime, + Int64 leftId, + Int64 rightId, + out LeapTransform leftTransform, + out LeapTransform rightTransform) + { + leftTransform = LeapTransform.Identity; + rightTransform = LeapTransform.Identity; + + UInt64 size = GetInterpolatedFrameSize(time); + IntPtr trackingBuffer = Marshal.AllocHGlobal((Int32)size); + eLeapRS result = LeapC.InterpolateFrameFromTime(_leapConnection, time, sourceTime, trackingBuffer, size); + reportAbnormalResults("LeapC get interpolated frame from time call was ", result); + + if (result == eLeapRS.eLeapRS_Success) + { + LEAP_TRACKING_EVENT tracking_evt; + StructMarshal.PtrToStruct(trackingBuffer, out tracking_evt); + + int id; + LEAP_VECTOR position; + LEAP_QUATERNION orientation; + + long handPtr = tracking_evt.pHands.ToInt64(); + long idPtr = handPtr + _handIdOffset; + long posPtr = handPtr + _handPositionOffset; + long rotPtr = handPtr + _handOrientationOffset; + int stride = StructMarshal.Size; + + for (uint i = tracking_evt.nHands; i-- != 0; idPtr += stride, posPtr += stride, rotPtr += stride) + { + id = Marshal.ReadInt32(new IntPtr(idPtr)); + StructMarshal.PtrToStruct(new IntPtr(posPtr), out position); + StructMarshal.PtrToStruct(new IntPtr(rotPtr), out orientation); + + LeapTransform transform = new LeapTransform(position.ToLeapVector(), orientation.ToLeapQuaternion()); + if (id == leftId) + { + leftTransform = transform; + } + else if (id == rightId) + { + rightTransform = transform; + } + } + } + + Marshal.FreeHGlobal(trackingBuffer); + } + + private void handleConnection(ref LEAP_CONNECTION_EVENT connectionMsg) + { + if (_leapConnectionEvent != null) + { + _leapConnectionEvent.DispatchOnContext(this, EventContext, new ConnectionEventArgs()); + } + } + + private void handleConnectionLost(ref LEAP_CONNECTION_LOST_EVENT connectionMsg) + { + if (LeapConnectionLost != null) + { + LeapConnectionLost.DispatchOnContext(this, EventContext, new ConnectionLostEventArgs()); + } + } + private void handleDeviceStatusEvent(ref LEAP_DEVICE_STATUS_CHANGE_EVENT statusEvent) + { + var device = _devices.FindDeviceByHandle(statusEvent.device.handle); + if (device == null) + return; + device.UpdateStatus(statusEvent.status); + } + + + private void handleDevice(ref LEAP_DEVICE_EVENT deviceMsg) + { + IntPtr deviceHandle = deviceMsg.device.handle; + if (deviceHandle == IntPtr.Zero) + return; + + LEAP_DEVICE_INFO deviceInfo = new LEAP_DEVICE_INFO(); + eLeapRS result; + + IntPtr device; + result = LeapC.OpenDevice(deviceMsg.device, out device); + if (result != eLeapRS.eLeapRS_Success) + return; + + deviceInfo.serial = IntPtr.Zero; + deviceInfo.size = (uint)Marshal.SizeOf(deviceInfo); + result = LeapC.GetDeviceInfo(device, ref deviceInfo); //Query the serial length + if (result != eLeapRS.eLeapRS_Success) + return; + + deviceInfo.serial = Marshal.AllocCoTaskMem((int)deviceInfo.serial_length); + result = LeapC.GetDeviceInfo(device, ref deviceInfo); //Query the serial + + if (result == eLeapRS.eLeapRS_Success) + { + Device apiDevice = new Device(deviceHandle, + device, + deviceInfo.h_fov, //radians + deviceInfo.v_fov, //radians + deviceInfo.range / 1000.0f, //to mm + deviceInfo.baseline / 1000.0f, //to mm + (Device.DeviceType)deviceInfo.type, + deviceInfo.status, + Marshal.PtrToStringAnsi(deviceInfo.serial)); + Marshal.FreeCoTaskMem(deviceInfo.serial); + _devices.AddOrUpdate(apiDevice); + + if (LeapDevice != null) + { + LeapDevice.DispatchOnContext(this, EventContext, new DeviceEventArgs(apiDevice)); + } + } + } + + private void handleLostDevice(ref LEAP_DEVICE_EVENT deviceMsg) + { + Device lost = _devices.FindDeviceByHandle(deviceMsg.device.handle); + if (lost != null) + { + _devices.Remove(lost); + + if (LeapDeviceLost != null) + { + LeapDeviceLost.DispatchOnContext(this, EventContext, new DeviceEventArgs(lost)); + } + } + } + + private void handleFailedDevice(ref LEAP_DEVICE_FAILURE_EVENT deviceMsg) + { + string failureMessage; + string failedSerialNumber = "Unavailable"; + switch (deviceMsg.status) + { + case eLeapDeviceStatus.eLeapDeviceStatus_BadCalibration: + failureMessage = "Bad Calibration. Device failed because of a bad calibration record."; + break; + case eLeapDeviceStatus.eLeapDeviceStatus_BadControl: + failureMessage = "Bad Control Interface. Device failed because of a USB control interface error."; + break; + case eLeapDeviceStatus.eLeapDeviceStatus_BadFirmware: + failureMessage = "Bad Firmware. Device failed because of a firmware error."; + break; + case eLeapDeviceStatus.eLeapDeviceStatus_BadTransport: + failureMessage = "Bad Transport. Device failed because of a USB communication error."; + break; + default: + failureMessage = "Device failed for an unknown reason"; + break; + } + Device failed = _devices.FindDeviceByHandle(deviceMsg.hDevice); + if (failed != null) + { + _devices.Remove(failed); + } + + if (LeapDeviceFailure != null) + { + LeapDeviceFailure.DispatchOnContext(this, EventContext, + new DeviceFailureEventArgs((uint)deviceMsg.status, failureMessage, failedSerialNumber)); + } + } + + private void handleConfigChange(ref LEAP_CONFIG_CHANGE_EVENT configEvent) + { + string config_key = ""; + _configRequests.TryGetValue(configEvent.requestId, out config_key); + if (config_key != null) + _configRequests.Remove(configEvent.requestId); + if (LeapConfigChange != null) + { + LeapConfigChange.DispatchOnContext(this, EventContext, + new ConfigChangeEventArgs(config_key, configEvent.status != false, configEvent.requestId)); + } + } + + private void handleConfigResponse(ref LEAP_CONNECTION_MESSAGE configMsg) + { + LEAP_CONFIG_RESPONSE_EVENT config_response_evt; + StructMarshal.PtrToStruct(configMsg.eventStructPtr, out config_response_evt); + string config_key = ""; + _configRequests.TryGetValue(config_response_evt.requestId, out config_key); + if (config_key != null) + _configRequests.Remove(config_response_evt.requestId); + + Config.ValueType dataType; + object value; + uint requestId = config_response_evt.requestId; + if (config_response_evt.value.type != eLeapValueType.eLeapValueType_String) + { + switch (config_response_evt.value.type) + { + case eLeapValueType.eLeapValueType_Boolean: + dataType = Config.ValueType.TYPE_BOOLEAN; + value = config_response_evt.value.boolValue; + break; + case eLeapValueType.eLeapValueType_Int32: + dataType = Config.ValueType.TYPE_INT32; + value = config_response_evt.value.intValue; + break; + case eLeapValueType.eLeapValueType_Float: + dataType = Config.ValueType.TYPE_FLOAT; + value = config_response_evt.value.floatValue; + break; + default: + dataType = Config.ValueType.TYPE_UNKNOWN; + value = new object(); + break; + } + } + else + { + LEAP_CONFIG_RESPONSE_EVENT_WITH_REF_TYPE config_ref_value; + StructMarshal.PtrToStruct(configMsg.eventStructPtr, out config_ref_value); + dataType = Config.ValueType.TYPE_STRING; + value = config_ref_value.value.stringValue; + } + SetConfigResponseEventArgs args = new SetConfigResponseEventArgs(config_key, dataType, value, requestId); + + if (LeapConfigResponse != null) + { + LeapConfigResponse.DispatchOnContext(this, EventContext, args); + } + } + + private void reportLogMessage(ref LEAP_LOG_EVENT logMsg) + { + if (LeapLogEvent != null) + { + LeapLogEvent.DispatchOnContext(this, EventContext, new LogEventArgs(publicSeverity(logMsg.severity), logMsg.timestamp, Marshal.PtrToStringAnsi(logMsg.message))); + } + } + + private MessageSeverity publicSeverity(eLeapLogSeverity leapCSeverity) + { + switch (leapCSeverity) + { + case eLeapLogSeverity.eLeapLogSeverity_Unknown: + return MessageSeverity.MESSAGE_UNKNOWN; + case eLeapLogSeverity.eLeapLogSeverity_Information: + return MessageSeverity.MESSAGE_INFORMATION; + case eLeapLogSeverity.eLeapLogSeverity_Warning: + return MessageSeverity.MESSAGE_WARNING; + case eLeapLogSeverity.eLeapLogSeverity_Critical: + return MessageSeverity.MESSAGE_CRITICAL; + default: + return MessageSeverity.MESSAGE_UNKNOWN; + } + } + + private void handlePointMappingChange(ref LEAP_POINT_MAPPING_CHANGE_EVENT pointMapping) + { + if (LeapPointMappingChange != null) + { + LeapPointMappingChange.DispatchOnContext(this, EventContext, new PointMappingChangeEventArgs(pointMapping.frame_id, pointMapping.timestamp, pointMapping.nPoints)); + } + } + + private void handleDroppedFrame(ref LEAP_DROPPED_FRAME_EVENT droppedFrame) + { + if (LeapDroppedFrame != null) + { + LeapDroppedFrame.DispatchOnContext(this, EventContext, new DroppedFrameEventArgs(droppedFrame.frame_id, droppedFrame.reason)); + } + } + + private void handleHeadPoseChange(ref LEAP_HEAD_POSE_EVENT headPose) + { + if (LeapHeadPoseChange != null) + { + LeapHeadPoseChange.DispatchOnContext(this, EventContext, new HeadPoseEventArgs(headPose.head_position, headPose.head_orientation)); + } + } + + private DistortionData createDistortionData(LEAP_IMAGE image, Image.CameraType camera) + { + DistortionData distortionData = new DistortionData(); + distortionData.Version = image.matrix_version; + distortionData.Width = LeapC.DistortionSize; //fixed value for now + distortionData.Height = LeapC.DistortionSize; //fixed value for now + + //Visit LeapC.h for more details. We need to marshal the float data manually + //since the distortion struct cannot be represented safely in c# + distortionData.Data = new float[(int)(distortionData.Width * distortionData.Height * 2)]; //2 float values per map point + Marshal.Copy(image.distortionMatrix, distortionData.Data, 0, distortionData.Data.Length); + + if (LeapDistortionChange != null) + { + LeapDistortionChange.DispatchOnContext(this, EventContext, new DistortionEventArgs(distortionData, camera)); + } + return distortionData; + } + + private void handleImage(ref LEAP_IMAGE_EVENT imageMsg) + { + if (LeapImage != null) + { + //Update distortion data, if changed + if ((_currentLeftDistortionData.Version != imageMsg.leftImage.matrix_version) || !_currentLeftDistortionData.IsValid) + { + _currentLeftDistortionData = createDistortionData(imageMsg.leftImage, Image.CameraType.LEFT); + } + if ((_currentRightDistortionData.Version != imageMsg.rightImage.matrix_version) || !_currentRightDistortionData.IsValid) + { + _currentRightDistortionData = createDistortionData(imageMsg.rightImage, Image.CameraType.RIGHT); + } + ImageData leftImage = new ImageData(Image.CameraType.LEFT, imageMsg.leftImage, _currentLeftDistortionData); + ImageData rightImage = new ImageData(Image.CameraType.RIGHT, imageMsg.rightImage, _currentRightDistortionData); + Image stereoImage = new Image(imageMsg.info.frame_id, imageMsg.info.timestamp, leftImage, rightImage); + LeapImage.DispatchOnContext(this, EventContext, new ImageEventArgs(stereoImage)); + } + } + + private void handlePolicyChange(ref LEAP_POLICY_EVENT policyMsg) + { + if (LeapPolicyChange != null) + { + LeapPolicyChange.DispatchOnContext(this, EventContext, new PolicyEventArgs(policyMsg.current_policy, _activePolicies)); + } + + _activePolicies = policyMsg.current_policy; + } + + public void SetAndClearPolicy(Controller.PolicyFlag set, Controller.PolicyFlag clear) + { + UInt64 setFlags = (ulong)FlagForPolicy(set); + UInt64 clearFlags = (ulong)FlagForPolicy(clear); + eLeapRS result = LeapC.SetPolicyFlags(_leapConnection, setFlags, clearFlags); + reportAbnormalResults("LeapC SetAndClearPolicy call was ", result); + } + + public void SetPolicy(Controller.PolicyFlag policy) + { + UInt64 setFlags = (ulong)FlagForPolicy(policy); + eLeapRS result = LeapC.SetPolicyFlags(_leapConnection, setFlags, 0); + reportAbnormalResults("LeapC SetPolicyFlags call was ", result); + } + + public void ClearPolicy(Controller.PolicyFlag policy) + { + UInt64 clearFlags = (ulong)FlagForPolicy(policy); + eLeapRS result = LeapC.SetPolicyFlags(_leapConnection, 0, clearFlags); + reportAbnormalResults("LeapC SetPolicyFlags call was ", result); + } + + static public eLeapPolicyFlag FlagForPolicy(Controller.PolicyFlag singlePolicy) + { + switch (singlePolicy) + { + case Controller.PolicyFlag.POLICY_BACKGROUND_FRAMES: + return eLeapPolicyFlag.eLeapPolicyFlag_BackgroundFrames; + case Controller.PolicyFlag.POLICY_IMAGES: + return eLeapPolicyFlag.eLeapPolicyFlag_Images; + case Controller.PolicyFlag.POLICY_OPTIMIZE_HMD: + return eLeapPolicyFlag.eLeapPolicyFlag_OptimizeHMD; + case Controller.PolicyFlag.POLICY_ALLOW_PAUSE_RESUME: + return eLeapPolicyFlag.eLeapPolicyFlag_AllowPauseResume; + case Controller.PolicyFlag.POLICY_MAP_POINTS: + return eLeapPolicyFlag.eLeapPolicyFlag_MapPoints; + case Controller.PolicyFlag.POLICY_OPTIMIZE_SCREENTOP: + return eLeapPolicyFlag.eLeapPolicyFlag_ScreenTop; + case Controller.PolicyFlag.POLICY_DEFAULT: + return 0; + default: + return 0; + } + } + + /// + /// Gets the active setting for a specific policy. + /// + /// Keep in mind that setting a policy flag is asynchronous, so changes are + /// not effective immediately after calling setPolicyFlag(). In addition, a + /// policy request can be declined by the user. You should always set the + /// policy flags required by your application at startup and check that the + /// policy change request was successful after an appropriate interval. + /// + /// If the controller object is not connected to the Leap Motion software, then the default + /// state for the selected policy is returned. + /// + /// + /// @since 2.1.6 + /// + public bool IsPolicySet(Controller.PolicyFlag policy) + { + UInt64 policyToCheck = (ulong)FlagForPolicy(policy); + return (_activePolicies & policyToCheck) == policyToCheck; + } + + public uint GetConfigValue(string config_key) + { + uint requestId = 0; + eLeapRS result = LeapC.RequestConfigValue(_leapConnection, config_key, out requestId); + reportAbnormalResults("LeapC RequestConfigValue call was ", result); + _configRequests[requestId] = config_key; + return requestId; + } + + public uint SetConfigValue(string config_key, T value) where T : IConvertible + { + uint requestId = 0; + eLeapRS result; + Type dataType = value.GetType(); + if (dataType == typeof(bool)) + { + result = LeapC.SaveConfigValue(_leapConnection, config_key, Convert.ToBoolean(value), out requestId); + } + else if (dataType == typeof(Int32)) + { + result = LeapC.SaveConfigValue(_leapConnection, config_key, Convert.ToInt32(value), out requestId); + } + else if (dataType == typeof(float)) + { + result = LeapC.SaveConfigValue(_leapConnection, config_key, Convert.ToSingle(value), out requestId); + } + else if (dataType == typeof(string)) + { + result = LeapC.SaveConfigValue(_leapConnection, config_key, Convert.ToString(value), out requestId); + } + else + { + throw new ArgumentException("Only boolean, Int32, float, and string types are supported."); + } + reportAbnormalResults("LeapC SaveConfigValue call was ", result); + _configRequests[requestId] = config_key; + return requestId; + } + + /// + /// Reports whether your application has a connection to the Leap Motion + /// daemon/service. Can be true even if the Leap Motion hardware is not available. + /// @since 1.2 + /// + public bool IsServiceConnected + { + get + { + if (_leapConnection == IntPtr.Zero) + return false; + + LEAP_CONNECTION_INFO pInfo = new LEAP_CONNECTION_INFO(); + pInfo.size = (uint)Marshal.SizeOf(pInfo); + eLeapRS result = LeapC.GetConnectionInfo(_leapConnection, ref pInfo); + reportAbnormalResults("LeapC GetConnectionInfo call was ", result); + + if (pInfo.status == eLeapConnectionStatus.eLeapConnectionStatus_Connected) + return true; + + return false; + } + } + + /// + /// The list of currently attached and recognized Leap Motion controller devices. + /// + /// The Device objects in the list describe information such as the range and + /// tracking volume. + /// + /// + /// Currently, the Leap Motion Controller only allows a single active device at a time, + /// however there may be multiple devices physically attached and listed here. Any active + /// device(s) are guaranteed to be listed first, however order is not determined beyond that. + /// + /// @since 1.0 + /// + public DeviceList Devices + { + get + { + if (_devices == null) + { + _devices = new DeviceList(); + } + + return _devices; + } + } + + public FailedDeviceList FailedDevices + { + get + { + if (_failedDevices == null) + { + _failedDevices = new FailedDeviceList(); + } + + return _failedDevices; + } + } + + public Vector PixelToRectilinear(Image.CameraType camera, Vector pixel) + { + LEAP_VECTOR pixelStruct = new LEAP_VECTOR(pixel); + LEAP_VECTOR ray = LeapC.LeapPixelToRectilinear(_leapConnection, + (camera == Image.CameraType.LEFT ? + eLeapPerspectiveType.eLeapPerspectiveType_stereo_left : + eLeapPerspectiveType.eLeapPerspectiveType_stereo_right), + pixelStruct); + return new Vector(ray.x, ray.y, ray.z); + } + + public Vector RectilinearToPixel(Image.CameraType camera, Vector ray) + { + LEAP_VECTOR rayStruct = new LEAP_VECTOR(ray); + LEAP_VECTOR pixel = LeapC.LeapRectilinearToPixel(_leapConnection, + (camera == Image.CameraType.LEFT ? + eLeapPerspectiveType.eLeapPerspectiveType_stereo_left : + eLeapPerspectiveType.eLeapPerspectiveType_stereo_right), + rayStruct); + return new Vector(pixel.x, pixel.y, pixel.z); + } + + public void TelemetryProfiling(ref LEAP_TELEMETRY_DATA telemetryData) + { + eLeapRS result = LeapC.LeapTelemetryProfiling(_leapConnection, ref telemetryData); + reportAbnormalResults("LeapC TelemetryProfiling call was ", result); + } + + public void GetPointMapping(ref PointMapping pm) + { + UInt64 size = 0; + IntPtr buffer = IntPtr.Zero; + while (true) + { + eLeapRS result = LeapC.GetPointMapping(_leapConnection, buffer, ref size); + if (result == eLeapRS.eLeapRS_InsufficientBuffer) + { + if (buffer != IntPtr.Zero) + Marshal.FreeHGlobal(buffer); + buffer = Marshal.AllocHGlobal((Int32)size); + continue; + } + reportAbnormalResults("LeapC get point mapping call was ", result); + if (result != eLeapRS.eLeapRS_Success) + { + pm.points = null; + pm.ids = null; + return; + } + break; + } + LEAP_POINT_MAPPING pmi; + StructMarshal.PtrToStruct(buffer, out pmi); + Int32 nPoints = (Int32)pmi.nPoints; + + pm.frameId = pmi.frame_id; + pm.timestamp = pmi.timestamp; + pm.points = new Vector[nPoints]; + pm.ids = new UInt32[nPoints]; + + float[] points = new float[3 * nPoints]; + Int32[] ids = new Int32[nPoints]; + Marshal.Copy(pmi.points, points, 0, 3 * nPoints); + Marshal.Copy(pmi.ids, ids, 0, nPoints); + + int j = 0; + for (int i = 0; i < nPoints; i++) + { + pm.points[i].x = points[j++]; + pm.points[i].y = points[j++]; + pm.points[i].z = points[j++]; + pm.ids[i] = unchecked((UInt32)ids[i]); + } + Marshal.FreeHGlobal(buffer); + } + + private eLeapRS _lastResult; //Used to avoid repeating the same log message, ie. for events like time out + private void reportAbnormalResults(string context, eLeapRS result) + { + if (result != eLeapRS.eLeapRS_Success && + result != _lastResult) + { + string msg = context + " " + result; + if (LeapLogEvent != null) + { + LeapLogEvent.DispatchOnContext(this, EventContext, + new LogEventArgs(MessageSeverity.MESSAGE_CRITICAL, + LeapC.GetNow(), + msg)); + } + } + _lastResult = result; + } + } +} diff --git a/vendor/LeapCSharp/Controller.cs b/vendor/LeapCSharp/Controller.cs new file mode 100644 index 00000000..fa8357b1 --- /dev/null +++ b/vendor/LeapCSharp/Controller.cs @@ -0,0 +1,837 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using LeapInternal; + using System; + using System.Threading; + + /// + /// The Controller class is your main interface to the Leap Motion Controller. + /// + /// Create an instance of this Controller class to access frames of tracking + /// data and configuration information.Frame data can be polled at any time + /// using the Controller.Frame() function.Call frame() or frame(0) to get the + /// most recent frame.Set the history parameter to a positive integer to access + /// previous frames.A controller stores up to 60 frames in its frame history. + /// + /// + /// Polling is an appropriate strategy for applications which already have an + /// intrinsic update loop, such as a game. You can also subscribe to the FrameReady + /// event to get tracking frames through an event delegate. + /// + /// If the current thread implements a SynchronizationContext that contains a message + /// loop, events are posted to that threads message loop. Otherwise, events are called + /// on an independent thread and applications must perform any needed synchronization + /// or marshalling of data between threads. Note that Unity3D does not create an + /// appropriate SynchronizationContext object. Typically, event handlers cannot access + /// any Unity objects. + /// + /// @since 1.0 + /// + public class Controller : + IController + { + Connection _connection; + bool _disposed = false; + Config _config; + + /// + /// The SynchronizationContext used for dispatching events. + /// + /// By default the synchronization context of the thread creating the controller + /// instance is used. You can change the context if desired. + /// + public SynchronizationContext EventContext + { + get + { + return _connection.EventContext; + } + set + { + _connection.EventContext = value; + } + } + + /// + /// Dispatched when the connection is initialized (but not necessarily connected). + /// + /// Can be dispatched more than once, if connection is restarted. + /// @since 3.0 + /// + public event EventHandler Init + { + add + { + if (_hasInitialized) + value(this, new LeapEventArgs(LeapEvent.EVENT_INIT)); + _init += value; + } + remove { _init -= value; } + } + + private bool _hasInitialized = false; + private EventHandler _init; + + /// + /// Dispatched when the connection to the service is established. + /// @since 3.0 + /// + public event EventHandler Connect + { + add + { + _connection.LeapConnection += value; + } + remove + { + _connection.LeapConnection -= value; + } + } + + private bool _hasConnected = false; + private EventHandler _connect; + + /// + /// Dispatched if the connection to the service is lost. + /// @since 3.0 + /// + public event EventHandler Disconnect + { + add + { + _connection.LeapConnectionLost += value; + } + remove + { + _connection.LeapConnectionLost -= value; + } + } + + /// + /// Dispatched when a tracking frame is ready. + /// @since 3.0 + /// + public event EventHandler FrameReady + { + add + { + _connection.LeapFrame += value; + } + remove + { + _connection.LeapFrame -= value; + } + } + + /// + /// Dispatched when an internal tracking frame is ready. + /// @since 3.0 + /// + public event EventHandler InternalFrameReady + { + add + { + _connection.LeapInternalFrame += value; + } + remove + { + _connection.LeapInternalFrame -= value; + } + } + + /// + /// Dispatched when a Leap Motion device is connected. + /// @since 3.0 + /// + public event EventHandler Device + { + add + { + _connection.LeapDevice += value; + } + remove + { + _connection.LeapDevice -= value; + } + } + + /// + /// Dispatched when a Leap Motion device is disconnected. + /// @since 3.0 + /// + public event EventHandler DeviceLost + { + add + { + _connection.LeapDeviceLost += value; + } + remove + { + _connection.LeapDeviceLost -= value; + } + } + + /// + /// Dispatched when a Leap device fails to initialize. + /// @since 3.0 + /// + public event EventHandler DeviceFailure + { + add + { + _connection.LeapDeviceFailure += value; + } + remove + { + _connection.LeapDeviceFailure -= value; + } + } + + /// + /// Dispatched when the system generates a loggable event. + /// @since 3.0 + /// + public event EventHandler LogMessage + { + add + { + _connection.LeapLogEvent += value; + } + remove + { + _connection.LeapLogEvent -= value; + } + } + + /// + /// Dispatched when a policy changes. + /// @since 3.0 + /// + public event EventHandler PolicyChange + { + add + { + _connection.LeapPolicyChange += value; + } + remove + { + _connection.LeapPolicyChange -= value; + } + } + + /// + /// Dispatched when a configuration setting changes. + /// @since 3.0 + /// + public event EventHandler ConfigChange + { + add + { + _connection.LeapConfigChange += value; + } + remove + { + _connection.LeapConfigChange -= value; + } + } + + /// + /// Dispatched when the image distortion map changes. + /// The distortion map can change when the Leap device switches orientation, + /// or a new device becomes active. + /// @since 3.0 + /// + public event EventHandler DistortionChange + { + add + { + _connection.LeapDistortionChange += value; + } + remove + { + _connection.LeapDistortionChange -= value; + } + } + + /// + /// Dispatched when the service drops a tracking frame. + /// + public event EventHandler DroppedFrame + { + add + { + _connection.LeapDroppedFrame += value; + } + remove + { + _connection.LeapDroppedFrame -= value; + } + } + + /// + /// Dispatched when an unrequested image is ready. + /// @since 4.0 + /// + public event EventHandler ImageReady + { + add + { + _connection.LeapImage += value; + } + remove + { + _connection.LeapImage -= value; + } + } + + /// + /// Dispatched whenever a thread wants to start profiling for a custom thread. + /// The event is always dispatched from the thread itself. + /// + /// The event data will contain the name of the thread, as well as an array of + /// all possible profiling blocks that could be entered on that thread. + /// + /// @since 4.0 + /// + public event Action BeginProfilingForThread + { + add + { + _connection.LeapBeginProfilingForThread += value; + } + remove + { + _connection.LeapBeginProfilingForThread -= value; + } + } + + /// + /// Dispatched whenever a thread is finished profiling. The event is always + /// dispatched from the thread itself. + /// + /// @since 4.0 + /// + public event Action EndProfilingForThread + { + add + { + _connection.LeapEndProfilingForThread += value; + } + remove + { + _connection.LeapEndProfilingForThread -= value; + } + } + + /// + /// Dispatched whenever a thread enters a profiling block. The event is always + /// dispatched from the thread itself. + /// + /// The event data will contain the name of the profiling block. + /// + /// @since 4.0 + /// + public event Action BeginProfilingBlock + { + add + { + _connection.LeapBeginProfilingBlock += value; + } + remove + { + _connection.LeapBeginProfilingBlock -= value; + } + } + + /// + /// Dispatched whenever a thread ends a profiling block. The event is always + /// dispatched from the thread itself. + /// + /// The event data will contain the name of the profiling block. + /// + /// @since 4.0 + /// + public event Action EndProfilingBlock + { + add + { + _connection.LeapEndProfilingBlock += value; + } + remove + { + _connection.LeapEndProfilingBlock -= value; + } + } + + /// + /// Dispatched when point mapping change events are generated by the service. + /// @since 4.0 + /// + public event EventHandler PointMappingChange + { + add + { + _connection.LeapPointMappingChange += value; + } + remove + { + _connection.LeapPointMappingChange -= value; + } + } + + /// + /// Dispatched when a new HeadPose is available. + /// + public event EventHandler HeadPoseChange + { + add + { + _connection.LeapHeadPoseChange += value; + } + remove + { + _connection.LeapHeadPoseChange -= value; + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + // Protected implementation of Dispose pattern. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + _connection.Dispose(); + _disposed = true; + } + + /// + /// Constructs a Controller object. + /// + /// The default constructor uses a connection key of 0. + /// + /// @since 1.0 + /// + public Controller() : this(0, null) { } + + /// + /// Constructs a Controller object using the specified connection key. + /// + /// All controller instances using the same key will use the same connection + /// to the service. In general, an application should not use more than one connection + /// for all its controllers. Each connection keeps its own cache of frames and images. + /// + /// @param connectionKey An identifier specifying the connection to use. If a + /// connection with the specified key already exists, that connection is used. + /// Otherwise, a new connection is created. + /// @since 3.0 + /// + public Controller(int connectionKey, string serverNamespace = null) + { + _connection = Connection.GetConnection(new Connection.Key(connectionKey, serverNamespace)); + _connection.EventContext = SynchronizationContext.Current; + + _connection.LeapInit += OnInit; + _connection.LeapConnection += OnConnect; + _connection.LeapConnectionLost += OnDisconnect; + + _connection.Start(); + } + + /// + /// Starts the connection. + /// + /// A connection starts automatically when created, but you can + /// use this function to restart the connection after stopping it. + /// + /// @since 3.0 + /// + public void StartConnection() + { + _connection.Start(); + } + + /// + /// Stops the connection. + /// + /// No more frames or other events are received from a stopped connection. You can + /// restart with StartConnection(). + /// + /// @since 3.0 + /// + public void StopConnection() + { + _connection.Stop(); + } + + /// + /// Reports whether your application has a connection to the Leap Motion + /// daemon/service. Can be true even if the Leap Motion hardware is not available. + /// @since 1.2 + /// + public bool IsServiceConnected + { + get + { + return _connection.IsServiceConnected; + } + } + + /// + /// Requests setting a policy. + /// + /// A request to change a policy is subject to user approval and a policy + /// can be changed by the user at any time (using the Leap Motion settings dialog). + /// The desired policy flags must be set every time an application runs. + /// + /// Policy changes are completed asynchronously and, because they are subject + /// to user approval or system compatibility checks, may not complete successfully. Call + /// Controller.IsPolicySet() after a suitable interval to test whether + /// the change was accepted. + /// @since 2.1.6 + /// + public void SetAndClearPolicy(PolicyFlag set, PolicyFlag clear) + { + _connection.SetAndClearPolicy(set, clear); + } + public void SetPolicy(PolicyFlag policy) + { + _connection.SetPolicy(policy); + } + + /// + /// Requests clearing a policy. + /// + /// Policy changes are completed asynchronously and, because they are subject + /// to user approval or system compatibility checks, may not complete successfully. Call + /// Controller.IsPolicySet() after a suitable interval to test whether + /// the change was accepted. + /// @since 2.1.6 + /// + public void ClearPolicy(PolicyFlag policy) + { + _connection.ClearPolicy(policy); + } + + /// + /// Gets the active setting for a specific policy. + /// + /// Keep in mind that setting a policy flag is asynchronous, so changes are + /// not effective immediately after calling setPolicyFlag(). In addition, a + /// policy request can be declined by the user. You should always set the + /// policy flags required by your application at startup and check that the + /// policy change request was successful after an appropriate interval. + /// + /// If the controller object is not connected to the Leap Motion software, then the default + /// state for the selected policy is returned. + /// + /// @since 2.1.6 + /// + public bool IsPolicySet(PolicyFlag policy) + { + return _connection.IsPolicySet(policy); + } + + /// + /// In most cases you should get Frame objects using the LeapProvider.CurrentFrame + /// property. The data in Frame objects taken directly from a Leap.Controller instance + /// is still in the Leap Motion frame of reference and will not match the hands + /// displayed in a Unity scene. + /// + /// Returns a frame of tracking data from the Leap Motion software. Use the optional + /// history parameter to specify which frame to retrieve. Call frame() or + /// frame(0) to access the most recent frame; call frame(1) to access the + /// previous frame, and so on. If you use a history value greater than the + /// number of stored frames, then the controller returns an empty frame. + /// + /// @param history The age of the frame to return, counting backwards from + /// the most recent frame (0) into the past and up to the maximum age (59). + /// @returns The specified frame; or, if no history parameter is specified, + /// the newest frame. If a frame is not available at the specified history + /// position, an invalid Frame is returned. + /// @since 1.0 + /// + public Frame Frame(int history = 0) + { + Frame frame = new Frame(); + Frame(frame, history); + return frame; + } + + /// + /// Identical to Frame(history) but instead of constructing a new frame and returning + /// it, the user provides a frame object to be filled with data instead. + /// + public void Frame(Frame toFill, int history = 0) + { + LEAP_TRACKING_EVENT trackingEvent; + _connection.Frames.Get(out trackingEvent, history); + toFill.CopyFrom(ref trackingEvent); + } + + /// + /// Returns the timestamp of a recent tracking frame. Use the + /// optional history parameter to specify how many frames in the past + /// to retrieve the timestamp. Leave the history parameter as + /// it's default value to return the timestamp of the most recent + /// tracked frame. + /// + public long FrameTimestamp(int history = 0) + { + LEAP_TRACKING_EVENT trackingEvent; + _connection.Frames.Get(out trackingEvent, history); + return trackingEvent.info.timestamp; + } + + /// + /// Returns the frame object with all hands transformed by the specified + /// transform matrix. + /// + public Frame GetTransformedFrame(LeapTransform trs, int history = 0) + { + return new Frame().CopyFrom(Frame(history)).Transform(trs); + } + + /// + /// Returns the Frame at the specified time, interpolating the data between existing frames, if necessary. + /// + public Frame GetInterpolatedFrame(Int64 time) + { + return _connection.GetInterpolatedFrame(time); + } + + /// + /// Fills the Frame with data taken at the specified time, interpolating the data between existing frames, if necessary. + /// + public void GetInterpolatedFrame(Frame toFill, Int64 time) + { + _connection.GetInterpolatedFrame(toFill, time); + } + + /// + /// Returns the Head pose at the specified time, interpolating the data between existing frames, if necessary. + /// + public LEAP_HEAD_POSE_EVENT GetInterpolatedHeadPose(Int64 time) + { + return _connection.GetInterpolatedHeadPose(time); + } + + public void GetInterpolatedHeadPose(ref LEAP_HEAD_POSE_EVENT toFill, Int64 time) + { + _connection.GetInterpolatedHeadPose(ref toFill, time); + } + + public void TelemetryProfiling(ref LEAP_TELEMETRY_DATA telemetryData) + { + _connection.TelemetryProfiling(ref telemetryData); + } + + public UInt64 TelemetryGetNow() + { + return LeapC.TelemetryGetNow(); + } + + public void GetPointMapping(ref PointMapping pointMapping) + { + _connection.GetPointMapping(ref pointMapping); + } + + /// + /// This is a special variant of GetInterpolatedFrameFromTime, for use with special + /// features that only require the position and orientation of the palm positions, and do + /// not care about pose data or any other data. + /// + /// You must specify the id of the hand that you wish to get a transform for. If you specify + /// an id that is not present in the interpolated frame, the output transform will be the + /// identity transform. + /// + public void GetInterpolatedLeftRightTransform(Int64 time, + Int64 sourceTime, + int leftId, + int rightId, + out LeapTransform leftTransform, + out LeapTransform rightTransform) + { + _connection.GetInterpolatedLeftRightTransform(time, sourceTime, leftId, rightId, out leftTransform, out rightTransform); + } + + public void GetInterpolatedFrameFromTime(Frame toFill, Int64 time, Int64 sourceTime) + { + _connection.GetInterpolatedFrameFromTime(toFill, time, sourceTime); + } + + /// + /// Returns a timestamp value as close as possible to the current time. + /// Values are in microseconds, as with all the other timestamp values. + /// + /// @since 2.2.7 + /// + public long Now() + { + return LeapC.GetNow(); + } + + /// + /// Reports whether this Controller is connected to the Leap Motion service and + /// the Leap Motion hardware is plugged in. + /// + /// When you first create a Controller object, isConnected() returns false. + /// After the controller finishes initializing and connects to the Leap Motion + /// software and if the Leap Motion hardware is plugged in, isConnected() returns true. + /// + /// You can either handle the onConnect event using a Listener instance or + /// poll the isConnected() function if you need to wait for your + /// application to be connected to the Leap Motion software before performing some other + /// operation. + /// + /// @since 1.0 + /// + public bool IsConnected + { + get + { + return IsServiceConnected && Devices.Count > 0; + } + } + + /// + /// Returns a Config object, which you can use to query the Leap Motion system for + /// configuration information. + /// + /// @since 1.0 + /// + public Config Config + { + get + { + if (_config == null) + _config = new Config(this._connection.ConnectionKey); + return _config; + } + } + + /// + /// The list of currently attached and recognized Leap Motion controller devices. + /// + /// The Device objects in the list describe information such as the range and + /// tracking volume. + /// + /// Currently, the Leap Motion Controller only allows a single active device at a time, + /// however there may be multiple devices physically attached and listed here. Any active + /// device(s) are guaranteed to be listed first, however order is not determined beyond that. + /// + /// @since 1.0 + /// + public DeviceList Devices + { + get + { + return _connection.Devices; + } + } + + /// + /// A list of any Leap Motion hardware devices that are physically connected to + /// the client computer, but are not functioning correctly. The list contains + /// FailedDevice objects containing the pnpID and the reason for failure. No + /// other device information is available. + /// + /// @since 3.0 + /// + public FailedDeviceList FailedDevices() + { + return _connection.FailedDevices; + } + + /// + /// The supported controller policies. + /// + /// The supported policy flags are: + /// + /// **POLICY_BACKGROUND_FRAMES** -- requests that your application receives frames + /// when it is not the foreground application for user input. + /// + /// The background frames policy determines whether an application + /// receives frames of tracking data while in the background. By + /// default, the Leap Motion software only sends tracking data to the foreground application. + /// Only applications that need this ability should request the background + /// frames policy. The "Allow Background Apps" checkbox must be enabled in the + /// Leap Motion Control Panel or this policy will be denied. + /// + /// **POLICY_OPTIMIZE_HMD** -- request that the tracking be optimized for head-mounted + /// tracking. + /// + /// The optimize HMD policy improves tracking in situations where the Leap + /// Motion hardware is attached to a head-mounted display. This policy is + /// not granted for devices that cannot be mounted to an HMD, such as + /// Leap Motion controllers embedded in a laptop or keyboard. + /// + /// Some policies can be denied if the user has disabled the feature on + /// their Leap Motion control panel. + /// + /// @since 1.0 + /// + public enum PolicyFlag + { + /// + /// The default policy. + /// + POLICY_DEFAULT = 0, + /// + /// Receive background frames. + /// + POLICY_BACKGROUND_FRAMES = (1 << 0), + /// + /// Allow streaming images. + /// + POLICY_IMAGES = (1 << 1), + /// + /// Optimize the tracking for head-mounted device. + /// + POLICY_OPTIMIZE_HMD = (1 << 2), + /// + /// Allow pausing and unpausing of the Leap Motion service. + /// + POLICY_ALLOW_PAUSE_RESUME = (1 << 3), + /// + /// Allow streaming map point + /// + POLICY_MAP_POINTS = (1 << 7), + /// + /// Optimize the tracking for screen-top device. + /// @since 5.0.0 + /// + POLICY_OPTIMIZE_SCREENTOP = (1 << 8), + } + + protected virtual void OnInit(object sender, LeapEventArgs eventArgs) + { + _hasInitialized = true; + } + + protected virtual void OnConnect(object sender, ConnectionEventArgs eventArgs) + { + _hasConnected = true; + } + + protected virtual void OnDisconnect(object sender, ConnectionLostEventArgs eventArgs) + { + _hasInitialized = false; + _hasConnected = false; + } + } +} diff --git a/vendor/LeapCSharp/CopyFromLeapCExtensions.cs b/vendor/LeapCSharp/CopyFromLeapCExtensions.cs new file mode 100644 index 00000000..194a6e67 --- /dev/null +++ b/vendor/LeapCSharp/CopyFromLeapCExtensions.cs @@ -0,0 +1,142 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace LeapInternal +{ + using Leap; + + public static class CopyFromLeapCExtensions + { + + /** + * Copies the data from an internal tracking message into a frame. + * + * @param trackingMsg The internal tracking message with the data to be copied into this frame. + */ + public static Frame CopyFrom(this Frame frame, ref LEAP_TRACKING_EVENT trackingMsg) + { + frame.Id = (long)trackingMsg.info.frame_id; + frame.Timestamp = (long)trackingMsg.info.timestamp; + frame.CurrentFramesPerSecond = trackingMsg.framerate; + + frame.ResizeHandList((int)trackingMsg.nHands); + + for (int i = frame.Hands.Count; i-- != 0;) + { + LEAP_HAND hand; + StructMarshal.ArrayElementToStruct(trackingMsg.pHands, i, out hand); + frame.Hands[i].CopyFrom(ref hand, frame.Id); + } + + return frame; + } + + /** + * Copies the data from an internal hand definition into a hand. + * + * @param leapHand The internal hand definition to be copied into this hand. + * @param frameId The frame id of the frame this hand belongs to. + */ + public static Hand CopyFrom(this Hand hand, ref LEAP_HAND leapHand, long frameId) + { + hand.FrameId = frameId; + hand.Id = (int)leapHand.id; + + hand.Arm.CopyFrom(leapHand.arm, Bone.BoneType.TYPE_INVALID); + + hand.Confidence = leapHand.confidence; + hand.GrabStrength = leapHand.grab_strength; + hand.GrabAngle = leapHand.grab_angle; + hand.PinchStrength = leapHand.pinch_strength; + hand.PinchDistance = leapHand.pinch_distance; + hand.PalmWidth = leapHand.palm.width; + hand.IsLeft = leapHand.type == eLeapHandType.eLeapHandType_Left; + hand.TimeVisible = (float)(leapHand.visible_time * 1e-6); + hand.PalmPosition = leapHand.palm.position.ToLeapVector(); + hand.StabilizedPalmPosition = leapHand.palm.stabilized_position.ToLeapVector(); + hand.PalmVelocity = leapHand.palm.velocity.ToLeapVector(); + hand.PalmNormal = leapHand.palm.normal.ToLeapVector(); + hand.Rotation = leapHand.palm.orientation.ToLeapQuaternion(); + hand.Direction = leapHand.palm.direction.ToLeapVector(); + hand.WristPosition = hand.Arm.NextJoint; + + hand.Fingers[0].CopyFrom(leapHand.thumb, Leap.Finger.FingerType.TYPE_THUMB, hand.Id, hand.TimeVisible); + hand.Fingers[1].CopyFrom(leapHand.index, Leap.Finger.FingerType.TYPE_INDEX, hand.Id, hand.TimeVisible); + hand.Fingers[2].CopyFrom(leapHand.middle, Leap.Finger.FingerType.TYPE_MIDDLE, hand.Id, hand.TimeVisible); + hand.Fingers[3].CopyFrom(leapHand.ring, Leap.Finger.FingerType.TYPE_RING, hand.Id, hand.TimeVisible); + hand.Fingers[4].CopyFrom(leapHand.pinky, Leap.Finger.FingerType.TYPE_PINKY, hand.Id, hand.TimeVisible); + + return hand; + } + + /** + * Copies the data from an internal finger definition into a finger. + * + * @param leapBone The internal finger definition to be copied into this finger. + * @param type The finger type of this finger. + * @param frameId The frame id of the frame this finger belongs to. + * @param handId The hand id of the hand this finger belongs to. + * @param timeVisible The time in seconds that this finger has been visible. + */ + public static Finger CopyFrom(this Finger finger, LEAP_DIGIT leapBone, Finger.FingerType type, int handId, float timeVisible) + { + finger.Id = (handId * 10) + leapBone.finger_id; + finger.HandId = handId; + finger.TimeVisible = timeVisible; + + Bone metacarpal = finger.bones[0]; + Bone proximal = finger.bones[1]; + Bone intermediate = finger.bones[2]; + Bone distal = finger.bones[3]; + + metacarpal.CopyFrom(leapBone.metacarpal, Leap.Bone.BoneType.TYPE_METACARPAL); + proximal.CopyFrom(leapBone.proximal, Leap.Bone.BoneType.TYPE_PROXIMAL); + intermediate.CopyFrom(leapBone.intermediate, Leap.Bone.BoneType.TYPE_INTERMEDIATE); + distal.CopyFrom(leapBone.distal, Leap.Bone.BoneType.TYPE_DISTAL); + + finger.TipPosition = distal.NextJoint; + finger.Direction = intermediate.Direction; + finger.Width = intermediate.Width; + finger.Length = (leapBone.finger_id == 0 ? 0.0f : 0.5f * proximal.Length) + intermediate.Length + 0.77f * distal.Length; //The values 0.5 for proximal and 0.77 for distal are used in platform code for this calculation + finger.IsExtended = leapBone.is_extended != 0; + finger.Type = type; + + return finger; + } + + /** + * Copies the data from an internal bone definition into a bone. + * + * @param leapBone The internal bone definition to be copied into this bone. + * @param type The bone type of this bone. + */ + public static Bone CopyFrom(this Bone bone, LEAP_BONE leapBone, Bone.BoneType type) + { + bone.Type = type; + bone.PrevJoint = leapBone.prev_joint.ToLeapVector(); + bone.NextJoint = leapBone.next_joint.ToLeapVector(); + bone.Direction = (bone.NextJoint - bone.PrevJoint); + bone.Length = bone.Direction.Magnitude; + + if (bone.Length < float.Epsilon) + { + bone.Direction = Vector.Zero; + } + else + { + bone.Direction /= bone.Length; + } + + bone.Center = (bone.PrevJoint + bone.NextJoint) / 2.0f; + bone.Rotation = leapBone.rotation.ToLeapQuaternion(); + bone.Width = leapBone.width; + + return bone; + } + } +} diff --git a/vendor/LeapCSharp/CopyFromOtherExtensions.cs b/vendor/LeapCSharp/CopyFromOtherExtensions.cs new file mode 100644 index 00000000..26fc137e --- /dev/null +++ b/vendor/LeapCSharp/CopyFromOtherExtensions.cs @@ -0,0 +1,119 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + + public static class CopyFromOtherExtensions + { + + /** + * Copies the data from a source frame into a frame. After the operation is + * complete, the frame will be identical to the source frame. + * + * @param source The source frame that is copied into a frame. + */ + public static Frame CopyFrom(this Frame frame, Frame source) + { + frame.Id = source.Id; + frame.Timestamp = source.Timestamp; + frame.CurrentFramesPerSecond = source.CurrentFramesPerSecond; + + frame.ResizeHandList(source.Hands.Count); + + for (int i = frame.Hands.Count; i-- != 0;) + { + frame.Hands[i].CopyFrom(source.Hands[i]); + } + + return frame; + } + + /* + * Copies the data from a source hand into a hand. After the operation is + * complete, the hand will be identical to the source hand. + * + * @param source The source hand that is copied into a hand. + */ + public static Hand CopyFrom(this Hand hand, Hand source) + { + hand.Id = source.Id; + hand.Confidence = source.Confidence; + hand.GrabStrength = source.GrabStrength; + hand.GrabAngle = source.GrabAngle; + hand.Rotation = source.Rotation; + hand.PinchStrength = source.PinchStrength; + hand.PinchDistance = source.PinchDistance; + hand.PalmWidth = source.PalmWidth; + hand.IsLeft = source.IsLeft; + hand.TimeVisible = source.TimeVisible; + hand.PalmPosition = source.PalmPosition; + hand.StabilizedPalmPosition = source.StabilizedPalmPosition; + hand.PalmVelocity = source.PalmVelocity; + hand.PalmNormal = source.PalmNormal; + hand.Direction = source.Direction; + hand.WristPosition = source.WristPosition; + + hand.Arm.CopyFrom(source.Arm); + + for (int i = 5; i-- != 0;) + { + hand.Fingers[i].CopyFrom(source.Fingers[i]); + } + + return hand; + } + + /** + * Copies the data from a source finger into a finger. After the operation is + * complete, the finger will be identical to the source finger. + * + * @param source The source finger that is copied into a finger. + */ + public static Finger CopyFrom(this Finger finger, Finger source) + { + for (int i = 4; i-- != 0;) + { + finger.bones[i].CopyFrom(source.bones[i]); + } + + finger.Id = source.Id; + finger.HandId = source.HandId; + finger.TimeVisible = source.TimeVisible; + + finger.TipPosition = source.TipPosition; + finger.Direction = source.Direction; + finger.Width = source.Width; + finger.Length = source.Length; + finger.IsExtended = source.IsExtended; + finger.Type = source.Type; + + return finger; + } + + /** + * Copies the data from a source bone into a bone. After the operation is + * complete, the bone will be identical to the source bone. + * + * @param source The source bone that is copied into a bone. + */ + public static Bone CopyFrom(this Bone bone, Bone source) + { + bone.PrevJoint = source.PrevJoint; + bone.NextJoint = source.NextJoint; + bone.Direction = source.Direction; + bone.Center = source.Center; + bone.Length = source.Length; + bone.Width = source.Width; + bone.Rotation = source.Rotation; + bone.Type = source.Type; + + return bone; + } + } +} diff --git a/vendor/LeapCSharp/Device.cs b/vendor/LeapCSharp/Device.cs new file mode 100644 index 00000000..49f77710 --- /dev/null +++ b/vendor/LeapCSharp/Device.cs @@ -0,0 +1,304 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using LeapInternal; + using System; + + /// + /// The Device class represents a physically connected device. + /// + /// The Device class contains information related to a particular connected + /// device such as device id, field of view relative to the device, + /// and the position and orientation of the device in relative coordinates. + /// + /// The position and orientation describe the alignment of the device relative to the user. + /// The alignment relative to the user is only descriptive. Aligning devices to users + /// provides consistency in the parameters that describe user interactions. + /// + /// Note that Device objects can be invalid, which means that they do not contain + /// valid device information and do not correspond to a physical device. + /// @since 1.0 + /// + public class Device : + IEquatable + { + + /// + /// Constructs a default Device object. + /// + /// Get valid Device objects from a DeviceList object obtained using the + /// Controller.Devices() method. + /// + /// @since 1.0 + /// + public Device() { } + + public Device(IntPtr deviceHandle, + IntPtr internalHandle, + float horizontalViewAngle, + float verticalViewAngle, + float range, + float baseline, + DeviceType type, + uint status, + string serialNumber) + { + Handle = deviceHandle; + InternalHandle = internalHandle; + HorizontalViewAngle = horizontalViewAngle; + VerticalViewAngle = verticalViewAngle; + Range = range; + Baseline = baseline; + Type = type; + SerialNumber = serialNumber; + UpdateStatus((eLeapDeviceStatus)status); + } + + /// + /// For internal use only. + /// + public void Update( + float horizontalViewAngle, + float verticalViewAngle, + float range, + float baseline, + uint status, + string serialNumber) + { + HorizontalViewAngle = horizontalViewAngle; + VerticalViewAngle = verticalViewAngle; + Range = range; + Baseline = baseline; + SerialNumber = serialNumber; + UpdateStatus((eLeapDeviceStatus)status); + } + + /// + /// For internal use only. + /// + public void Update(Device updatedDevice) + { + HorizontalViewAngle = updatedDevice.HorizontalViewAngle; + VerticalViewAngle = updatedDevice.VerticalViewAngle; + Range = updatedDevice.Range; + Baseline = updatedDevice.Baseline; + IsStreaming = updatedDevice.IsStreaming; + SerialNumber = updatedDevice.SerialNumber; + } + + /// + /// Updates the status fields by parsing the uint given by the event + /// + internal void UpdateStatus(eLeapDeviceStatus status) + { + if ((status & eLeapDeviceStatus.eLeapDeviceStatus_Streaming) == eLeapDeviceStatus.eLeapDeviceStatus_Streaming) + IsStreaming = true; + else + IsStreaming = false; + if ((status & eLeapDeviceStatus.eLeapDeviceStatus_Smudged) == eLeapDeviceStatus.eLeapDeviceStatus_Smudged) + IsSmudged = true; + else + IsSmudged = false; + if ((status & eLeapDeviceStatus.eLeapDeviceStatus_Robust) == eLeapDeviceStatus.eLeapDeviceStatus_Robust) + IsLightingBad = true; + else + IsLightingBad = false; + if ((status & eLeapDeviceStatus.eLeapDeviceStatus_LowResource) == eLeapDeviceStatus.eLeapDeviceStatus_LowResource) + IsLowResource = true; + else + IsLowResource = false; + } + + /// + /// For internal use only. + /// + public IntPtr Handle { get; private set; } + + private IntPtr InternalHandle; + + public bool SetPaused(bool pause) + { + eLeapRS result = LeapC.LeapSetPause(Handle, pause); + return result == eLeapRS.eLeapRS_Success; + } + + /// + /// Compare Device object equality. + /// + /// Two Device objects are equal if and only if both Device objects represent the + /// exact same Device and both Devices are valid. + /// + /// @since 1.0 + /// + public bool Equals(Device other) + { + return SerialNumber == other.SerialNumber; + } + + /// + /// A string containing a brief, human readable description of the Device object. + /// @since 1.0 + /// + public override string ToString() + { + return "Device serial# " + this.SerialNumber; + } + + /// + /// The angle in radians of view along the x axis of this device. + /// + /// The Leap Motion controller scans a region in the shape of an inverted pyramid + /// centered at the device's center and extending upwards. The horizontalViewAngle + /// reports the view angle along the long dimension of the device. + /// + /// @since 1.0 + /// + public float HorizontalViewAngle { get; private set; } + + /// + /// The angle in radians of view along the z axis of this device. + /// + /// The Leap Motion controller scans a region in the shape of an inverted pyramid + /// centered at the device's center and extending upwards. The verticalViewAngle + /// reports the view angle along the short dimension of the device. + /// + /// @since 1.0 + /// + public float VerticalViewAngle { get; private set; } + + /// + /// The maximum reliable tracking range from the center of this device. + /// + /// The range reports the maximum recommended distance from the device center + /// for which tracking is expected to be reliable. This distance is not a hard limit. + /// Tracking may be still be functional above this distance or begin to degrade slightly + /// before this distance depending on calibration and extreme environmental conditions. + /// + /// @since 1.0 + /// + public float Range { get; private set; } + + /// + /// The distance in mm between the center points of the stereo sensors. + /// + /// The baseline value, together with the maximum resolution, influence the + /// maximum range. + /// + /// @since 2.2.5 + /// + public float Baseline { get; private set; } + + /// + /// Reports whether this device is streaming data to your application. + /// + /// Currently only one controller can provide data at a time. + /// @since 1.2 + /// + public bool IsStreaming { get; internal set; } + + /// + /// The device type. + /// + /// Use the device type value in the (rare) circumstances that you + /// have an application feature which relies on a particular type of device. + /// Current types of device include the original Leap Motion peripheral, + /// keyboard-embedded controllers, and laptop-embedded controllers. + /// + /// @since 1.2 + /// + public DeviceType Type { get; private set; } + + /// + /// An alphanumeric serial number unique to each device. + /// + /// Consumer device serial numbers consist of 2 letters followed by 11 digits. + /// + /// When using multiple devices, the serial number provides an unambiguous + /// identifier for each device. + /// @since 2.2.2 + /// + public string SerialNumber { get; private set; } + + /// + /// Returns the internal status field of the current device + /// + protected uint GetDeviceStatus() + { + eLeapRS result; + + LEAP_DEVICE_INFO deviceInfo = new LEAP_DEVICE_INFO(); + deviceInfo.serial = IntPtr.Zero; + deviceInfo.size = (uint)System.Runtime.InteropServices.Marshal.SizeOf(deviceInfo); + result = LeapC.GetDeviceInfo(InternalHandle, ref deviceInfo); + + if (result != eLeapRS.eLeapRS_Success) + return 0; + uint status = deviceInfo.status; + System.Runtime.InteropServices.Marshal.FreeCoTaskMem(deviceInfo.serial); + return status; + } + + + /// + /// The software has detected a possible smudge on the translucent cover + /// over the Leap Motion cameras. + /// @since 3.0 + /// + public bool IsSmudged { get; internal set; } + + /// + /// The software has entered low-resource mode + /// @since 3.0 + /// + public bool IsLowResource { get; internal set; } + + /// + /// The software has detected excessive IR illumination, which may interfere + /// with tracking. If robust mode is enabled, the system will enter robust mode when + /// isLightingBad() is true. + /// @since 3.0 + /// + public bool IsLightingBad { get; internal set; } + + /// + /// The available types of Leap Motion controllers. + /// + public enum DeviceType + { + TYPE_INVALID = -1, + + /// + /// A standalone USB peripheral. The original Leap Motion controller device. + /// @since 1.2 + /// + TYPE_PERIPHERAL = (int)eLeapDeviceType.eLeapDeviceType_Peripheral, + + /// + /// Internal research product codename "Dragonfly". + /// + TYPE_DRAGONFLY = (int)eLeapDeviceType.eLeapDeviceType_Dragonfly, + + /// + /// Internal research product codename "Nightcrawler". + /// + TYPE_NIGHTCRAWLER = (int)eLeapDeviceType.eLeapDeviceType_Nightcrawler, + + /// + /// Research product codename "Rigel". + /// + TYPE_RIGEL = (int)eLeapDeviceType.eLeapDevicePID_Rigel, + + [Obsolete] + TYPE_LAPTOP, + [Obsolete] + TYPE_KEYBOARD + } + } +} diff --git a/vendor/LeapCSharp/DeviceList.cs b/vendor/LeapCSharp/DeviceList.cs new file mode 100644 index 00000000..eb01ef63 --- /dev/null +++ b/vendor/LeapCSharp/DeviceList.cs @@ -0,0 +1,94 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + using System.Collections.Generic; + + /// + /// The DeviceList class represents a list of Device objects. + /// + /// Get a DeviceList object by calling Controller.Devices(). + /// @since 1.0 + /// + public class DeviceList : + List + { + + /// + /// Constructs an empty list of devices. + /// @since 1.0 + /// + public DeviceList() { } + + /// + /// For internal use only. + /// + public Device FindDeviceByHandle(IntPtr deviceHandle) + { + for (int d = 0; d < this.Count; d++) + { + if (this[d].Handle == deviceHandle) + return this[d]; + } + return null; + } + + /// + /// The device that is currently streaming tracking data. + /// If no streaming devices are found, returns null + /// + public Device ActiveDevice + { + get + { + if (Count == 1) + { + return this[0]; + } + + for (int d = 0; d < Count; d++) + { + this[d].UpdateStatus(LeapInternal.eLeapDeviceStatus.eLeapDeviceStatus_Streaming); + if (this[d].IsStreaming) + { + return this[d]; + } + } + + return null; + } + } + + /// + /// For internal use only. + /// + public void AddOrUpdate(Device device) + { + Device existingDevice = FindDeviceByHandle(device.Handle); + if (existingDevice != null) + { + existingDevice.Update(device); + } + else + { + Add(device); + } + } + + /// + /// Reports whether the list is empty. + /// @since 1.0 + /// + public bool IsEmpty + { + get { return Count == 0; } + } + } +} diff --git a/vendor/LeapCSharp/DistortionData.cs b/vendor/LeapCSharp/DistortionData.cs new file mode 100644 index 00000000..31e25886 --- /dev/null +++ b/vendor/LeapCSharp/DistortionData.cs @@ -0,0 +1,93 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +using System; + +namespace Leap +{ + /// + /// The DistortionData class contains the distortion map for correcting the + /// lens distortion of an image. + /// + /// The distortion data is an array containing a 64x64 grid of floating point pairs. + /// The distortion map for both sides of an image pair are stacked in + /// the Data array -- the left map first, followed by the right map. + /// + /// @since 3.0 + /// + public class DistortionData + { + /// + /// Constructs an uninitialized distortion object. + /// @since 3.0 + /// + public DistortionData() { } + + /// + /// @since 3.0 + /// + public DistortionData(UInt64 version, float width, float height, float[] data) + { + Version = version; + Width = width; + Height = height; + Data = data; + } + /// + /// An identifier assigned to the distortion map. + /// + /// When the distortion map changes -- either because the devices flips the images + /// to automatically orient the hands or because a different device is plugged in, + /// the version number of the distortion data changes. + /// + /// Note that the version always increases. If the images change orientation and then + /// return to their original orientation, a new version number is assigned. Thus + /// the version number can be used to detect when the data has changed, but not + /// to uniquely identify the data. + /// @since 3.0 + /// + public UInt64 Version { get; set; } + /// + /// The width of the distortion map. + /// + /// Currently always 64. Note that there are two floating point values for every point in the map. + /// @since 3.0 + /// + public float Width { get; set; } + /// + /// The height of the distortion map. + /// + /// Currently always 64. + /// @since 3.0 + /// + public float Height { get; set; } + /// + /// The distortion data. + /// + /// @since 3.0 + /// + public float[] Data { get; set; } + /// + /// Reports whether the distortion data is internally consistent. + /// @since 3.0 + /// + public bool IsValid + { + get + { + if (Data != null && + Width == LeapInternal.LeapC.DistortionSize && + Height == LeapInternal.LeapC.DistortionSize && + Data.Length == Width * Height * 2) + return true; + + return false; + } + } + } +} diff --git a/vendor/LeapCSharp/Events.cs b/vendor/LeapCSharp/Events.cs new file mode 100644 index 00000000..ec7a6b94 --- /dev/null +++ b/vendor/LeapCSharp/Events.cs @@ -0,0 +1,323 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using LeapInternal; + using System; + + /// + /// An enumeration defining the types of Leap Motion events. + /// @since 3.0 + /// + public enum LeapEvent + { + EVENT_CONNECTION, //!< A connection event has occurred + EVENT_CONNECTION_LOST, //!< The connection with the service has been lost + EVENT_DEVICE, //!< A device event has occurred + EVENT_DEVICE_FAILURE, //!< A device failure event has occurred + EVENT_DEVICE_LOST, //!< Event asserted when the underlying device object has been lost + EVENT_POLICY_CHANGE, //!< A change in policy occurred + EVENT_CONFIG_RESPONSE, //!< Response to a Config value request + EVENT_CONFIG_CHANGE, //!< Success response to a Config value change + EVENT_FRAME, //!< A tracking frame has been received + EVENT_INTERNAL_FRAME, //!< An internal tracking frame has been received + EVENT_IMAGE_COMPLETE, //!< A requested image is available + EVENT_IMAGE_REQUEST_FAILED, //!< A requested image could not be provided + EVENT_DISTORTION_CHANGE, //!< The distortion matrix used for image correction has changed + EVENT_LOG_EVENT, //!< A diagnostic event has occurred + EVENT_INIT, + EVENT_DROPPED_FRAME, + EVENT_IMAGE, //!< An unrequested image is available + EVENT_POINT_MAPPING_CHANGE, + EVENT_HEAD_POSE + }; + /// + /// A generic object with no arguments beyond the event type. + /// @since 3.0 + /// + public class LeapEventArgs : EventArgs + { + public LeapEventArgs(LeapEvent type) + { + this.type = type; + } + public LeapEvent type { get; set; } + } + + /// + /// Dispatched when a tracking frame is ready. + /// + /// Provides the Frame object as an argument. + /// @since 3.0 + /// + public class FrameEventArgs : LeapEventArgs + { + public FrameEventArgs(Frame frame) : base(LeapEvent.EVENT_FRAME) + { + this.frame = frame; + } + + public Frame frame { get; set; } + } + + public class InternalFrameEventArgs : LeapEventArgs + { + public InternalFrameEventArgs(ref LEAP_TRACKING_EVENT frame) : base(LeapEvent.EVENT_INTERNAL_FRAME) + { + this.frame = frame; + } + + public LEAP_TRACKING_EVENT frame { get; set; } + } + + /// + /// Dispatched when loggable events are generated by the service and the + /// service connection code. + /// + /// Provides the severity rating, log text, and timestamp as arguments. + /// @since 3.0 + /// + public class LogEventArgs : LeapEventArgs + { + public LogEventArgs(MessageSeverity severity, Int64 timestamp, string message) : base(LeapEvent.EVENT_LOG_EVENT) + { + this.severity = severity; + this.message = message; + this.timestamp = timestamp; + } + + public MessageSeverity severity { get; set; } + public Int64 timestamp { get; set; } + public string message { get; set; } + } + + /// + /// Dispatched when a policy change is complete. + /// + /// Provides the current and previous policies as arguments. + /// + /// @since 3.0 + /// + public class PolicyEventArgs : LeapEventArgs + { + public PolicyEventArgs(UInt64 currentPolicies, UInt64 oldPolicies) : base(LeapEvent.EVENT_POLICY_CHANGE) + { + this.currentPolicies = currentPolicies; + this.oldPolicies = oldPolicies; + } + + public UInt64 currentPolicies { get; set; } + public UInt64 oldPolicies { get; set; } + } + + /// + /// Dispatched when the image distortion map changes. + /// + /// Provides the new distortion map as an argument. + /// @since 3.0 + /// + public class DistortionEventArgs : LeapEventArgs + { + public DistortionEventArgs(DistortionData distortion, Image.CameraType camera) : base(LeapEvent.EVENT_DISTORTION_CHANGE) + { + this.distortion = distortion; + this.camera = camera; + } + public DistortionData distortion { get; protected set; } + public Image.CameraType camera { get; protected set; } + } + + /// + /// Dispatched when a configuration change is completed. + /// + /// Provides the configuration key, whether the change was successful, and the id of the original change request. + /// @since 3.0 + /// + public class ConfigChangeEventArgs : LeapEventArgs + { + public ConfigChangeEventArgs(string config_key, bool succeeded, uint requestId) : base(LeapEvent.EVENT_CONFIG_CHANGE) + { + this.ConfigKey = config_key; + this.Succeeded = succeeded; + this.RequestId = requestId; + } + public string ConfigKey { get; set; } + public bool Succeeded { get; set; } + public uint RequestId { get; set; } + + } + + /// + /// Dispatched when a configuration change is completed. + /// + /// Provides the configuration key, whether the change was successful, and the id of the original change request. + /// @since 3.0 + /// + public class SetConfigResponseEventArgs : LeapEventArgs + { + public SetConfigResponseEventArgs(string config_key, Config.ValueType dataType, object value, uint requestId) : base(LeapEvent.EVENT_CONFIG_RESPONSE) + { + this.ConfigKey = config_key; + this.DataType = dataType; + this.Value = value; + this.RequestId = requestId; + } + public string ConfigKey { get; set; } + public Config.ValueType DataType { get; set; } + public object Value { get; set; } + public uint RequestId { get; set; } + } + + /// + /// Dispatched when the connection is established. + /// @since 3.0 + /// + public class ConnectionEventArgs : LeapEventArgs + { + public ConnectionEventArgs() : base(LeapEvent.EVENT_CONNECTION) { } + } + + /// + /// Dispatched when the connection is lost. + /// @since 3.0 + /// + public class ConnectionLostEventArgs : LeapEventArgs + { + public ConnectionLostEventArgs() : base(LeapEvent.EVENT_CONNECTION_LOST) { } + } + + /// + /// Dispatched when a device is plugged in. + /// + /// Provides the device as an argument. + /// @since 3.0 + /// + public class DeviceEventArgs : LeapEventArgs + { + public DeviceEventArgs(Device device) : base(LeapEvent.EVENT_DEVICE) + { + this.Device = device; + } + public Device Device { get; set; } + } + + /// + /// Dispatched when a device is plugged in, but fails to initialize or when + /// a working device fails in use. + /// + /// Provides the failure reason and, if available, the serial number. + /// @since 3.0 + /// + public class DeviceFailureEventArgs : LeapEventArgs + { + public DeviceFailureEventArgs(uint code, string message, string serial) : base(LeapEvent.EVENT_DEVICE_FAILURE) + { + ErrorCode = code; + ErrorMessage = message; + DeviceSerialNumber = serial; + } + + public uint ErrorCode { get; set; } + public string ErrorMessage { get; set; } + public string DeviceSerialNumber { get; set; } + } + + public class DroppedFrameEventArgs : LeapEventArgs + { + public DroppedFrameEventArgs(Int64 frame_id, eLeapDroppedFrameType type) : base(LeapEvent.EVENT_DROPPED_FRAME) + { + frameID = frame_id; + reason = type; + } + + public Int64 frameID { get; set; } + public eLeapDroppedFrameType reason { get; set; } + } + + /// + /// Dispatched when an unrequested Image is ready. + /// + /// Provides the Image object as an argument. + /// @since 4.0 + /// + public class ImageEventArgs : LeapEventArgs + { + public ImageEventArgs(Image image) : base(LeapEvent.EVENT_IMAGE) + { + this.image = image; + } + + public Image image { get; set; } + } + + /// + /// Dispatched when point mapping change events are generated by the service. + /// + /// @since 4.0 + /// + public class PointMappingChangeEventArgs : LeapEventArgs + { + public PointMappingChangeEventArgs(Int64 frame_id, Int64 timestamp, UInt32 nPoints) : base(LeapEvent.EVENT_POINT_MAPPING_CHANGE) + { + this.frameID = frame_id; + this.timestamp = timestamp; + this.nPoints = nPoints; + } + + public Int64 frameID { get; set; } + public Int64 timestamp { get; set; } + public UInt32 nPoints { get; set; } + } + + public class HeadPoseEventArgs : LeapEventArgs + { + public HeadPoseEventArgs(LEAP_VECTOR head_position, LEAP_QUATERNION head_orientation) : base(LeapEvent.EVENT_POINT_MAPPING_CHANGE) + { + this.headPosition = head_position; + this.headOrientation = head_orientation; + } + + public LEAP_VECTOR headPosition { get; set; } + public LEAP_QUATERNION headOrientation { get; set; } + } + + public struct BeginProfilingForThreadArgs + { + public string threadName; + public string[] blockNames; + + public BeginProfilingForThreadArgs(string threadName, params string[] blockNames) + { + this.threadName = threadName; + this.blockNames = blockNames; + } + } + + public struct EndProfilingForThreadArgs { } + + public struct BeginProfilingBlockArgs + { + public string blockName; + + public BeginProfilingBlockArgs(string blockName) + { + this.blockName = blockName; + } + } + + public struct EndProfilingBlockArgs + { + public string blockName; + + public EndProfilingBlockArgs(string blockName) + { + this.blockName = blockName; + } + } +} diff --git a/vendor/LeapCSharp/FailedDevice.cs b/vendor/LeapCSharp/FailedDevice.cs new file mode 100644 index 00000000..75871e49 --- /dev/null +++ b/vendor/LeapCSharp/FailedDevice.cs @@ -0,0 +1,88 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + + /// + /// The FailedDevice class provides information about Leap Motion hardware that + /// has been physically connected to the client computer, but is not operating + /// correctly. + /// + /// Failed devices do not provide any tracking data and do not show up in the + /// Controller.Devices() list. + /// + /// Get the list of failed devices using Controller.FailedDevices(). + /// + /// @since 3.0 + /// + public class FailedDevice : + IEquatable + { + + public FailedDevice() + { + Failure = FailureType.FAIL_UNKNOWN; + PnpId = "0"; + } + + /// + /// Test FailedDevice equality. + /// True if the devices are the same. + /// @since 3.0 + /// + public bool Equals(FailedDevice other) + { + return PnpId == other.PnpId; + } + + /// + /// The device plug-and-play id string. + /// @since 3.0 + /// + public string PnpId { get; private set; } + + /// + /// The reason for device failure. + /// The failure reasons are defined as members of the FailureType enumeration. + /// + /// @since 3.0 + /// + public FailureType Failure { get; private set; } + + /// + /// The errors that can cause a device to fail to properly connect to the service. + /// + /// @since 3.0 + /// + public enum FailureType + { + /// + /// The cause of the error is unknown. + /// + FAIL_UNKNOWN, + /// + /// The device has a bad calibration record. + /// + FAIL_CALIBRATION, + /// + /// The device firmware is corrupt or failed to update. + /// + FAIL_FIRMWARE, + /// + /// The device is unresponsive. + /// + FAIL_TRANSPORT, + /// + /// The service cannot establish the required USB control interfaces. + /// + FAIL_CONTROl + } + } +} diff --git a/vendor/LeapCSharp/FailedDeviceList.cs b/vendor/LeapCSharp/FailedDeviceList.cs new file mode 100644 index 00000000..04834a1c --- /dev/null +++ b/vendor/LeapCSharp/FailedDeviceList.cs @@ -0,0 +1,47 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System.Collections.Generic; + + /// + /// The list of FailedDevice objects contains an entry for every failed Leap Motion + /// hardware device connected to the client computer. FailedDevice objects report + /// the device pnpID string and reason for failure. + /// + /// Get the list of FailedDevice objects from Controller.FailedDevices(). + /// + /// @since 3.0 + /// + public class FailedDeviceList : List + { + + /// + /// Constructs an empty list. + /// + public FailedDeviceList() { } + + /// + /// Appends the contents of another FailedDeviceList to this one. + /// + public FailedDeviceList Append(FailedDeviceList other) + { + AddRange(other); + return this; + } + + /// + /// Reports whether the list is empty. + /// + public bool IsEmpty + { + get { return Count == 0; } + } + } +} diff --git a/vendor/LeapCSharp/Finger.cs b/vendor/LeapCSharp/Finger.cs new file mode 100644 index 00000000..bc1e8a37 --- /dev/null +++ b/vendor/LeapCSharp/Finger.cs @@ -0,0 +1,183 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + + /// + /// The Finger class represents a tracked finger. + /// + /// Fingers are objects that the Leap Motion software has classified as a finger. + /// Get valid Finger objects from a Frame or a Hand object. + /// @since 1.0 + /// + [Serializable] + public class Finger + { + public Bone[] bones = new Bone[4]; + + /// + /// Constructs a finger. + /// + /// An uninitialized finger is considered invalid. + /// Get valid Finger objects from a Hand object. + /// + /// @since 3.0 + /// + public Finger() + { + bones[0] = new Bone(); + bones[1] = new Bone(); + bones[2] = new Bone(); + bones[3] = new Bone(); + } + + /// + /// Constructs a finger. + /// + /// Generally, you should not create your own finger objects. Such objects will not + /// have valid tracking data. Get valid finger objects from a hand in a frame + /// received from the service. + /// @since 3.0 + /// + public Finger(long frameId, + int handId, + int fingerId, + float timeVisible, + Vector tipPosition, + Vector direction, + float width, + float length, + bool isExtended, + FingerType type, + Bone metacarpal, + Bone proximal, + Bone intermediate, + Bone distal) + { + Type = type; + bones[0] = metacarpal; + bones[1] = proximal; + bones[2] = intermediate; + bones[3] = distal; + Id = (handId * 10) + fingerId; + HandId = handId; + TipPosition = tipPosition; + Direction = direction; + Width = width; + Length = length; + IsExtended = isExtended; + TimeVisible = timeVisible; + } + + /// + /// The bone at a given bone index on this finger. + /// @since 2.0 + /// + public Bone Bone(Bone.BoneType boneIx) + { + return bones[(int)boneIx]; + } + + /// + /// A string containing a brief, human readable description of the Finger object. + /// @since 1.0 + /// + public override string ToString() + { + return Enum.GetName(typeof(FingerType), Type) + " id:" + Id; + } + + /// + /// The type of this finger. + /// @since 2.0 + /// + public Finger.FingerType Type; + + /// + /// A unique ID assigned to this Finger object, whose value remains the + /// same across consecutive frames while the tracked hand remains visible. + /// If tracking of the hand is lost, the Leap Motion software may assign a + /// new ID when it detects the hand in a future frame. + /// + /// Use the ID value to find this Finger object in future frames. + /// + /// IDs should be from 1 to 100 (inclusive). If more than 100 objects are tracked + /// an IDs of -1 will be used until an ID in the defined range is available. + /// + /// @since 1.0 + /// + public int Id; + + /// + /// The Hand associated with a finger. + /// @since 1.0 + /// + public int HandId; + + /// + /// The tip position of this Finger. + /// @since 1.0 + /// + public Vector TipPosition; + + /// + /// The direction in which this finger or tool is pointing. The direction is expressed + /// as a unit vector pointing in the same direction as the tip. + /// @since 1.0 + /// + public Vector Direction; + + /// + /// The estimated width of the finger. + /// @since 1.0 + /// + public float Width; + + /// + /// The estimated length of the finger. + /// @since 1.0 + /// + public float Length; + + /// + /// Whether or not this Finger is in an extended posture. + /// + /// A finger is considered extended if it is extended straight from the hand as if + /// pointing. A finger is not extended when it is bent down and curled towards the + /// palm. + /// + /// @since 2.0 + /// + public bool IsExtended; + + /// + /// The duration of time this Finger has been visible to the Leap Motion Controller. + /// @since 1.0 + /// + public float TimeVisible; + + /// + /// Enumerates the names of the fingers. + /// + /// Members of this enumeration are returned by Finger.Type() to identify a + /// Finger object. + /// @since 2.0 + /// + public enum FingerType + { + TYPE_THUMB = 0, + TYPE_INDEX = 1, + TYPE_MIDDLE = 2, + TYPE_RING = 3, + TYPE_PINKY = 4, + TYPE_UNKNOWN = -1 + } + } +} diff --git a/vendor/LeapCSharp/Frame.cs b/vendor/LeapCSharp/Frame.cs new file mode 100644 index 00000000..e8e5d6f2 --- /dev/null +++ b/vendor/LeapCSharp/Frame.cs @@ -0,0 +1,207 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + using System.Collections.Generic; + + /// + /// The Frame class represents a set of hand and finger tracking data detected + /// in a single frame. + /// + /// The Leap Motion software detects hands, fingers and tools within the tracking area, reporting + /// their positions, orientations, gestures, and motions in frames at the Leap Motion frame rate. + /// + /// Access Frame objects through an instance of the Controller class. + /// @since 1.0 + /// + [Serializable] + public class Frame : IEquatable + { + [ThreadStatic] + private static Queue _handPool; + + /// + /// Constructs a Frame object. + /// + /// Frame instances created with this constructor are invalid. + /// Get valid Frame objects by calling the Controller.Frame() function. + /// + /// The only time you should use this constructor is before deserializing + /// serialized frame data, or if you are going to be passing this Frame + /// to a method that fills it with valid data. + /// + /// @since 1.0 + /// + public Frame() + { + Hands = new List(); + } + + /// + /// Constructs a new Frame. + /// @since 3.0 + /// + public Frame(long id, long timestamp, float fps, List hands) + { + Id = id; + Timestamp = timestamp; + CurrentFramesPerSecond = fps; + Hands = hands; + } + + [Obsolete] + public int SerializeLength + { + get + { + throw new NotImplementedException(); + } + } + + [Obsolete] + public byte[] Serialize + { + get + { + throw new NotImplementedException(); + } + } + + [Obsolete] + public void Deserialize(byte[] arg) + { + throw new NotImplementedException(); + } + + /// + /// The Hand object with the specified ID in this frame, or null if none + /// exists. + /// + /// Use the Frame.Hand() function to retrieve the Hand object from + /// this frame using an ID value obtained from a previous frame. + /// This function always returns a Hand object, but if no hand + /// with the specified ID is present, an invalid Hand object is returned. + /// + /// Note that ID values persist across frames, but only until tracking of a + /// particular object is lost. If tracking of a hand is lost and subsequently + /// regained, the new Hand object representing that physical hand may have + /// a different ID than that representing the physical hand in an earlier frame. + /// @since 1.0 + public Hand Hand(int id) + { + for (int i = Hands.Count; i-- != 0;) + { + if (Hands[i].Id == id) + { + return Hands[i]; + } + } + return null; + } + + /// + /// Compare Frame object equality. + /// + /// Two Frame objects are equal if and only if both Frame objects represent + /// the exact same frame of tracking data and both Frame objects are valid. + /// @since 1.0 + /// + public bool Equals(Frame other) + { + return Id == other.Id && Timestamp == other.Timestamp; + } + + /// + /// A string containing a brief, human readable description of the Frame object. + /// @since 1.0 + /// + public override string ToString() + { + return "Frame id: " + this.Id + " timestamp: " + this.Timestamp; + } + + /// + /// A unique ID for this Frame. + /// + /// Consecutive frames processed by the Leap Motion software have consecutive + /// increasing values. You can use the frame ID to avoid processing the same + /// Frame object twice, as well as to make sure that your application processes + /// every frame. + /// + /// @since 1.0 + /// + public long Id; + + /// + /// The frame capture time in microseconds elapsed since an arbitrary point in + /// time in the past. + /// + /// You can use Controller.Now() to calculate the age of the frame. + /// + /// @since 1.0 + /// + public long Timestamp; + + /// + /// The instantaneous framerate. + /// + /// The rate at which the Leap Motion software is providing frames of data + /// (in frames per second). The framerate can fluctuate depending on available computing + /// resources, activity within the device field of view, software tracking settings, + /// and other factors. + /// + /// @since 1.0 + /// + public float CurrentFramesPerSecond; + + /// + /// The list of Hand objects detected in this frame, given in arbitrary order. + /// The list can be empty if no hands are detected. + /// + /// @since 1.0 + /// + public List Hands; + + /// + /// Resizes the Hand list to have a specific size. If the size is decreased, + /// the removed hands are placed into the hand pool. If the size is increased, the + /// new spaces are filled with hands taken from the hand pool. If the pool is + /// empty, new hands are constructed instead. + /// + public void ResizeHandList(int count) + { + if (_handPool == null) + { + _handPool = new Queue(); + } + + while (Hands.Count < count) + { + Hand newHand; + if (_handPool.Count > 0) + { + newHand = _handPool.Dequeue(); + } + else + { + newHand = new Hand(); + } + Hands.Add(newHand); + } + + while (Hands.Count > count) + { + Hand lastHand = Hands[Hands.Count - 1]; + Hands.RemoveAt(Hands.Count - 1); + _handPool.Enqueue(lastHand); + } + } + } +} diff --git a/vendor/LeapCSharp/Hand.cs b/vendor/LeapCSharp/Hand.cs new file mode 100644 index 00000000..7d1d4162 --- /dev/null +++ b/vendor/LeapCSharp/Hand.cs @@ -0,0 +1,322 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + using System.Collections.Generic; + + /// + /// The Hand class reports the physical characteristics of a detected hand. + /// + /// Hand tracking data includes a palm position and velocity; vectors for + /// the palm normal and direction to the fingers; and lists of the attached fingers. + /// + /// Note that Hand objects can be invalid, which means that they do not contain + /// valid tracking data and do not correspond to a physical entity. Invalid Hand + /// objects can be the result of using the default constructor, or modifying the + /// hand data in an incorrect way. + /// @since 1.0 + /// + [Serializable] + public class Hand : IEquatable + { + + /// + /// Constructs a Hand object. + /// + /// An uninitialized hand is considered invalid. + /// Get valid Hand objects from a Frame object. + /// + /// @since 1.0 + /// + public Hand() + { + Arm = new Arm(); + Fingers = new List(5); + Fingers.Add(new Finger()); + Fingers.Add(new Finger()); + Fingers.Add(new Finger()); + Fingers.Add(new Finger()); + Fingers.Add(new Finger()); + } + + /// + /// Constructs a hand. + /// + /// Generally, you should not create your own Hand objects. Such objects will not + /// have valid tracking data. Get valid Hand objects from a frame + /// received from the service. + /// @since 3.0 + /// + public Hand(long frameID, + int id, + float confidence, + float grabStrength, + float grabAngle, + float pinchStrength, + float pinchDistance, + float palmWidth, + bool isLeft, + float timeVisible, + Arm arm, + List fingers, + Vector palmPosition, + Vector stabilizedPalmPosition, + Vector palmVelocity, + Vector palmNormal, + LeapQuaternion palmOrientation, + Vector direction, + Vector wristPosition) + { + FrameId = frameID; + Id = id; + Confidence = confidence; + GrabStrength = grabStrength; + GrabAngle = grabAngle; + PinchStrength = pinchStrength; + PinchDistance = pinchDistance; + PalmWidth = palmWidth; + IsLeft = isLeft; + TimeVisible = timeVisible; + Arm = arm; + Fingers = fingers; + PalmPosition = palmPosition; + StabilizedPalmPosition = stabilizedPalmPosition; + PalmVelocity = palmVelocity; + PalmNormal = palmNormal; + Rotation = palmOrientation; + Direction = direction; + WristPosition = wristPosition; + } + + /// + /// The Finger object with the specified ID attached to this hand. + /// + /// Use the Hand.Finger() function to retrieve a Finger object attached to + /// this hand using an ID value obtained from a previous frame. + /// + /// Note that ID values persist across frames, but only until tracking of a + /// particular object is lost. If tracking of a hand is lost and subsequently + /// regained, the new Finger object representing that finger may have a + /// different ID than that representing the finger in an earlier frame. + /// + /// @since 1.0 + /// + public Finger Finger(int id) + { + for (int i = Fingers.Count; i-- != 0;) + { + if (Fingers[i].Id == id) + { + return Fingers[i]; + } + } + return null; + } + + /// + /// Compare Hand object equality. + /// + /// Two Hand objects are equal if and only if both Hand objects represent the + /// exact same physical hand in the same frame and both Hand objects are valid. + /// + public bool Equals(Hand other) + { + return Id == other.Id && FrameId == other.FrameId; + } + + /// + /// A string containing a brief, human readable description of the Hand object. + /// @since 1.0 + /// + public override string ToString() + { + return string.Format( + "Hand {0} {1}.", + this.Id, + this.IsLeft ? "left" : "right" + ); + } + + public long FrameId; + + /// + /// A unique ID assigned to this Hand object, whose value remains the same + /// across consecutive frames while the tracked hand remains visible. If + /// tracking is lost (for example, when a hand is occluded by another hand + /// or when it is withdrawn from or reaches the edge of the Leap Motion Controller field of view), + /// the Leap Motion software may assign a new ID when it detects the hand in a future frame. + /// + /// Use the ID value with the Frame.Hand() function to find this Hand object + /// in future frames. + /// + /// @since 1.0 + /// + public int Id; + + /// + /// The list of Finger objects detected in this frame that are attached to + /// this hand, given in order from thumb to pinky. The list cannot be empty. + /// @since 1.0 + /// + public List Fingers; + + /// + /// The center position of the palm. + /// @since 1.0 + /// + public Vector PalmPosition; + + /// + /// The rate of change of the palm position. + /// @since 1.0 + /// + public Vector PalmVelocity; + + /// + /// The normal vector to the palm. If your hand is flat, this vector will + /// point downward, or "out" of the front surface of your palm. + /// + /// The direction is expressed as a unit vector pointing in the same + /// direction as the palm normal (that is, a vector orthogonal to the palm). + /// + /// You can use the palm normal vector to compute the roll angle of the palm with + /// respect to the horizontal plane. + /// @since 1.0 + /// + public Vector PalmNormal; + + /// + /// The direction from the palm position toward the fingers. + /// + /// The direction is expressed as a unit vector pointing in the same + /// direction as the directed line from the palm position to the fingers. + /// + /// You can use the palm direction vector to compute the pitch and yaw angles of the palm with + /// respect to the horizontal plane. + /// @since 1.0 + /// + public Vector Direction; + + /// + /// The transform of the hand. + /// + /// Note, in version prior to 3.1, the Basis was a Matrix object. + /// @since 3.1 + /// + public LeapTransform Basis { get { return new LeapTransform(PalmPosition, Rotation); } } + + /// + /// The rotation of the hand as a quaternion. + /// + /// @since 3.1 + /// + public LeapQuaternion Rotation; + + /// + /// The strength of a grab hand pose. + /// + /// The strength is zero for an open hand, and blends to one when a grabbing hand + /// pose is recognized. + /// @since 2.0 + /// + public float GrabStrength; + + /// + /// The angle between the fingers and the hand of a grab hand pose. + /// + /// The angle is computed by looking at the angle between the direction of the + /// 4 fingers and the direction of the hand. Thumb is not considered when + /// computing the angle. + /// The angle is 0 radian for an open hand, and reaches pi radians when the pose + /// is a tight fist. + /// + /// @since 3.0 + /// + public float GrabAngle; + + /// + /// The holding strength of a pinch hand pose. + /// + /// The strength is zero for an open hand, and blends to one when a pinching + /// hand pose is recognized. Pinching can be done between the thumb + /// and any other finger of the same hand. + /// @since 2.0 + /// + public float PinchStrength; + + /// + /// The distance between the thumb and index finger of a pinch hand pose. + /// + /// The distance is computed by looking at the shortest distance between + /// the last 2 phalanges of the thumb and those of the index finger. + /// This pinch measurement only takes thumb and index finger into account. + /// @since 3.0 + /// + public float PinchDistance; + + /// + /// The estimated width of the palm when the hand is in a flat position. + /// @since 2.0 + /// + public float PalmWidth; + + /// + /// The stabilized palm position of this Hand. + /// + /// Smoothing and stabilization is performed in order to make + /// this value more suitable for interaction with 2D content. The stabilized + /// position lags behind the palm position by a variable amount, depending + /// primarily on the speed of movement. + /// @since 1.0 + /// + public Vector StabilizedPalmPosition; + + /// + /// The position of the wrist of this hand. + /// @since 2.0.3 + /// + public Vector WristPosition; + + /// + /// The duration of time this Hand has been visible to the Leap Motion Controller. + /// @since 1.0 + /// + public float TimeVisible; + + /// + /// How confident we are with a given hand pose. + /// The confidence level ranges between 0.0 and 1.0 inclusive. + /// + /// @since 2.0 + /// + public float Confidence; + + /// + /// Identifies whether this Hand is a left hand. + /// @since 2.0 + /// + public bool IsLeft; + + /// + /// Identifies whether this Hand is a right hand. + /// @since 2.0 + /// + public bool IsRight { get { return !IsLeft; } } + + /// + /// The arm to which this hand is attached. + /// + /// If the arm is not completely in view, Arm attributes are estimated based on + /// the attributes of entities that are in view combined with typical human anatomy. + /// @since 2.0.3 + /// + public Arm Arm; + } +} diff --git a/vendor/LeapCSharp/IController.cs b/vendor/LeapCSharp/IController.cs new file mode 100644 index 00000000..f72b7086 --- /dev/null +++ b/vendor/LeapCSharp/IController.cs @@ -0,0 +1,46 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +using System; + +namespace Leap +{ + public interface IController : + IDisposable + { + Frame Frame(int history = 0); + Frame GetTransformedFrame(LeapTransform trs, int history = 0); + Frame GetInterpolatedFrame(Int64 time); + + void SetPolicy(Controller.PolicyFlag policy); + void ClearPolicy(Controller.PolicyFlag policy); + bool IsPolicySet(Controller.PolicyFlag policy); + + long Now(); + + bool IsConnected { get; } + Config Config { get; } + DeviceList Devices { get; } + + event EventHandler Connect; + event EventHandler Disconnect; + event EventHandler FrameReady; + event EventHandler Device; + event EventHandler DeviceLost; + event EventHandler DeviceFailure; + event EventHandler LogMessage; + + //new + event EventHandler PolicyChange; + event EventHandler ConfigChange; + event EventHandler DistortionChange; + event EventHandler ImageReady; + event EventHandler PointMappingChange; + event EventHandler HeadPoseChange; + } +} diff --git a/vendor/LeapCSharp/Image.cs b/vendor/LeapCSharp/Image.cs new file mode 100644 index 00000000..4cd9927e --- /dev/null +++ b/vendor/LeapCSharp/Image.cs @@ -0,0 +1,434 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using LeapInternal; + using System; + + /// + /// The Image class represents a stereo image pair from the Leap Motion device. + /// + /// In addition to image data, the Image object provides a distortion map for correcting + /// lens distortion. + /// @since 2.1.0 + /// + public class Image + { + private ImageData leftImage; + private ImageData rightImage; + private Int64 frameId = 0; + private Int64 timestamp = 0; + + public Image(Int64 frameId, Int64 timestamp, ImageData leftImage, ImageData rightImage) + { + if (leftImage == null || rightImage == null) + { + throw new ArgumentNullException("images"); + } + if (leftImage.type != rightImage.type || + leftImage.format != rightImage.format || + leftImage.width != rightImage.width || + leftImage.height != rightImage.height || + leftImage.bpp != rightImage.bpp || + leftImage.DistortionSize != rightImage.DistortionSize) + { + throw new ArgumentException("image mismatch"); + } + this.frameId = frameId; + this.timestamp = timestamp; + this.leftImage = leftImage; + this.rightImage = rightImage; + } + + private ImageData imageData(CameraType camera) + { + return camera == CameraType.LEFT ? leftImage : rightImage; + } + + /// + /// The buffer containing the image data. + /// + /// The image data is a set of 8-bit intensity values. The buffer is + /// image.Width * image.Height * image.BytesPerPixel bytes long. + /// + /// Use the ByteOffset(` method to find the beginning offset + /// of the data for the specified camera. + /// + /// @since 4.0 + /// + public byte[] Data(CameraType camera) + { + if (camera != CameraType.LEFT && camera != CameraType.RIGHT) + return null; + + return imageData(camera).AsByteArray; + } + + /// + /// The offset, in number of bytes, from the beginning of the Data() + /// buffer to the first byte of the image data for the specified camera. + /// + /// @since 4.0 + /// + public UInt32 ByteOffset(CameraType camera) + { + if (camera != CameraType.LEFT && camera != CameraType.RIGHT) + return 0; + + return imageData(camera).byteOffset; + } + + /// + /// The number of bytes in the Data() buffer corresponding to each + /// image. Use the ByteOffset() function to find the starting byte + /// offset for each image. + /// + /// @since 4.0 + /// + public UInt32 NumBytes + { + get + { + return leftImage.width * leftImage.height * leftImage.bpp; + } + } + + /// + /// The distortion calibration map for this image. + /// + /// The calibration map is a 64x64 grid of points. Each point is defined by + /// a pair of 32-bit floating point values. Each point in the map + /// represents a ray projected into the camera. The value of + /// a grid point defines the pixel in the image data containing the brightness + /// value produced by the light entering along the corresponding ray. By + /// interpolating between grid data points, you can find the brightness value + /// for any projected ray. Grid values that fall outside the range [0..1] do + /// not correspond to a value in the image data and those points should be ignored. + /// + /// The calibration map can be used to render an undistorted image as well as to + /// find the true angle from the camera to a feature in the raw image. The + /// distortion map itself is designed to be used with GLSL shader programs. + /// In other contexts, it may be more convenient to use the Image Rectify() + /// and Warp() functions. + /// + /// Distortion is caused by the lens geometry as well as imperfections in the + /// lens and sensor window. The calibration map is created by the calibration + /// process run for each device at the factory (and which can be rerun by the + /// user). + /// + /// @since 2.1.0 + /// + public float[] Distortion(CameraType camera) + { + if (camera != CameraType.LEFT && camera != CameraType.RIGHT) + return null; + + return imageData(camera).DistortionData.Data; + } + + /// + /// Provides the corrected camera ray intercepting the specified point on the image. + /// + /// Given a point on the image, PixelToRectilinear() corrects for camera distortion + /// and returns the true direction from the camera to the source of that image point + /// within the Leap Motion field of view. + /// + /// This direction vector has an x and y component [x, y, 1], with the third element + /// always one. Note that this vector uses the 2D camera coordinate system + /// where the x-axis parallels the longer (typically horizontal) dimension and + /// the y-axis parallels the shorter (vertical) dimension. The camera coordinate + /// system does not correlate to the 3D Leap Motion coordinate system. + /// + /// **Note:** This function should be called immediately after an image is obtained. Incorrect + /// results will be returned if the image orientation has changed or a different device is plugged + /// in between the time the image was received and the time this function is called. + /// + /// Note, this function was formerly named Rectify(). + /// @since 2.1.0 + /// + public Vector PixelToRectilinear(CameraType camera, Vector pixel) + { + return Connection.GetConnection().PixelToRectilinear(camera, pixel); + } + + /// + /// Provides the point in the image corresponding to a ray projecting + /// from the camera. + /// + /// Given a ray projected from the camera in the specified direction, RectilinearToPixel() + /// corrects for camera distortion and returns the corresponding pixel + /// coordinates in the image. + /// + /// The ray direction is specified in relationship to the camera. The first + /// vector element corresponds to the "horizontal" view angle; the second + /// corresponds to the "vertical" view angle. + /// + /// The RectilinearToPixel() function returns pixel coordinates outside of the image bounds + /// if you project a ray toward a point for which there is no recorded data. + /// + /// RectilinearToPixel() is typically not fast enough for realtime distortion correction. + /// For better performance, use a shader program executed on a GPU. + /// + /// **Note:** This function should be called immediately after an image is obtained. Incorrect + /// results will be returned if the image orientation has changed or a different device is plugged + /// in between the time the image was received and the time this function is called. + /// + /// Note, this function was formerly named Warp(). + /// @since 2.1.0 + /// + public Vector RectilinearToPixel(CameraType camera, Vector ray) + { + return Connection.GetConnection().RectilinearToPixel(camera, ray); + } + + /// + /// Compare Image object equality. + /// + /// Two Image objects are equal if and only if both Image objects represent the + /// exact same Image and both Images are valid. + /// @since 2.1.0 + /// + public bool Equals(Image other) + { + return + this.frameId == other.frameId && + this.Type == other.Type && + this.Timestamp == other.Timestamp; + } + + /// + /// A string containing a brief, human readable description of the Image object. + /// @since 2.1.0 + /// + public override string ToString() + { + return "Image sequence" + this.frameId + ", format: " + this.Format + ", type: " + this.Type; + } + + /// + /// The image sequence ID. + /// @since 2.2.1 + /// + public Int64 SequenceId + { + get + { + return frameId; + } + } + + /// + /// The image width. + /// @since 2.1.0 + /// + public int Width + { + get + { + return (int)leftImage.width; + } + } + + /// + /// The image height. + /// @since 2.1.0 + /// + public int Height + { + get + { + return (int)leftImage.height; + } + } + + /// + /// The number of bytes per pixel. + /// + /// Use this value along with Image.Width() and Image.Height() + /// to calculate the size of the data buffer. + /// + /// @since 2.2.0 + /// + public int BytesPerPixel + { + get + { + return (int)leftImage.bpp; + } + } + + /// + /// The image format. + /// @since 2.2.0 + /// + public FormatType Format + { + get + { + switch (leftImage.format) + { + case eLeapImageFormat.eLeapImageType_IR: + return FormatType.INFRARED; + case eLeapImageFormat.eLeapImageType_RGBIr_Bayer: + return FormatType.IBRG; + default: + return FormatType.INFRARED; + } + } + } + + public ImageType Type + { + get + { + switch (leftImage.type) + { + case eLeapImageType.eLeapImageType_Default: + return ImageType.DEFAULT; + case eLeapImageType.eLeapImageType_Raw: + return ImageType.RAW; + default: + return ImageType.DEFAULT; + } + } + } + + /// + /// The stride of the distortion map. + /// + /// Since each point on the 64x64 element distortion map has two values in the + /// buffer, the stride is 2 times the size of the grid. (Stride is currently fixed + /// at 2 * 64 = 128). + /// + /// @since 2.1.0 + /// + public int DistortionWidth + { + get + { + return leftImage.DistortionSize * 2; + } + } + + /// + /// The distortion map height. + /// Currently fixed at 64. + /// + /// @since 2.1.0 + /// + public int DistortionHeight + { + get + { + return leftImage.DistortionSize; + } + } + + /// + /// The horizontal ray offset for a particular camera. + /// + /// Used to convert between normalized coordinates in the range [0..1] and the + /// ray slope range [-4..4]. + /// + /// @since 4.0 + /// + public float RayOffsetX(CameraType camera) + { + if (camera != CameraType.LEFT && camera != CameraType.RIGHT) + return 0; + + return imageData(camera).RayOffsetX; + } + + /// + /// The vertical ray offset for a particular camera. + /// + /// Used to convert between normalized coordinates in the range [0..1] and the + /// ray slope range [-4..4]. + /// + /// @since 2.1.0 + /// + public float RayOffsetY(CameraType camera) + { + if (camera != CameraType.LEFT && camera != CameraType.RIGHT) + return 0; + + return imageData(camera).RayOffsetY; + } + + /// + /// The horizontal ray scale factor for a particular camera. + /// + /// Used to convert between normalized coordinates in the range [0..1] and the + /// ray slope range [-4..4]. + /// + /// @since 2.1.0 + /// + public float RayScaleX(CameraType camera) + { + if (camera != CameraType.LEFT && camera != CameraType.RIGHT) + return 0; + + return imageData(camera).RayScaleX; + } + + /// + /// The vertical ray scale factor for a particular camera. + /// + /// Used to convert between normalized coordinates in the range [0..1] and the + /// ray slope range [-4..4]. + /// + /// @since 2.1.0 + /// + public float RayScaleY(CameraType camera) + { + if (camera != CameraType.LEFT && camera != CameraType.RIGHT) + return 0; + + return imageData(camera).RayScaleY; + } + + /// + /// Returns a timestamp indicating when this frame began being captured on the device. + /// @since 2.2.7 + /// + public Int64 Timestamp + { + get + { + return timestamp; + } + } + + /// + /// Enumerates the possible image formats. + /// + /// The Image.Format() function returns an item from the FormatType enumeration. + /// @since 2.2.0 + /// + public enum FormatType + { + INFRARED = 0, + IBRG = 1 + } + + public enum ImageType + { + DEFAULT, + RAW + } + + public enum CameraType + { + LEFT = 0, + RIGHT = 1 + }; + } + +} diff --git a/vendor/LeapCSharp/ImageData.cs b/vendor/LeapCSharp/ImageData.cs new file mode 100644 index 00000000..473948e4 --- /dev/null +++ b/vendor/LeapCSharp/ImageData.cs @@ -0,0 +1,47 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace LeapInternal +{ + using Leap; + using System; + + public class ImageData + { + private LEAP_IMAGE_PROPERTIES _properties; + private object _object; + + public Image.CameraType camera { get; protected set; } + public eLeapImageType type { get { return _properties.type; } } + public eLeapImageFormat format { get { return _properties.format; } } + public UInt32 bpp { get { return _properties.bpp; } } + public UInt32 width { get { return _properties.width; } } + public UInt32 height { get { return _properties.height; } } + public float RayScaleX { get { return _properties.x_scale; } } + public float RayScaleY { get { return _properties.y_scale; } } + public float RayOffsetX { get { return _properties.x_offset; } } + public float RayOffsetY { get { return _properties.y_offset; } } + public byte[] AsByteArray { get { return _object as byte[]; } } + public float[] AsFloatArray { get { return _object as float[]; } } + public UInt32 byteOffset { get; protected set; } + + public int DistortionSize { get { return LeapC.DistortionSize; } } + public UInt64 DistortionMatrixKey { get; protected set; } + public DistortionData DistortionData { get; protected set; } + + public ImageData(Image.CameraType camera, LEAP_IMAGE image, DistortionData distortionData) + { + this.camera = camera; + this._properties = image.properties; + this.DistortionMatrixKey = image.matrix_version; + this.DistortionData = distortionData; + this._object = MemoryManager.GetPinnedObject(image.data); + this.byteOffset = image.offset; + } + } +} diff --git a/vendor/LeapCSharp/LeapC.cs b/vendor/LeapCSharp/LeapC.cs new file mode 100644 index 00000000..941348f6 --- /dev/null +++ b/vendor/LeapCSharp/LeapC.cs @@ -0,0 +1,1049 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + + +namespace LeapInternal +{ + using System; + using System.Runtime.InteropServices; + + public enum eLeapConnectionStatus : uint + { + /// + /// A connection has been established. + /// + eLeapConnectionStatus_NotConnected = 0, + /// + /// The connection has not been completed. Call OpenConnection. + /// + eLeapConnectionStatus_Connected, + /// + /// The connection handshake has not completed. + /// + eLeapConnectionStatus_HandshakeIncomplete, + /// + /// A connection could not be established because the server does not appear to be running. + /// + eLeapConnectionStatus_NotRunning = 0xE7030004 + }; + + public enum eLeapDeviceCaps : uint + { + /// + /// The device can send color images. + /// + eLeapDeviceCaps_Color = 0x00000001, + }; + + public enum eLeapDeviceType : uint + { + /// + /// The Leap Motion consumer peripheral + /// + eLeapDeviceType_Peripheral = 0x0003, + /// + /// Internal research product codename "Dragonfly". + /// + eLeapDeviceType_Dragonfly = 0x1102, + /// + /// Internal research product codename "Nightcrawler". + /// + eLeapDeviceType_Nightcrawler = 0x1201, + /// + /// Research product codename "Rigel". + /// + eLeapDevicePID_Rigel = 0x1202 + }; + + public enum eLeapServiceDisposition : uint + { + /// + /// The service cannot receive frames fast enough from the underlying hardware. + /// @since 3.1.3 + /// + eLeapServiceState_LowFpsDetected = 0x00000001, + + /// + /// The service has paused itself due to an insufficient frame rate from the hardware. + /// @since 3.1.3 + /// + eLeapServiceState_PoorPerformancePause = 0x00000002, + }; + + public enum eDistortionMatrixType + { + /// + /// A 64x64 matrix of pairs of points. + /// + eDistortionMatrixType_64x64 + }; + + public enum eLeapPolicyFlag : uint + { + /// + /// Allows frame receipt even when this application is not the foreground application. + /// + eLeapPolicyFlag_BackgroundFrames = 0x00000001, + /// + /// Allow streaming images + /// + eLeapPolicyFlag_Images = 0x00000002, + /// + /// Optimize HMD Policy Flag. + /// + eLeapPolicyFlag_OptimizeHMD = 0x00000004, + /// + /// Modifies the security token to allow calls to LeapPauseDevice to succeed + /// + eLeapPolicyFlag_AllowPauseResume = 0x00000008, + /// + /// Allows streaming map points. + /// + eLeapPolicyFlag_MapPoints = 0x00000080, + /// + /// The policy specifying whether to optimize tracking for screen-top device. + /// @since 5.0.0 + /// + eLeapPolicyFlag_ScreenTop = 0x00000100, + }; + + public enum eLeapDeviceStatus : uint + { + /// + /// Presently sending frames to all clients that have requested them. + /// + eLeapDeviceStatus_Streaming = 0x00000001, + /// + /// Device streaming has been paused. + /// + eLeapDeviceStatus_Paused = 0x00000002, + /// + /// There are known sources of infrared interference. Device has transitioned to + /// robust mode in order to compensate. + /// + eLeapDeviceStatus_Robust = 0x00000004, + /// + /// The device's window is smudged, tracking may be degraded. + /// + eLeapDeviceStatus_Smudged = 0x00000008, + /// + /// The device has entered low-resource mode. + /// + eLeapDeviceStatus_LowResource = 0x00000010, + /// + /// The device has failed, but the failure reason is not known. + /// + eLeapDeviceStatus_UnknownFailure = 0xE8010000, + /// + /// Bad calibration, cannot send frames. + /// + eLeapDeviceStatus_BadCalibration = 0xE8010001, + /// + /// Corrupt firmware and/or cannot receive a required firmware update. + /// + eLeapDeviceStatus_BadFirmware = 0xE8010002, + /// + /// Exhibiting USB communications issues. + /// + eLeapDeviceStatus_BadTransport = 0xE8010003, + /// + /// Missing critical control interfaces needed for communication. + /// + eLeapDeviceStatus_BadControl = 0xE8010004, + }; + + public enum eLeapImageType + { + eLeapImageType_Unknown = 0, + /// + /// Default processed IR image + /// + eLeapImageType_Default, + /// + /// Image from raw sensor values + /// + eLeapImageType_Raw + }; + + public enum eLeapImageFormat : uint + { + /// + /// An invalid or unknown format. + /// + eLeapImageFormat_UNKNOWN = 0, + /// + /// An infrared image. + /// + eLeapImageType_IR = 0x317249, + /// + /// A Bayer RGBIr image with uncorrected RGB channels + /// + eLeapImageType_RGBIr_Bayer = 0x49425247, + }; + + public enum eLeapPerspectiveType + { + /// + /// An unknown or invalid type. + /// + eLeapPerspectiveType_invalid = 0, + /// + /// A canonically left image. + /// + eLeapPerspectiveType_stereo_left = 1, + /// + /// A canonically right image. + /// + eLeapPerspectiveType_stereo_right = 2, + /// + /// Reserved for future use. + /// + eLeapPerspectiveType_mono = 3, + }; + + public enum eLeapHandType + { + eLeapHandType_Left, + eLeapHandType_Right + }; + + public enum eLeapLogSeverity + { + /// + /// The message severity is not known or was not specified. + /// + eLeapLogSeverity_Unknown = 0, + /// + /// A message about a fault that could render the software or device non-functional. + /// + eLeapLogSeverity_Critical, + /// + /// A message warning about a condition that could degrade device capabilities. + /// + eLeapLogSeverity_Warning, + /// + /// A system status message. + /// + eLeapLogSeverity_Information + }; + + public enum eLeapValueType : int + { + /// + /// The type is unknown (which is an abnormal condition). + /// + eLeapValueType_Unknown, + eLeapValueType_Boolean, + eLeapValueType_Int32, + eLeapValueType_Float, + eLeapValueType_String + }; + + public enum eLeapAllocatorType : uint + { + eLeapAllocatorType_Int8 = 0, + eLeapAllocatorType_Uint8 = 1, + eLeapAllocatorType_Int16 = 2, + eLeapAllocatorType_UInt16 = 3, + eLeapAllocatorType_Int32 = 4, + eLeapAllocatorType_UInt32 = 5, + eLeapAllocatorType_Float = 6, + eLeapAllocatorType_Int64 = 8, + eLeapAllocatorType_UInt64 = 9, + eLeapAllocatorType_Double = 10, + }; + + public enum eLeapRS : uint + { + /// + /// The operation completed successfully. + /// + eLeapRS_Success = 0x00000000, + /// + /// An undetermined error has occurred. + /// This is usually the result of an abnormal operating condition in LeapC, + /// the Leap Motion service, or the host computer itself. + /// + eLeapRS_UnknownError = 0xE2010000, + /// + /// An invalid argument was specified. + /// + eLeapRS_InvalidArgument = 0xE2010001, + /// + /// Insufficient resources existed to complete the request. + /// + eLeapRS_InsufficientResources = 0xE2010002, + /// + /// The specified buffer was not large enough to complete the request. + /// + eLeapRS_InsufficientBuffer = 0xE2010003, + /// + /// The requested operation has timed out. + /// + eLeapRS_Timeout = 0xE2010004, + /// + /// The operation is invalid because there is no current connection. + /// + eLeapRS_NotConnected = 0xE2010005, + /// + /// The operation is invalid because the connection is not complete. + /// + eLeapRS_HandshakeIncomplete = 0xE2010006, + /// + /// The specified buffer size is too large. + /// + eLeapRS_BufferSizeOverflow = 0xE2010007, + /// + /// A communications protocol error occurred. + /// + eLeapRS_ProtocolError = 0xE2010008, + /// + /// The server incorrectly specified zero as a client ID. + /// + eLeapRS_InvalidClientID = 0xE2010009, + /// + /// The connection to the service was unexpectedly closed while reading or writing a message. + /// The server may have terminated. + /// + eLeapRS_UnexpectedClosed = 0xE201000A, + /// + /// The specified request token does not appear to be valid + /// + /// Provided that the token value which identifies the request itself was, at one point, valid, this + /// error condition occurs when the request to which the token refers has already been satisfied or + /// is currently being satisfied. + /// + eLeapRS_UnknownImageFrameRequest = 0xE201000B, + /// + /// The specified frame ID is not valid or is no longer valid + /// + /// Provided that frame ID was, at one point, valid, this error condition occurs when the identifier + /// refers to a frame that occurred further in the past than is currently recorded in the rolling + /// frame window. + /// + eLeapRS_UnknownTrackingFrameID = 0xE201000C, + /// + /// The specified timestamp references a future point in time + /// + /// The related routine can only operate on time points having occurred in the past, and the + /// provided timestamp occurs in the future. + /// + eLeapRS_RoutineIsNotSeer = 0xE201000D, + /// + /// The specified timestamp references a point too far in the past + /// + /// The related routine can only operate on time points occurring within its immediate record of + /// the past. + /// + eLeapRS_TimestampTooEarly = 0xE201000E, + /// + /// LeapPollConnection is called concurrently. + /// + eLeapRS_ConcurrentPoll = 0xE201000F, + /// + /// A connection to the Leap Motion service could not be established. + /// + eLeapRS_NotAvailable = 0xE7010002, + /// + /// The requested operation can only be performed while the device is sending data. + /// + eLeapRS_NotStreaming = 0xE7010004, + /// + /// The specified device could not be opened. It is possible that the device identifier + /// is invalid, or that the device has been disconnected since being enumerated. + /// + eLeapRS_CannotOpenDevice = 0xE7010005, + }; + + public enum eLeapEventType + { + /// + /// No event has occurred within the timeout period specified when calling LeapPollConnection(). + /// + eLeapEventType_None = 0, + /// + /// A connection to the Leap Motion service has been established. + /// + eLeapEventType_Connection, + /// + /// The connection to the Leap Motion service has been lost. + /// + eLeapEventType_ConnectionLost, + /// + /// A device has been detected or plugged-in. + /// A device event is dispatched after a connection is established for any + /// devices already plugged in. (The system currently only supports one + /// streaming device at a time.) + /// + eLeapEventType_Device, + /// + /// Note that unplugging a device generates an eLeapEventType_DeviceLost event + /// message, not a failure message. + /// + eLeapEventType_DeviceFailure, + /// + /// A policy change has occurred. + /// This can be due to setting a policy with LeapSetPolicyFlags() or due to changing + /// or policy-related config settings, including images_mode. + /// (A user can also change these policies using the Leap Motion Control Panel.) + /// + eLeapEventType_Policy, + /// + /// A tracking frame. The message contains the tracking data for the frame. + /// + eLeapEventType_Tracking = 0x100, + /// + /// The request for an image has failed. + /// The message contains information about the failure. The client application + /// will not receive the requested image set. + /// + eLeapEventType_ImageRequestError, + /// + /// The request for an image is complete. + /// The image data has been completely written to the application-provided + /// buffer. + /// + eLeapEventType_ImageComplete, + /// + /// A system message. + /// + eLeapEventType_LogEvent, + /// + /// The device connection has been lost. + /// + /// This event is generally asserted when the device has been detached from the system, when the + /// connection to the service has been lost, or if the device is closed while streaming. Generally, + /// any event where the system can conclude no further frames will be received will result in this + /// message. The DeviceEvent field will be filled with the id of the formerly attached device. + /// + eLeapEventType_DeviceLost, + /// + /// The asynchronous response to a call to LeapRequestConfigValue(). + /// Contains the value of requested configuration item. + /// + eLeapEventType_ConfigResponse, + /// + /// The asynchronous response to a call to LeapSaveConfigValue(). + /// Reports whether the change succeeded or failed. + /// + eLeapEventType_ConfigChange, + /// + /// Notification that a status change has been detected on an attached device. + /// + eLeapEventType_DeviceStatusChange, + /// + /// A tracking frame has been dropped by the service. + /// + eLeapEventType_DroppedFrame, + /// + /// Notification that an unrequested stereo image pair is available. + /// + eLeapEventType_Image, + /// + /// Notification that point mapping has changed. + /// + eLeapEventType_PointMappingChange, + /// + /// An array of system messages. + /// + eLeapEventType_LogEvents, + /// + /// A new head pose is available. + /// + eLeapEventType_HeadPose + }; + + public enum eLeapDeviceFlag : uint + { + /// + /// Flag set if the device is presently streaming frames + /// + /// This flag is updated when the user pauses or resumes tracking on the device from the Leap control + /// panel. Modification of this flag will fail if the AllowPauseResume policy is not set on this device + /// object. + /// + eLeapDeviceFlag_Stream = 0x00000001 + }; + + public enum eLeapDroppedFrameType + { + eLeapDroppedFrameType_PreprocessingQueue, + eLeapDroppedFrameType_TrackingQueue, + eLeapDroppedFrameType_Other + }; + + //Note the following LeapC structs are just IntPtrs in C#: + // LEAP_CONNECTION is an IntPtr + // LEAP_DEVICE is an IntPtr + // LEAP_CLOCK_REBASER is an IntPtr + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct LEAP_CONNECTION_CONFIG + { + public UInt32 size; + public UInt32 flags; + public IntPtr server_namespace; //char* + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_CONNECTION_INFO + { + public UInt32 size; + public eLeapConnectionStatus status; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_CONNECTION_EVENT + { + public eLeapServiceDisposition flags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_DEVICE_REF + { + public IntPtr handle; //void * + public UInt32 id; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_CONNECTION_LOST_EVENT + { + public UInt32 flags; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_ALLOCATOR + { + [MarshalAs(UnmanagedType.FunctionPtr)] + public Allocate allocate; + [MarshalAs(UnmanagedType.FunctionPtr)] + public Deallocate deallocate; + public IntPtr state; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_DEVICE_EVENT + { + public UInt32 flags; + public LEAP_DEVICE_REF device; + public eLeapDeviceStatus status; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_DEVICE_STATUS_CHANGE_EVENT + { + public LEAP_DEVICE_REF device; + public eLeapDeviceStatus last_status; + public eLeapDeviceStatus status; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_DEVICE_FAILURE_EVENT + { + public eLeapDeviceStatus status; + public IntPtr hDevice; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_TRACKING_EVENT + { + public LEAP_FRAME_HEADER info; + public Int64 tracking_id; + public UInt32 nHands; + public IntPtr pHands; //LEAP_HAND* + public float framerate; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_DROPPED_FRAME_EVENT + { + public Int64 frame_id; + public eLeapDroppedFrameType reason; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_POINT_MAPPING_CHANGE_EVENT + { + public Int64 frame_id; + public Int64 timestamp; + public UInt32 nPoints; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_POINT_MAPPING + { + public Int64 frame_id; + public Int64 timestamp; + public UInt32 nPoints; + public IntPtr points; //LEAP_VECTOR* + public IntPtr ids; //uint32* + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_HEAD_POSE_EVENT + { + public Int64 timestamp; + public LEAP_VECTOR head_position; + public LEAP_QUATERNION head_orientation; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_CONNECTION_MESSAGE + { + public UInt32 size; + public eLeapEventType type; + public IntPtr eventStructPtr; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_DISCONNECTION_EVENT + { + public UInt32 reserved; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct LEAP_DEVICE_INFO + { + public UInt32 size; + public UInt32 status; + public eLeapDeviceCaps caps; + public eLeapDeviceType type; + public UInt32 baseline; + public UInt32 serial_length; + public IntPtr serial; //char* + public float h_fov; + public float v_fov; + public UInt32 range; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_FRAME_HEADER + { + public IntPtr reserved; + public Int64 frame_id; + public Int64 timestamp; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_IMAGE_PROPERTIES + { + public eLeapImageType type; + public eLeapImageFormat format; + public UInt32 bpp; + public UInt32 width; + public UInt32 height; + public float x_scale; + public float y_scale; + public float x_offset; + public float y_offset; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_IMAGE + { + public LEAP_IMAGE_PROPERTIES properties; + public UInt64 matrix_version; + + //LEAP_DISTORTION_MATRIX* + //The struct LEAP_DISTORTION_MATRIX cannot exist in c# without using unsafe code + //This is ok though, since it is just an array of floats + //so you need to manually marshal this pointer to the correct size and type + //See LeapC.h for details + public IntPtr distortionMatrix; + public IntPtr data; // void* of an allocator-supplied buffer + public UInt32 offset; // Offset, in bytes, from beginning of buffer to start of image data + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_IMAGE_EVENT + { + public LEAP_FRAME_HEADER info; + public LEAP_IMAGE leftImage; + public LEAP_IMAGE rightImage; + public IntPtr calib; //LEAP_CALIBRATION + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_VECTOR + { + public float x; + public float y; + public float z; + + public Leap.Vector ToLeapVector() + { + return new Leap.Vector(x, y, z); + } + + public LEAP_VECTOR(Leap.Vector leap) + { + x = leap.x; + y = leap.y; + z = leap.z; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_QUATERNION + { + public float x; + public float y; + public float z; + public float w; + + public Leap.LeapQuaternion ToLeapQuaternion() + { + return new Leap.LeapQuaternion(x, y, z, w); + } + + public LEAP_QUATERNION(Leap.LeapQuaternion q) + { + x = q.x; + y = q.y; + z = q.z; + w = q.w; + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_MATRIX_3x3 + { + public LEAP_VECTOR m1; + public LEAP_VECTOR m2; + public LEAP_VECTOR m3; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_BONE + { + public LEAP_VECTOR prev_joint; + public LEAP_VECTOR next_joint; + public float width; + public LEAP_QUATERNION rotation; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_DIGIT + { + public Int32 finger_id; + public LEAP_BONE metacarpal; + public LEAP_BONE proximal; + public LEAP_BONE intermediate; + public LEAP_BONE distal; + public Int32 is_extended; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_PALM + { + public LEAP_VECTOR position; + public LEAP_VECTOR stabilized_position; + public LEAP_VECTOR velocity; + public LEAP_VECTOR normal; + public float width; + public LEAP_VECTOR direction; + public LEAP_QUATERNION orientation; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_HAND + { + public UInt32 id; + public UInt32 flags; + public eLeapHandType type; + public float confidence; + public UInt64 visible_time; + public float pinch_distance; + public float grab_angle; + public float pinch_strength; + public float grab_strength; + public LEAP_PALM palm; + public LEAP_DIGIT thumb; + public LEAP_DIGIT index; + public LEAP_DIGIT middle; + public LEAP_DIGIT ring; + public LEAP_DIGIT pinky; + public LEAP_BONE arm; + } + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_TIP + { + public LEAP_VECTOR position; + public float radius; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct LEAP_LOG_EVENT + { + public eLeapLogSeverity severity; + public Int64 timestamp; + public IntPtr message; //char* + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct LEAP_POLICY_EVENT + { + public UInt32 reserved; + public UInt32 current_policy; + } + + [StructLayout(LayoutKind.Explicit, Pack = 1)] + public struct LEAP_VARIANT_VALUE_TYPE + { + [FieldOffset(0)] + public eLeapValueType type; + [FieldOffset(4)] + public Int32 boolValue; + [FieldOffset(4)] + public Int32 intValue; + [FieldOffset(4)] + public float floatValue; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct LEAP_VARIANT_REF_TYPE + { + public eLeapValueType type; + public string stringValue; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_CONFIG_RESPONSE_EVENT + { + public UInt32 requestId; + public LEAP_VARIANT_VALUE_TYPE value; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct LEAP_CONFIG_RESPONSE_EVENT_WITH_REF_TYPE + { + public UInt32 requestId; + public LEAP_VARIANT_REF_TYPE value; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct LEAP_CONFIG_CHANGE_EVENT + { + public UInt32 requestId; + public bool status; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct LEAP_TELEMETRY_DATA + { + public UInt32 threadId; + public UInt64 startTime; + public UInt64 endTime; + public UInt32 zoneDepth; + public string fileName; + public UInt32 lineNumber; + public string zoneName; + } + + public class LeapC + { + private LeapC() { } + public static int DistortionSize = 64; + + [DllImport("LeapC", EntryPoint = "LeapGetNow")] + public static extern long GetNow(); + + [DllImport("LeapC", EntryPoint = "LeapCreateClockRebaser")] + public static extern eLeapRS CreateClockRebaser(out IntPtr phClockRebaser); + + [DllImport("LeapC", EntryPoint = "LeapDestroyClockRebaser")] + public static extern eLeapRS DestroyClockRebaser(IntPtr hClockRebaser); + + [DllImport("LeapC", EntryPoint = "LeapUpdateRebase")] + public static extern eLeapRS UpdateRebase(IntPtr hClockRebaser, Int64 userClock, Int64 leapClock); + + [DllImport("LeapC", EntryPoint = "LeapRebaseClock")] + public static extern eLeapRS RebaseClock(IntPtr hClockRebaser, Int64 userClock, out Int64 leapClock); + + [DllImport("LeapC", EntryPoint = "LeapCreateConnection")] + public static extern eLeapRS CreateConnection(ref LEAP_CONNECTION_CONFIG pConfig, out IntPtr pConnection); + + //Overrides to allow config to be set to null to use default config + [DllImport("LeapC", EntryPoint = "LeapCreateConnection")] + private static extern eLeapRS CreateConnection(IntPtr nulled, out IntPtr pConnection); + public static eLeapRS CreateConnection(out IntPtr pConnection) + { + return CreateConnection(IntPtr.Zero, out pConnection); + } + + [DllImport("LeapC", EntryPoint = "LeapGetConnectionInfo")] + public static extern eLeapRS GetConnectionInfo(IntPtr hConnection, ref LEAP_CONNECTION_INFO pInfo); + + [DllImport("LeapC", EntryPoint = "LeapOpenConnection")] + public static extern eLeapRS OpenConnection(IntPtr hConnection); + + [DllImport("LeapC", EntryPoint = "LeapSetAllocator")] + public static extern eLeapRS SetAllocator(IntPtr hConnection, ref LEAP_ALLOCATOR pAllocator); + + [DllImport("LeapC", EntryPoint = "LeapGetDeviceList")] + public static extern eLeapRS GetDeviceList(IntPtr hConnection, [In, Out] LEAP_DEVICE_REF[] pArray, out UInt32 pnArray); + + [DllImport("LeapC", EntryPoint = "LeapGetDeviceList")] + private static extern eLeapRS GetDeviceList(IntPtr hConnection, [In, Out] IntPtr pArray, out UInt32 pnArray); + //Override to allow pArray argument to be set to null (IntPtr.Zero) in order to get the device count + public static eLeapRS GetDeviceCount(IntPtr hConnection, out UInt32 deviceCount) + { + return GetDeviceList(hConnection, IntPtr.Zero, out deviceCount); + } + + [DllImport("LeapC", EntryPoint = "LeapOpenDevice")] + public static extern eLeapRS OpenDevice(LEAP_DEVICE_REF rDevice, out IntPtr pDevice); + + [DllImport("LeapC", EntryPoint = "LeapGetDeviceInfo", CharSet = CharSet.Ansi)] + public static extern eLeapRS GetDeviceInfo(IntPtr hDevice, ref LEAP_DEVICE_INFO info); + + [DllImport("LeapC", EntryPoint = "LeapSetPolicyFlags")] + public static extern eLeapRS SetPolicyFlags(IntPtr hConnection, UInt64 set, UInt64 clear); + + [DllImport("LeapC", EntryPoint = "LeapSetPause")] + public static extern eLeapRS LeapSetPause(IntPtr hConnection, bool pause); + + [DllImport("LeapC", EntryPoint = "LeapPollConnection")] + public static extern eLeapRS PollConnection(IntPtr hConnection, UInt32 timeout, ref LEAP_CONNECTION_MESSAGE msg); + + [DllImport("LeapC", EntryPoint = "LeapGetFrameSize")] + public static extern eLeapRS GetFrameSize(IntPtr hConnection, Int64 timestamp, out UInt64 pncbEvent); + + [DllImport("LeapC", EntryPoint = "LeapInterpolateFrame")] + public static extern eLeapRS InterpolateFrame(IntPtr hConnection, Int64 timestamp, IntPtr pEvent, UInt64 ncbEvent); + + [DllImport("LeapC", EntryPoint = "LeapInterpolateFrameFromTime")] + public static extern eLeapRS InterpolateFrameFromTime(IntPtr hConnection, Int64 timestamp, Int64 sourceTimestamp, IntPtr pEvent, UInt64 ncbEvent); + + [DllImport("LeapC", EntryPoint = "LeapInterpolateHeadPose")] + public static extern eLeapRS InterpolateHeadPose(IntPtr hConnection, Int64 timestamp, ref LEAP_HEAD_POSE_EVENT headPose); + + [DllImport("LeapC", EntryPoint = "LeapPixelToRectilinear")] + public static extern LEAP_VECTOR LeapPixelToRectilinear(IntPtr hConnection, eLeapPerspectiveType camera, LEAP_VECTOR pixel); + + [DllImport("LeapC", EntryPoint = "LeapRectilinearToPixel")] + public static extern LEAP_VECTOR LeapRectilinearToPixel(IntPtr hConnection, eLeapPerspectiveType camera, LEAP_VECTOR rectilinear); + + [DllImport("LeapC", EntryPoint = "LeapCloseDevice")] + public static extern void CloseDevice(IntPtr pDevice); + + [DllImport("LeapC", EntryPoint = "LeapCloseConnection")] + public static extern eLeapRS CloseConnection(IntPtr hConnection); + + [DllImport("LeapC", EntryPoint = "LeapDestroyConnection")] + public static extern void DestroyConnection(IntPtr connection); + + [DllImport("LeapC", EntryPoint = "LeapSaveConfigValue")] + private static extern eLeapRS SaveConfigValue(IntPtr hConnection, string key, IntPtr value, out UInt32 requestId); + + [DllImport("LeapC", EntryPoint = "LeapRequestConfigValue")] + public static extern eLeapRS RequestConfigValue(IntPtr hConnection, string name, out UInt32 request_id); + + public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, bool value, out UInt32 requestId) + { + LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE(); //This is a C# approximation of a C union + valueStruct.type = eLeapValueType.eLeapValueType_Boolean; + valueStruct.boolValue = value ? 1 : 0; + return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId); + } + public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, Int32 value, out UInt32 requestId) + { + LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE(); + valueStruct.type = eLeapValueType.eLeapValueType_Int32; + valueStruct.intValue = value; + return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId); + } + public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, float value, out UInt32 requestId) + { + LEAP_VARIANT_VALUE_TYPE valueStruct = new LEAP_VARIANT_VALUE_TYPE(); + valueStruct.type = eLeapValueType.eLeapValueType_Float; + valueStruct.floatValue = value; + return SaveConfigWithValueType(hConnection, key, valueStruct, out requestId); + } + public static eLeapRS SaveConfigValue(IntPtr hConnection, string key, string value, out UInt32 requestId) + { + LEAP_VARIANT_REF_TYPE valueStruct; + valueStruct.type = eLeapValueType.eLeapValueType_String; + valueStruct.stringValue = value; + return SaveConfigWithRefType(hConnection, key, valueStruct, out requestId); + } + private static eLeapRS SaveConfigWithValueType(IntPtr hConnection, string key, LEAP_VARIANT_VALUE_TYPE valueStruct, out UInt32 requestId) + { + IntPtr configValue = Marshal.AllocHGlobal(Marshal.SizeOf(valueStruct)); + eLeapRS callResult = eLeapRS.eLeapRS_UnknownError; + try + { + Marshal.StructureToPtr(valueStruct, configValue, false); + callResult = SaveConfigValue(hConnection, key, configValue, out requestId); + } + finally + { + Marshal.FreeHGlobal(configValue); + } + return callResult; + } + private static eLeapRS SaveConfigWithRefType(IntPtr hConnection, string key, LEAP_VARIANT_REF_TYPE valueStruct, out UInt32 requestId) + { + IntPtr configValue = Marshal.AllocHGlobal(Marshal.SizeOf(valueStruct)); + eLeapRS callResult = eLeapRS.eLeapRS_UnknownError; + try + { + Marshal.StructureToPtr(valueStruct, configValue, false); + callResult = SaveConfigValue(hConnection, key, configValue, out requestId); + } + finally + { + Marshal.FreeHGlobal(configValue); + } + return callResult; + } + + [DllImport("LeapC", EntryPoint = "LeapGetPointMappingSize")] + public static extern eLeapRS GetPointMappingSize(IntPtr hConnection, ref ulong pSize); + + [DllImport("LeapC", EntryPoint = "LeapGetPointMapping")] + public static extern eLeapRS GetPointMapping(IntPtr hConnection, IntPtr pointMapping, ref ulong pSize); + + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct LEAP_RECORDING_PARAMETERS + { + public UInt32 mode; + } + [StructLayout(LayoutKind.Sequential, Pack = 1, CharSet = CharSet.Ansi)] + public struct LEAP_RECORDING_STATUS + { + public UInt32 mode; + } + + [DllImport("LeapC", EntryPoint = "LeapRecordingOpen")] + public static extern eLeapRS RecordingOpen(ref IntPtr ppRecording, string userPath, LEAP_RECORDING_PARAMETERS parameters); + + [DllImport("LeapC", EntryPoint = "LeapRecordingClose")] + public static extern eLeapRS RecordingClose(ref IntPtr ppRecording); + + [DllImport("LeapC", EntryPoint = "LeapRecordingGetStatus")] + public static extern eLeapRS LeapRecordingGetStatus(IntPtr pRecording, ref LEAP_RECORDING_STATUS status); + + [DllImport("LeapC", EntryPoint = "LeapRecordingReadSize")] + public static extern eLeapRS RecordingReadSize(IntPtr pRecording, ref UInt64 pncbEvent); + + [DllImport("LeapC", EntryPoint = "LeapRecordingRead")] + public static extern eLeapRS RecordingRead(IntPtr pRecording, ref LEAP_TRACKING_EVENT pEvent, UInt64 ncbEvent); + + [DllImport("LeapC", EntryPoint = "LeapRecordingWrite")] + public static extern eLeapRS RecordingWrite(IntPtr pRecording, ref LEAP_TRACKING_EVENT pEvent, ref UInt64 pnBytesWritten); + + [DllImport("LeapC", EntryPoint = "LeapTelemetryProfiling")] + public static extern eLeapRS LeapTelemetryProfiling(IntPtr hConnection, ref LEAP_TELEMETRY_DATA telemetryData); + + [DllImport("LeapC", EntryPoint = "LeapTelemetryGetNow")] + public static extern UInt64 TelemetryGetNow(); + } +} diff --git a/vendor/LeapCSharp/LeapQuaternion.cs b/vendor/LeapCSharp/LeapQuaternion.cs new file mode 100644 index 00000000..76b0dad8 --- /dev/null +++ b/vendor/LeapCSharp/LeapQuaternion.cs @@ -0,0 +1,171 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + + /// + /// The LeapQuaternion struct represents a rotation in three-dimensional space. + /// @since 3.1.2 + /// + [Serializable] + public struct LeapQuaternion : + IEquatable + { + + /// + /// Creates a new LeapQuaternion with the specified component values. + /// @since 3.1.2 + /// + public LeapQuaternion(float x, float y, float z, float w) : + this() + { + this.x = x; + this.y = y; + this.z = z; + this.w = w; + } + + /// + /// Copies the specified LeapQuaternion. + /// @since 3.1.2 + /// + public LeapQuaternion(LeapQuaternion quaternion) : + this() + { + x = quaternion.x; + y = quaternion.y; + z = quaternion.z; + w = quaternion.w; + } + + /// + /// Copies the specified LEAP_QUATERNION. + /// @since 3.1.2 + /// + public LeapQuaternion(LeapInternal.LEAP_QUATERNION quaternion) : + this() + { + x = quaternion.x; + y = quaternion.y; + z = quaternion.z; + w = quaternion.w; + } + + /// + /// Returns a string containing this quaternion in a human readable format: (x, y, z). + /// @since 3.1.2 + /// + public override string ToString() + { + return "(" + x + ", " + y + ", " + z + ", " + w + ")"; + } + + /// + /// Compare LeapQuaternion equality component-wise. + /// @since 3.1.2 + /// + public bool Equals(LeapQuaternion v) + { + return x.NearlyEquals(v.x) && y.NearlyEquals(v.y) && z.NearlyEquals(v.z) && w.NearlyEquals(v.w); + } + public override bool Equals(Object obj) + { + return obj is LeapQuaternion && Equals((LeapQuaternion)obj); + } + + /// + /// Returns true if all of the quaternion's components are finite. If any + /// component is NaN or infinite, then this returns false. + /// @since 3.1.2 + /// + public bool IsValid() + { + return !(float.IsNaN(x) || float.IsInfinity(x) || + float.IsNaN(y) || float.IsInfinity(y) || + float.IsNaN(z) || float.IsInfinity(z) || + float.IsNaN(w) || float.IsInfinity(w)); + } + + public float x; + public float y; + public float z; + public float w; + + /// + /// The magnitude, or length, of this quaternion. + /// @since 3.1.2 + /// + public float Magnitude + { + get { return (float)Math.Sqrt(x * x + y * y + z * z + w * w); } + } + + /// + /// The square of the magnitude, or length, of this quaternion. + /// @since 3.1.2 + /// + public float MagnitudeSquared + { + get { return x * x + y * y + z * z + w * w; } + } + + /// + /// A normalized copy of this quaternion. + /// @since 3.1.2 + /// + public LeapQuaternion Normalized + { + get + { + float denom = MagnitudeSquared; + if (denom <= Constants.EPSILON) + { + return Identity; + } + denom = 1.0f / (float)Math.Sqrt(denom); + return new LeapQuaternion(x * denom, y * denom, z * denom, w * denom); + } + } + + /// + /// Concatenates the rotation described by this quaternion with the one provided + /// and returns the result. + /// @since 3.1.2 + /// + public LeapQuaternion Multiply(LeapQuaternion rhs) + { + return new LeapQuaternion( + w * rhs.x + x * rhs.w + y * rhs.z - z * rhs.y, + w * rhs.y + y * rhs.w + z * rhs.x - x * rhs.z, + w * rhs.z + z * rhs.w + x * rhs.y - y * rhs.x, + w * rhs.w - x * rhs.x - y * rhs.y - z * rhs.z); + } + + /// + /// The identity quaternion. + /// @since 3.1.2 + /// + public static readonly LeapQuaternion Identity = new LeapQuaternion(0, 0, 0, 1); + + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + x.GetHashCode(); + hash = hash * 23 + y.GetHashCode(); + hash = hash * 23 + z.GetHashCode(); + hash = hash * 23 + w.GetHashCode(); + + return hash; + } + } + } +} diff --git a/vendor/LeapCSharp/LeapTransform.cs b/vendor/LeapCSharp/LeapTransform.cs new file mode 100644 index 00000000..a3cf0740 --- /dev/null +++ b/vendor/LeapCSharp/LeapTransform.cs @@ -0,0 +1,277 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + + /// + /// The LeapTransform class represents a transform in three dimensional space. + /// + /// Note that the LeapTransform class replaces the Leap.Matrix class. + /// @since 3.1.2 + /// + public struct LeapTransform + { + /// + /// Constructs a new transform from the specified translation and rotation. + /// @since 3.1.2 + /// + public LeapTransform(Vector translation, LeapQuaternion rotation) : + this(translation, rotation, Vector.Ones) + { + } + + /// + /// Constructs a new transform from the specified translation, rotation and scale. + /// @since 3.1.2 + /// + public LeapTransform(Vector translation, LeapQuaternion rotation, Vector scale) : + this() + { + _scale = scale; + // these are non-trival setters. + this.translation = translation; + this.rotation = rotation; // Calls validateBasis + } + + /// + /// Transforms the specified position vector, applying translation, rotation and scale. + /// @since 3.1.2 + /// + public Vector TransformPoint(Vector point) + { + return _xBasisScaled * point.x + _yBasisScaled * point.y + _zBasisScaled * point.z + translation; + } + + /// + /// Transforms the specified direction vector, applying rotation only. + /// @since 3.1.2 + /// + public Vector TransformDirection(Vector direction) + { + return _xBasis * direction.x + _yBasis * direction.y + _zBasis * direction.z; + } + + /// + /// Transforms the specified velocity vector, applying rotation and scale. + /// @since 3.1.2 + /// + public Vector TransformVelocity(Vector velocity) + { + return _xBasisScaled * velocity.x + _yBasisScaled * velocity.y + _zBasisScaled * velocity.z; + } + + /// + /// Transforms the specified quaternion. + /// Multiplies the quaternion representing the rotational part of this transform by the specified + /// quaternion. + /// + /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in + /// an indeterminate state. Neither this function nor the LeapTransform.rotation quaternion can be used after + /// the basis vectors are set. + /// + /// @since 3.1.2 + /// + public LeapQuaternion TransformQuaternion(LeapQuaternion rhs) + { + if (_quaternionDirty) + throw new InvalidOperationException("Calling TransformQuaternion after Basis vectors have been modified."); + + if (_flip) + { + // Mirror the axis of rotation across the flip axis. + rhs.x *= _flipAxes.x; + rhs.y *= _flipAxes.y; + rhs.z *= _flipAxes.z; + } + + LeapQuaternion t = _quaternion.Multiply(rhs); + return t; + } + + /// + /// Mirrors this transform's rotation and scale across the x-axis. Translation is not affected. + /// @since 3.1.2 + /// + public void MirrorX() + { + _xBasis = -_xBasis; + _xBasisScaled = -_xBasisScaled; + + _flip = true; + _flipAxes.y = -_flipAxes.y; + _flipAxes.z = -_flipAxes.z; + } + + /// + /// Mirrors this transform's rotation and scale across the z-axis. Translation is not affected. + /// @since 3.1.2 + /// + public void MirrorZ() + { + _zBasis = -_zBasis; + _zBasisScaled = -_zBasisScaled; + + _flip = true; + _flipAxes.x = -_flipAxes.x; + _flipAxes.y = -_flipAxes.y; + } + + /// + /// The x-basis of the transform. + /// + /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in + /// an indeterminate state. Neither the TransformQuaternion() function nor the LeapTransform.rotation quaternion + /// can be used after the basis vectors are set. + /// + /// @since 3.1.2 + /// + public Vector xBasis + { + get { return _xBasis; } + set + { + _xBasis = value; + _xBasisScaled = value * scale.x; + _quaternionDirty = true; + } + } + + /// + /// The y-basis of the transform. + /// + /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in + /// an indeterminate state. Neither the TransformQuaternion() function nor the LeapTransform.rotation quaternion + /// can be used after the basis vectors are set. + /// + /// @since 3.1.2 + /// + public Vector yBasis + { + get { return _yBasis; } + set + { + _yBasis = value; + _yBasisScaled = value * scale.y; + _quaternionDirty = true; + } + } + + /// + /// The z-basis of the transform. + /// + /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in + /// an indeterminate state. Neither the TransformQuaternion() function nor the LeapTransform.rotation quaternion + /// can be used after the basis vectors are set. + /// + /// @since 3.1.2 + /// + public Vector zBasis + { + get { return _zBasis; } + set + { + _zBasis = value; + _zBasisScaled = value * scale.z; + _quaternionDirty = true; + } + } + + /// + /// The translation component of the transform. + /// @since 3.1.2 + /// + public Vector translation + { + get { return _translation; } + set + { + _translation = value; + } + } + + /// + /// The scale factors of the transform. + /// Scale is kept separate from translation. + /// @since 3.1.2 + /// + public Vector scale + { + get { return _scale; } + set + { + _scale = value; + _xBasisScaled = _xBasis * scale.x; + _yBasisScaled = _yBasis * scale.y; + _zBasisScaled = _zBasis * scale.z; + } + } + + /// + /// The rotational component of the transform. + /// + /// **Important:** Modifying the basis vectors of this transform directly leaves the underlying quaternion in + /// an indeterminate state. This rotation quaternion cannot be accessed after + /// the basis vectors are modified directly. + /// + /// @since 3.1.2 + /// + public LeapQuaternion rotation + { + get + { + if (_quaternionDirty) + throw new InvalidOperationException("Requesting rotation after Basis vectors have been modified."); + return _quaternion; + } + set + { + _quaternion = value; + + float d = value.MagnitudeSquared; + float s = 2.0f / d; + float xs = value.x * s, ys = value.y * s, zs = value.z * s; + float wx = value.w * xs, wy = value.w * ys, wz = value.w * zs; + float xx = value.x * xs, xy = value.x * ys, xz = value.x * zs; + float yy = value.y * ys, yz = value.y * zs, zz = value.z * zs; + + _xBasis = new Vector(1.0f - (yy + zz), xy + wz, xz - wy); + _yBasis = new Vector(xy - wz, 1.0f - (xx + zz), yz + wx); + _zBasis = new Vector(xz + wy, yz - wx, 1.0f - (xx + yy)); + + _xBasisScaled = _xBasis * scale.x; + _yBasisScaled = _yBasis * scale.y; + _zBasisScaled = _zBasis * scale.z; + + _quaternionDirty = false; + _flip = false; + _flipAxes = new Vector(1.0f, 1.0f, 1.0f); + } + } + + /// + /// The identity transform. + /// @since 3.1.2 + /// + public static readonly LeapTransform Identity = new LeapTransform(Vector.Zero, LeapQuaternion.Identity, Vector.Ones); + + private Vector _translation; + private Vector _scale; + private LeapQuaternion _quaternion; + private bool _quaternionDirty; + private bool _flip; + private Vector _flipAxes; + private Vector _xBasis; + private Vector _yBasis; + private Vector _zBasis; + private Vector _xBasisScaled; + private Vector _yBasisScaled; + private Vector _zBasisScaled; + } +} diff --git a/vendor/LeapCSharp/Logger.cs b/vendor/LeapCSharp/Logger.cs new file mode 100644 index 00000000..3e916c4e --- /dev/null +++ b/vendor/LeapCSharp/Logger.cs @@ -0,0 +1,55 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +using System; +using System.Reflection; + +namespace LeapInternal +{ + public static class Logger + { + + /// + /// Logs message to the a Console. + /// + public static void Log(object message) + { + //UnityEngine.Debug.Log(message); + } + + public static void LogStruct(object thisObject, string title = "") + { + try + { + if (!thisObject.GetType().IsValueType) + { + Log(title + " ---- Trying to log non-struct with struct logger"); + return; + } + Log(title + " ---- " + thisObject.GetType().ToString()); + FieldInfo[] fieldInfos; + fieldInfos = thisObject.GetType().GetFields( + BindingFlags.Public | BindingFlags.NonPublic // Get public and non-public + | BindingFlags.Static | BindingFlags.Instance // Get instance + static + | BindingFlags.FlattenHierarchy); // Search up the hierarchy + + // write member names + foreach (FieldInfo fieldInfo in fieldInfos) + { + object obj = fieldInfo.GetValue(thisObject); + string value = obj == null ? "null" : obj.ToString(); + Log(" -------- Name: " + fieldInfo.Name + ", Value = " + value); + } + } + catch (Exception exception) + { + Log(exception.Message); + } + } + } +} diff --git a/vendor/LeapCSharp/Matrix.cs b/vendor/LeapCSharp/Matrix.cs new file mode 100644 index 00000000..44bf58ff --- /dev/null +++ b/vendor/LeapCSharp/Matrix.cs @@ -0,0 +1,362 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + + /// + /// The Matrix struct represents a transformation matrix. + /// + /// To use this struct to transform a Vector, construct a matrix containing the + /// desired transformation and then use the Matrix::transformPoint() or + /// Matrix.TransformDirection() functions to apply the transform. + /// + /// Transforms can be combined by multiplying two or more transform matrices using + /// the * operator. + /// @since 1.0 + /// + public struct Matrix + { + + /// + /// Multiply two matrices. + /// + public static Matrix operator *(Matrix m1, Matrix m2) + { + return m1._operator_mul(m2); + } + + /// + /// Copy this matrix to the specified array of 9 float values in row-major order. + /// + public float[] ToArray3x3(float[] output) + { + output[0] = xBasis.x; + output[1] = xBasis.y; + output[2] = xBasis.z; + output[3] = yBasis.x; + output[4] = yBasis.y; + output[5] = yBasis.z; + output[6] = zBasis.x; + output[7] = zBasis.y; + output[8] = zBasis.z; + return output; + } + + /// + /// Copy this matrix to the specified array containing 9 double values in row-major order. + /// + public double[] ToArray3x3(double[] output) + { + output[0] = xBasis.x; + output[1] = xBasis.y; + output[2] = xBasis.z; + output[3] = yBasis.x; + output[4] = yBasis.y; + output[5] = yBasis.z; + output[6] = zBasis.x; + output[7] = zBasis.y; + output[8] = zBasis.z; + return output; + } + + /// + /// Convert this matrix to an array containing 9 float values in row-major order. + /// + public float[] ToArray3x3() + { + return ToArray3x3(new float[9]); + } + + /// + /// Copy this matrix to the specified array of 16 float values in row-major order. + /// + public float[] ToArray4x4(float[] output) + { + output[0] = xBasis.x; + output[1] = xBasis.y; + output[2] = xBasis.z; + output[3] = 0.0f; + output[4] = yBasis.x; + output[5] = yBasis.y; + output[6] = yBasis.z; + output[7] = 0.0f; + output[8] = zBasis.x; + output[9] = zBasis.y; + output[10] = zBasis.z; + output[11] = 0.0f; + output[12] = origin.x; + output[13] = origin.y; + output[14] = origin.z; + output[15] = 1.0f; + return output; + } + + /// + /// Copy this matrix to the specified array of 16 double values in row-major order. + /// + public double[] ToArray4x4(double[] output) + { + output[0] = xBasis.x; + output[1] = xBasis.y; + output[2] = xBasis.z; + output[3] = 0.0f; + output[4] = yBasis.x; + output[5] = yBasis.y; + output[6] = yBasis.z; + output[7] = 0.0f; + output[8] = zBasis.x; + output[9] = zBasis.y; + output[10] = zBasis.z; + output[11] = 0.0f; + output[12] = origin.x; + output[13] = origin.y; + output[14] = origin.z; + output[15] = 1.0f; + return output; + } + + /// + /// Convert this matrix to an array containing 16 float values in row-major order. + /// + public float[] ToArray4x4() + { + return ToArray4x4(new float[16]); + } + + /// + /// Constructs a copy of the specified Matrix object. + /// @since 1.0 + /// + public Matrix(Matrix other) : + this() + { + xBasis = other.xBasis; + yBasis = other.yBasis; + zBasis = other.zBasis; + origin = other.origin; + } + + /// + /// Constructs a transformation matrix from the specified basis vectors. + /// @since 1.0 + /// + public Matrix(Vector xBasis, Vector yBasis, Vector zBasis) : + this() + { + this.xBasis = xBasis; + this.yBasis = yBasis; + this.zBasis = zBasis; + this.origin = Vector.Zero; + } + + /// + /// Constructs a transformation matrix from the specified basis and translation vectors. + /// @since 1.0 + /// + public Matrix(Vector xBasis, Vector yBasis, Vector zBasis, Vector origin) : + this() + { + this.xBasis = xBasis; + this.yBasis = yBasis; + this.zBasis = zBasis; + this.origin = origin; + } + + /// + /// Constructs a transformation matrix specifying a rotation around the specified vector. + /// @since 1.0 + /// + public Matrix(Vector axis, float angleRadians) : + this() + { + xBasis = Vector.XAxis; + yBasis = Vector.YAxis; + zBasis = Vector.ZAxis; + origin = Vector.Zero; + SetRotation(axis, angleRadians); + } + + /// + /// Constructs a transformation matrix specifying a rotation around the specified vector + /// and a translation by the specified vector. + /// @since 1.0 + /// + public Matrix(Vector axis, float angleRadians, Vector translation) : + this() + { + xBasis = Vector.XAxis; + yBasis = Vector.YAxis; + zBasis = Vector.ZAxis; + origin = translation; + this.SetRotation(axis, angleRadians); + } + + public Matrix(float m00, + float m01, + float m02, + float m10, + float m11, + float m12, + float m20, + float m21, + float m22) : + this() + { + xBasis = new Vector(m00, m01, m02); + yBasis = new Vector(m10, m11, m12); + zBasis = new Vector(m20, m21, m22); + origin = Vector.Zero; + } + + public Matrix(float m00, + float m01, + float m02, + float m10, + float m11, + float m12, + float m20, + float m21, + float m22, + float m30, + float m31, + float m32) : + this() + { + xBasis = new Vector(m00, m01, m02); + yBasis = new Vector(m10, m11, m12); + zBasis = new Vector(m20, m21, m22); + origin = new Vector(m30, m31, m32); + } + + /// + /// Sets this transformation matrix to represent a rotation around the specified vector. + /// + /// This function erases any previous rotation and scale transforms applied + /// to this matrix, but does not affect translation. + /// + /// @since 1.0 + /// + public void SetRotation(Vector axis, float angleRadians) + { + Vector n = axis.Normalized; + float s = (float)Math.Sin(angleRadians); + float c = (float)Math.Cos(angleRadians); + float C = (1 - c); + + xBasis = new Vector(n[0] * n[0] * C + c, n[0] * n[1] * C - n[2] * s, n[0] * n[2] * C + n[1] * s); + yBasis = new Vector(n[1] * n[0] * C + n[2] * s, n[1] * n[1] * C + c, n[1] * n[2] * C - n[0] * s); + zBasis = new Vector(n[2] * n[0] * C - n[1] * s, n[2] * n[1] * C + n[0] * s, n[2] * n[2] * C + c); + } + + /// + /// Transforms a vector with this matrix by transforming its rotation, + /// scale, and translation. + /// + /// Translation is applied after rotation and scale. + /// + /// @since 1.0 + /// + public Vector TransformPoint(Vector point) + { + return xBasis * point.x + yBasis * point.y + zBasis * point.z + origin; + } + + /// + /// Transforms a vector with this matrix by transforming its rotation and + /// scale only. + /// @since 1.0 + /// + public Vector TransformDirection(Vector direction) + { + return xBasis * direction.x + yBasis * direction.y + zBasis * direction.z; + } + + /// + /// Performs a matrix inverse if the matrix consists entirely of rigid + /// transformations (translations and rotations). If the matrix is not rigid, + /// this operation will not represent an inverse. + /// + /// Note that all matrices that are directly returned by the API are rigid. + /// + /// @since 1.0 + /// + public Matrix RigidInverse() + { + Matrix rotInverse = new Matrix(new Vector(xBasis[0], yBasis[0], zBasis[0]), + new Vector(xBasis[1], yBasis[1], zBasis[1]), + new Vector(xBasis[2], yBasis[2], zBasis[2])); + rotInverse.origin = rotInverse.TransformDirection(-origin); + return rotInverse; + } + + /// + /// Multiply transform matrices. + /// Combines two transformations into a single equivalent transformation. + /// @since 1.0 + /// + private Matrix _operator_mul(Matrix other) + { + return new Matrix(TransformDirection(other.xBasis), + TransformDirection(other.yBasis), + TransformDirection(other.zBasis), + TransformPoint(other.origin)); + } + + /// + /// Compare Matrix equality component-wise. + /// @since 1.0 + /// + public bool Equals(Matrix other) + { + return xBasis == other.xBasis && + yBasis == other.yBasis && + zBasis == other.zBasis && + origin == other.origin; + } + + /// + /// Write the matrix to a string in a human readable format. + /// + public override string ToString() + { + return string.Format("xBasis: {0} yBasis: {1} zBasis: {2} origin: {3}", xBasis, yBasis, zBasis, origin); + } + + /// + /// The basis vector for the x-axis. + /// @since 1.0 + /// + public Vector xBasis { get; set; } + + /// + /// The basis vector for the y-axis. + /// @since 1.0 + /// + public Vector yBasis { get; set; } + + /// + /// The basis vector for the z-axis. + /// @since 1.0 + /// + public Vector zBasis { get; set; } + + /// + /// The translation factors for all three axes. + /// @since 1.0 + /// + public Vector origin { get; set; } + + /// + /// Returns the identity matrix specifying no translation, rotation, and scale. + /// @since 1.0 + /// + public static readonly Matrix Identity = new Matrix(Vector.XAxis, Vector.YAxis, Vector.ZAxis, Vector.Zero); + } +} diff --git a/vendor/LeapCSharp/MemoryManager.cs b/vendor/LeapCSharp/MemoryManager.cs new file mode 100644 index 00000000..f5083605 --- /dev/null +++ b/vendor/LeapCSharp/MemoryManager.cs @@ -0,0 +1,190 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +//using AOT; +using System; +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Runtime.InteropServices; + +namespace LeapInternal +{ + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate IntPtr Allocate(UInt32 size, eLeapAllocatorType typeHint, IntPtr state); + + [UnmanagedFunctionPointer(CallingConvention.Cdecl)] + public delegate void Deallocate(IntPtr buffer, IntPtr state); + + public static class MemoryManager + { + + /// + /// Specifies whether or not a pooling strategy should be used for the + /// internal MemoryManager. If enabled, memory will be periodically + /// recycled to be used again instead of being deallocated. + /// + /// An object may be reclaimed from the pool at any time on the + /// worker thread. If you are running into issues where an object + /// you are working with is being overwritten, consider making a copy, + /// or turning up the MinPoolSize. + /// + public static bool EnablePooling = true; + + /// + /// Specifies how many objects of a specific type need to be in the pool + /// before they will start to be recycled. Turning this number up can + /// help prevent issues where objects you are working with are being + /// overwritten with new objects. Turning this number down can reduce + /// the total memory footprint used by the memory manager. + /// + public static uint MinPoolSize = 64; + + private static ConcurrentDictionary _activeMemory = + new ConcurrentDictionary(); + private static ConcurrentDictionary> _pooledMemory = + new ConcurrentDictionary>(); + + //[MonoPInvokeCallback(typeof(Allocate))] + public static IntPtr Pin(UInt32 size, eLeapAllocatorType typeHint, IntPtr state) + { + try + { + //Construct a key to identify the desired allocation + PoolKey key = new PoolKey() + { + type = typeHint, + size = size + }; + + //Attempt to find the pool that holds this type of allocation + Queue pool; + if (!_pooledMemory.TryGetValue(key, out pool)) + { + //Construct a new pool if none exists yet + pool = new Queue(); + _pooledMemory[key] = pool; + } + + //Attempt to get an object from the pool + object memory; + if (EnablePooling && pool.Count > MinPoolSize) + { + memory = pool.Dequeue(); + } + else + { + //If the pool is empty, we need to construct a new object + switch (typeHint) + { + default: + case eLeapAllocatorType.eLeapAllocatorType_Uint8: + memory = new byte[size]; + break; + case eLeapAllocatorType.eLeapAllocatorType_Float: + memory = new float[(size + sizeof(float) - 1) / sizeof(float)]; + break; + } + } + + //Pin the object so its address will not change + GCHandle handle = GCHandle.Alloc(memory, GCHandleType.Pinned); + IntPtr ptr = handle.AddrOfPinnedObject(); + + //Put the information about the newly pinned allocation into the + //active memory map so it can be retrieved and freed layer. + _activeMemory.TryAdd(ptr, new ActiveMemoryInfo() + { + handle = handle, + key = key + }); + + return ptr; + } + catch (Exception e) + { + //UnityEngine.Debug.LogException(e); + } + + return IntPtr.Zero; + } + + //[MonoPInvokeCallback(typeof(Deallocate))] + public static void Unpin(IntPtr ptr, IntPtr state) + { + try + { + //Grab the info for the given pointer + ActiveMemoryInfo info = _activeMemory[ptr]; + + //First we return the object back to its pool + if (EnablePooling) + { + _pooledMemory[info.key].Enqueue(info.handle.Target); + } + + //Then we remove the pointer from the active memory map + ActiveMemoryInfo value; + + _activeMemory.TryRemove(ptr, out value); + + //Finally we unpin the memory + info.handle.Free(); + } + catch (Exception e) + { + //UnityEngine.Debug.LogException(e); + } + } + + public static object GetPinnedObject(IntPtr ptr) + { + try + { + return _activeMemory[ptr].handle.Target; + } + catch (Exception) { } + return null; + } + + private struct PoolKey : IEquatable + { + public eLeapAllocatorType type; + public UInt32 size; + + public override int GetHashCode() + { + return (int)type | (int)size << 4; + } + + public bool Equals(PoolKey other) + { + return type == other.type && + size == other.size; + } + + public override bool Equals(object obj) + { + if (obj is PoolKey) + { + return Equals((PoolKey)obj); + } + else + { + return false; + } + } + } + + private struct ActiveMemoryInfo + { + public GCHandle handle; + public PoolKey key; + } + } +} diff --git a/vendor/LeapCSharp/MessageSeverity.cs b/vendor/LeapCSharp/MessageSeverity.cs new file mode 100644 index 00000000..5e3e619a --- /dev/null +++ b/vendor/LeapCSharp/MessageSeverity.cs @@ -0,0 +1,24 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + /// + /// Reports whether the message is for + /// a severe failure, a recoverable warning, or a status change. + /// @since 3.0 + /// + public enum MessageSeverity + { + MESSAGE_UNKNOWN = 0, + MESSAGE_CRITICAL = 1, + MESSAGE_WARNING = 2, + /** A verbose, informational message */ + MESSAGE_INFORMATION = 3 + } +} diff --git a/vendor/LeapCSharp/PointMapping.cs b/vendor/LeapCSharp/PointMapping.cs new file mode 100644 index 00000000..65956028 --- /dev/null +++ b/vendor/LeapCSharp/PointMapping.cs @@ -0,0 +1,19 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + + public struct PointMapping + { + public long frameId; + public long timestamp; + public Vector[] points; + public uint[] ids; + } +} diff --git a/vendor/LeapCSharp/StructMarshal.cs b/vendor/LeapCSharp/StructMarshal.cs new file mode 100644 index 00000000..610588d2 --- /dev/null +++ b/vendor/LeapCSharp/StructMarshal.cs @@ -0,0 +1,92 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +using System; +using System.Runtime.InteropServices; + +namespace LeapInternal +{ + + /** + * A helper class to marshal between unmanaged memory and structs without creating garbage. + */ + public static class StructMarshal where T : struct + { +#if !ENABLE_IL2CPP + [StructLayout(LayoutKind.Sequential)] + private class StructContainer + { + public T value; + } + + [ThreadStatic] + private static StructContainer _container; +#endif + + private static int _sizeofT; + + static StructMarshal() + { + _sizeofT = Marshal.SizeOf(typeof(T)); + } + + /** + * Returns the size in bytes of the struct of type T. This call is equivalent to + * Marshal.Sizeof(typeof(T)) but caches the result for ease of access. + */ + public static int Size + { + get + { + return _sizeofT; + } + } + + /** + * Converts an IntPtr to a struct of type T. + */ + public static void PtrToStruct(IntPtr ptr, out T t) + { +#if ENABLE_IL2CPP +#if UNITY_2018_1_OR_NEWER + unsafe { + Unity.Collections.LowLevel.Unsafe.UnsafeUtility.CopyPtrToStructure((void*)ptr, out t); + } +#else +#error UnityModules Only supports IL2CPP on versions of Unity 2018.1 or greater. +#endif +#else + if (_container == null) + { + _container = new StructContainer(); + } + + try + { + Marshal.PtrToStructure(ptr, _container); + t = _container.value; + } + catch (Exception e) + { + //UnityEngine.Debug.LogException(e); + t = default(T); + } +#endif + } + + /** + * Converts a single element in an array pointed to by ptr to a struct + * of type T. This method does not and cannot do any bounds checking! + * This method does not create any garbage. + */ + public static void ArrayElementToStruct(IntPtr ptr, int arrayIndex, out T t) + { + PtrToStruct(new IntPtr(ptr.ToInt64() + _sizeofT * arrayIndex), out t); + } + } +} diff --git a/vendor/LeapCSharp/TransformExtensions.cs b/vendor/LeapCSharp/TransformExtensions.cs new file mode 100644 index 00000000..038a5f95 --- /dev/null +++ b/vendor/LeapCSharp/TransformExtensions.cs @@ -0,0 +1,176 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + + public static class TransformExtensions + { + + /** + * Does an in-place rigid transformation of a Frame. + * + * @param transform A LeapTransform containing the desired translation, rotation, and scale + * to be applied to the Frame. + */ + public static Frame Transform(this Frame frame, LeapTransform transform) + { + for (int i = frame.Hands.Count; i-- != 0;) + { + frame.Hands[i].Transform(transform); + } + + return frame; + } + + /** + * Returns a new frame that is a copy of a frame, with an additional rigid + * transformation applied to it. + * + * @param transform The transformation to be applied to the copied frame. + */ + public static Frame TransformedCopy(this Frame frame, LeapTransform transform) + { + return new Frame().CopyFrom(frame).Transform(transform); + } + + /** + * Does an in-place rigid transformation of a Hand. + * + * @param transform A LeapTransform containing the desired translation, rotation, and scale + * to be applied to the Hand. + */ + public static Hand Transform(this Hand hand, LeapTransform transform) + { + hand.PalmPosition = transform.TransformPoint(hand.PalmPosition); + hand.StabilizedPalmPosition = transform.TransformPoint(hand.StabilizedPalmPosition); + hand.PalmVelocity = transform.TransformVelocity(hand.PalmVelocity); + hand.PalmNormal = transform.TransformDirection(hand.PalmNormal); + hand.Direction = transform.TransformDirection(hand.Direction); + hand.WristPosition = transform.TransformPoint(hand.WristPosition); + hand.PalmWidth *= Math.Abs(transform.scale.x); + hand.Rotation = transform.TransformQuaternion(hand.Rotation); + + hand.Arm.Transform(transform); + + for (int i = 5; i-- != 0;) + { + hand.Fingers[i].Transform(transform); + } + + return hand; + } + + /** + * Returns a new hand that is a copy of a hand, with an additional rigid + * transformation applied to it. + * + * @param transform The transformation to be applied to the copied hand. + */ + public static Hand TransformedCopy(this Hand hand, LeapTransform transform) + { + return new Hand().CopyFrom(hand).Transform(transform); + } + + /** + * Does an in-place rigid transformation of a Finger. + * + * @param transform A LeapTransform containing the desired translation, rotation, and scale + * to be applied to the Finger. + */ + public static Finger Transform(this Finger finger, LeapTransform transform) + { + Bone nextBone = finger.bones[3]; + nextBone.NextJoint = transform.TransformPoint(nextBone.NextJoint); + + finger.TipPosition = nextBone.NextJoint; + + for (int i = 3; i-- != 0;) + { + Bone bone = finger.bones[i]; + + bone.NextJoint = nextBone.PrevJoint = transform.TransformPoint(bone.NextJoint); + + nextBone.TransformGivenJoints(transform); + nextBone = bone; + } + + nextBone.PrevJoint = transform.TransformPoint(nextBone.PrevJoint); + nextBone.TransformGivenJoints(transform); + + finger.Direction = finger.bones[2].Direction; + finger.Width *= Math.Abs(transform.scale.x); + finger.Length *= Math.Abs(transform.scale.z); + + return finger; + } + + /** + * Returns a new finger that is a copy of a finger, with an additional rigid + * transformation applied to it. + * + * @param transform The transformation to be applied to the copied finger. + */ + public static Finger TransformedCopy(this Finger finger, LeapTransform transform) + { + return new Finger().CopyFrom(finger).Transform(transform); + } + + /** + * Does an in-place rigid transformation of a Bone. + * + * @param transform A LeapTransform containing the desired translation, rotation, and scale +- * to be applied to the bone. + */ + public static Bone Transform(this Bone bone, LeapTransform transform) + { + bone.PrevJoint = transform.TransformPoint(bone.PrevJoint); + bone.NextJoint = transform.TransformPoint(bone.NextJoint); + + bone.TransformGivenJoints(transform); + + return bone; + } + + /** + * Does an in-place rigid transformation of a Bone, assuming the joints have already been transformed. + * + * @param transform A LeapTransform containing the desired translation, rotation, and scale +- * to be applied to the bone. + */ + internal static void TransformGivenJoints(this Bone bone, LeapTransform transform) + { + bone.Length *= Math.Abs(transform.scale.z); + bone.Center = (bone.PrevJoint + bone.NextJoint) / 2.0f; + + if (bone.Length < float.Epsilon) + { + bone.Direction = Vector.Zero; + } + else + { + bone.Direction = (bone.NextJoint - bone.PrevJoint) / bone.Length; + } + + bone.Width *= Math.Abs(transform.scale.x); + bone.Rotation = transform.TransformQuaternion(bone.Rotation); + } + + /** + * Returns a new bone that is a copy of a bone, with an additional rigid + * transformation applied to it. + * + * @param transform The transformation to be applied to the copied bone. + */ + public static Bone TransformedCopy(this Bone bone, LeapTransform transform) + { + return new Bone().CopyFrom(bone).Transform(transform); + } + } +} diff --git a/vendor/LeapCSharp/Vector.cs b/vendor/LeapCSharp/Vector.cs new file mode 100644 index 00000000..e1cc5fea --- /dev/null +++ b/vendor/LeapCSharp/Vector.cs @@ -0,0 +1,425 @@ +/****************************************************************************** + * Copyright (C) Ultraleap, Inc. 2011-2021. * + * * + * Use subject to the terms of the Apache License 2.0 available at * + * http://www.apache.org/licenses/LICENSE-2.0, or another agreement * + * between Ultraleap and you, your company or other organization. * + ******************************************************************************/ + +namespace Leap +{ + using System; + + /// + /// Constants used in Leap Motion math functions. + /// + public static class Constants + { + public const float PI = 3.1415926536f; + public const float DEG_TO_RAD = 0.0174532925f; + public const float RAD_TO_DEG = 57.295779513f; + public const float EPSILON = 1.192092896e-07f; + } + + /// + /// The Vector struct represents a three-component mathematical vector or point + /// such as a direction or position in three-dimensional space. + /// + /// The Leap Motion software employs a right-handed Cartesian coordinate system. + /// Values given are in units of real-world millimeters. The origin is centered + /// at the center of the Leap Motion Controller. The x- and z-axes lie in the horizontal + /// plane, with the x-axis running parallel to the long edge of the device. + /// The y-axis is vertical, with positive values increasing upwards (in contrast + /// to the downward orientation of most computer graphics coordinate systems). + /// The z-axis has positive values increasing away from the computer screen. + /// @since 1.0 + /// + [Serializable] + public struct Vector : IEquatable + { + + public static Vector operator +(Vector v1, Vector v2) + { + return new Vector(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z); + } + + public static Vector operator -(Vector v1, Vector v2) + { + return new Vector(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z); + } + + public static Vector operator *(Vector v1, float scalar) + { + return new Vector(v1.x * scalar, v1.y * scalar, v1.z * scalar); + } + + public static Vector operator *(float scalar, Vector v1) + { + return new Vector(v1.x * scalar, v1.y * scalar, v1.z * scalar); + } + + public static Vector operator /(Vector v1, float scalar) + { + return new Vector(v1.x / scalar, v1.y / scalar, v1.z / scalar); + } + + public static Vector operator -(Vector v1) + { + return new Vector(-v1.x, -v1.y, -v1.z); + } + + public static bool operator ==(Vector v1, Vector v2) + { + return v1.Equals(v2); + } + + public static bool operator !=(Vector v1, Vector v2) + { + return !v1.Equals(v2); + } + + public float[] ToFloatArray() + { + return new float[] { x, y, z }; + } + + /// + /// Creates a new Vector with the specified component values. + /// @since 1.0 + /// + public Vector(float x, float y, float z) : + this() + { + this.x = x; + this.y = y; + this.z = z; + } + + /// + /// Copies the specified Vector. + /// @since 1.0 + /// + public Vector(Vector vector) : + this() + { + x = vector.x; + y = vector.y; + z = vector.z; + } + + /// + /// The distance between the point represented by this Vector + /// object and a point represented by the specified Vector object. + /// + /// @since 1.0 + /// + public float DistanceTo(Vector other) + { + return (float)Math.Sqrt((x - other.x) * (x - other.x) + + (y - other.y) * (y - other.y) + + (z - other.z) * (z - other.z)); + + } + + /// + /// The angle between this vector and the specified vector in radians. + /// + /// The angle is measured in the plane formed by the two vectors. The + /// angle returned is always the smaller of the two conjugate angles. + /// Thus A.angleTo(B) == B.angleTo(A) and is always a positive + /// value less than or equal to pi radians (180 degrees). + /// + /// If either vector has zero length, then this function returns zero. + /// @since 1.0 + /// + public float AngleTo(Vector other) + { + float denom = MagnitudeSquared * other.MagnitudeSquared; + if (denom <= Constants.EPSILON) + { + return 0.0f; + } + float val = Dot(other) / (float)Math.Sqrt(denom); + if (val >= 1.0f) + { + return 0.0f; + } + else if (val <= -1.0f) + { + return Constants.PI; + } + return (float)Math.Acos(val); + } + + /// + /// The dot product of this vector with another vector. + /// + /// The dot product is the magnitude of the projection of this vector + /// onto the specified vector. + /// @since 1.0 + /// + public float Dot(Vector other) + { + return (x * other.x) + (y * other.y) + (z * other.z); + } + + /// + /// The cross product of this vector and the specified vector. + /// + /// The cross product is a vector orthogonal to both original vectors. + /// It has a magnitude equal to the area of a parallelogram having the + /// two vectors as sides. The direction of the returned vector is + /// determined by the right-hand rule. Thus A.cross(B) == -B.cross(A). + /// + /// @since 1.0 + /// + public Vector Cross(Vector other) + { + return new Vector((y * other.z) - (z * other.y), + (z * other.x) - (x * other.z), + (x * other.y) - (y * other.x)); + } + + /// + /// Returns a string containing this vector in a human readable format: (x, y, z). + /// @since 1.0 + /// + public override string ToString() + { + return "(" + x + ", " + y + ", " + z + ")"; + } + + /// + /// Compare Vector equality component-wise. + /// @since 1.0 + /// + public bool Equals(Vector v) + { + return x.NearlyEquals(v.x) && y.NearlyEquals(v.y) && z.NearlyEquals(v.z); + } + + public override bool Equals(Object obj) + { + return obj is Vector && Equals((Vector)obj); + } + + /// + /// Returns true if all of the vector's components are finite. If any + /// component is NaN or infinite, then this returns false. + /// @since 1.0 + /// + public bool IsValid() + { + return !(float.IsNaN(x) || float.IsInfinity(x) || + float.IsNaN(y) || float.IsInfinity(y) || + float.IsNaN(z) || float.IsInfinity(z)); + } + + /// + /// Index vector components numerically. + /// Index 0 is x, index 1 is y, and index 2 is z. + /// @since 1.0 + /// + public float this[uint index] + { + get + { + if (index == 0) + return x; + if (index == 1) + return y; + if (index == 2) + return z; + throw new IndexOutOfRangeException(); + } + set + { + if (index == 0) + x = value; + if (index == 1) + y = value; + if (index == 2) + z = value; + throw new IndexOutOfRangeException(); + } + } + + public float x; + public float y; + public float z; + + /// + /// The magnitude, or length, of this vector. + /// + /// The magnitude is the L2 norm, or Euclidean distance between the origin and + /// the point represented by the (x, y, z) components of this Vector object. + /// @since 1.0 + /// + public float Magnitude + { + get { return (float)Math.Sqrt(x * x + y * y + z * z); } + } + + /// + /// The square of the magnitude, or length, of this vector. + /// @since 1.0 + /// + public float MagnitudeSquared + { + get { return x * x + y * y + z * z; } + } + + /// + /// The pitch angle in radians. + /// + /// Pitch is the angle between the negative z-axis and the projection of + /// the vector onto the y-z plane. In other words, pitch represents rotation + /// around the x-axis. + /// If the vector points upward, the returned angle is between 0 and pi radians + /// (180 degrees); if it points downward, the angle is between 0 and -pi radians. + /// + /// @since 1.0 + /// + public float Pitch + { + get { return (float)Math.Atan2(y, -z); } + } + + /// + /// The roll angle in radians. + /// + /// Roll is the angle between the y-axis and the projection of + /// the vector onto the x-y plane. In other words, roll represents rotation + /// around the z-axis. If the vector points to the left of the y-axis, + /// then the returned angle is between 0 and pi radians (180 degrees); + /// if it points to the right, the angle is between 0 and -pi radians. + /// + /// Use this function to get roll angle of the plane to which this vector is a + /// normal. For example, if this vector represents the normal to the palm, + /// then this function returns the tilt or roll of the palm plane compared + /// to the horizontal (x-z) plane. + /// + /// @since 1.0 + /// + public float Roll + { + get { return (float)Math.Atan2(x, -y); } + } + + /// + /// The yaw angle in radians. + /// + /// Yaw is the angle between the negative z-axis and the projection of + /// the vector onto the x-z plane. In other words, yaw represents rotation + /// around the y-axis. If the vector points to the right of the negative z-axis, + /// then the returned angle is between 0 and pi radians (180 degrees); + /// if it points to the left, the angle is between 0 and -pi radians. + /// + /// @since 1.0 + /// + public float Yaw + { + get { return (float)Math.Atan2(x, -z); } + } + + /// + /// A normalized copy of this vector. + /// + /// A normalized vector has the same direction as the original vector, + /// but with a length of one. + /// + /// @since 1.0 + /// + public Vector Normalized + { + get + { + float denom = MagnitudeSquared; + if (denom <= Constants.EPSILON) + { + return Zero; + } + denom = 1.0f / (float)Math.Sqrt(denom); + return new Vector(x * denom, y * denom, z * denom); + } + } + + /// + /// The zero vector: (0, 0, 0) + /// + public static readonly Vector Zero = new Vector(0, 0, 0); + + /// + /// The ones vector: (1, 1, 1) + /// + public static readonly Vector Ones = new Vector(1, 1, 1); + + /// + /// The x-axis unit vector: (1, 0, 0) + /// + public static readonly Vector XAxis = new Vector(1, 0, 0); + + /// + /// The y-axis unit vector: (0, 1, 0) + /// + public static readonly Vector YAxis = new Vector(0, 1, 0); + + /// + /// The z-axis unit vector: (0, 0, 1) + /// + public static readonly Vector ZAxis = new Vector(0, 0, 1); + + /// + /// The unit vector pointing forward along the negative z-axis: (0, 0, -1) + /// + public static readonly Vector Forward = new Vector(0, 0, -1); + + /// + /// The unit vector pointing backward along the positive z-axis: (0, 0, 1) + /// + public static readonly Vector Backward = new Vector(0, 0, 1); + + /// + /// The unit vector pointing left along the negative x-axis: (-1, 0, 0) + /// + public static readonly Vector Left = new Vector(-1, 0, 0); + + /// + /// The unit vector pointing right along the positive x-axis: (1, 0, 0) + /// + public static readonly Vector Right = new Vector(1, 0, 0); + + /// + /// The unit vector pointing up along the positive y-axis: (0, 1, 0) + /// + public static readonly Vector Up = new Vector(0, 1, 0); + + /// + /// The unit vector pointing down along the negative y-axis: (0, -1, 0) + /// + public static readonly Vector Down = new Vector(0, -1, 0); + + + public static Vector Lerp(Vector a, Vector b, float t) + { + return new Vector( + a.x + t * (b.x - a.x), + a.y + t * (b.y - a.y), + a.z + t * (b.z - a.z) + ); + } + + public override int GetHashCode() + { + unchecked // Overflow is fine, just wrap + { + int hash = 17; + hash = hash * 23 + x.GetHashCode(); + hash = hash * 23 + y.GetHashCode(); + hash = hash * 23 + z.GetHashCode(); + + return hash; + } + } + } +} diff --git a/vendor/LeapSDK/LICENSE.md b/vendor/LeapSDK/LICENSE.md new file mode 100644 index 00000000..25c5e0ca --- /dev/null +++ b/vendor/LeapSDK/LICENSE.md @@ -0,0 +1,388 @@ +ULTRALEAP TRACKING SDK AGREEMENT +Updated: 26 October 2021 +Permitted uses +This SDK Agreement (“Agreement”) covers use of the Ultraleap hand tracking SDK (the “SDK”) by +individuals and businesses for the following purposes: +1. Your personal, non-commercial use (for the avoidance of doubt, excluding use for the design or +manufacture of a commercial or distributable product (e.g in design studios)); or +2. Commercial use for the development and sale consumer facing games, made available for sale to +be purchased by consumers for personal use either at retail or through app stores (excluding, +without limitation, location-based entertainment and arcade applications); or +3. Demonstration of your application to internal and external stakeholders and customers where +there is no transaction, no sale of tickets specifically for the application, or any other form of +compensation for you or your organisation, +but in all cases excluding applications relating to the following: (a) the production of or trade in tobacco, +alcoholic beverages, and related products, (b) the production or trade in weapons of any kind or any +military applications, (c) casinos, gambling and equivalent enterprises, (d) human cloning, human +embryos, or stem cells, or (e) nuclear energy. +Any other uses, or applications using third party hardware are “Specialised Applications” and will require +a separate license agreement. Please contact Ultraleap info@ultraleap.com for more information. +In each case, the SDK may only be used with Ultraleap Hardware and Ultraleap Software. + +1. Parties +1.1. This Agreement is made between the individual or entity (“you” or the “Developer”) that accepts +it and Ultraleap Limited (“Ultraleap”). You accept this Agreement by (a) accepting it on download +of the SDK, or (b) if you use or access the SDK or any part of the SDK. Your entry into this +Agreement also binds your authorized users, and your company or organisation. +1.2. If you do not agree to the terms of this Agreement you must not use the SDK. +1.3. Capitalized terms bear the meanings given in the “Definitions” section of this Agreement. +1.4. This Agreement incorporates the terms of the Ultraleap Hand Tracking End User License +Agreement (“EULA”), which is available at https://developer.leapmotion.com/end-user-license- +agreement or from Ultraleap on request. In the event of a conflict between these terms and the +EULA, these terms will prevail. +2. License +Development License +2.1. Conditional on your compliance with the terms and conditions of this Agreement, Ultraleap +hereby grants you a limited, non-exclusive, personal, revocable, non-sublicensable, and non- +transferable license to: +2.1.1. install and use a reasonable number of copies of the SDK on computers owned or +controlled by you for the purpose of developing and testing applications that (a) are not +Specialised Applications and (b) are intended for use solely in connection with Ultraleap +Hardware and Ultraleap Software (each being an “Ultraleap Enabled Application”); and +2.1.2. modify and incorporate into your Ultraleap Enabled Application any sample code +provided in the SDK. +Distribution License +2.2. Conditional on your compliance with the terms and conditions of this Agreement, Ultraleap +hereby grants you a limited, non-exclusive, personal, revocable, non-transferrable license of +Ultraleap’s intellectual property rights to the extent necessary to: +2.2.1. copy and distribute (or have copied and distributed) the Ultraleap Redistributables, +solely as compiled with, incorporated into, or packaged with, your Ultraleap Enabled +Application; and +2.2.2. to make (but not have made), use, sell, offer for sale, and import your Ultraleap Enabled +Application. +3. Restrictions +3.1. The license granted to you in section 2.1 and section 2.2 is subject to the following restrictions, +as well as others listed in this Agreement: +3.1.1. Except as expressly permitted in section 2.1, (a) you may not publish, distribute, or copy +the SDK, and (b) you may not modify or create derivative works of the SDK; +3.1.2. Except as expressly permitted in section 2.2, you may not, and may not allow any third +party, directly or indirectly, to publish, post, or otherwise make available, the Ultraleap +Redistributables; +3.1.3. You may not, and may not enable others to, distributed the Non-Redistributable +Materials; +3.1.4. You may use the SDK solely in connection with Ultraleap Hardware and/or Ultraleap +Software; +3.1.5. You may not use the SDK to create, or aid in the creation, directly or indirectly, of any +software or hardware which provides hand tracking functionality or which is otherwise +substantially similar to the features or functionality of Ultraleap products; +3.1.6. You may not, and may not enable others to, directly or indirectly, reverse engineer, +decompile, disassemble, or otherwise attempt to reconstruct, identify, or discover any +source code, underlying ideas, techniques, or algorithms in the Ultraleap Software, the +Ultraleap Hardware, or any software which forms part of the SDK, nor attempt to +circumvent any related security measures (except as and only to the extent any +foregoing restriction is prohibited by applicable law notwithstanding the foregoing +restriction, or to the extent as may be permitted by licensing terms governing the use of +any open source software components or sample code contained within the SDK; +3.1.7. You may not remove, obscure, or alter any proprietary rights or confidentiality notices +within the SDK or any software, documentation, or other materials in it or supplied with +it; +3.1.8. You must not allow the Ultraleap Software or SDK to fall under the terms of any license +which would obligate you or Ultraleap to make available or publish any part of the +Ultraleap Software or SDK. +3.1.9. You may not create Ultraleap Enabled Applications or other software that prevent or +degrade the interaction of applications developed by others with the Ultraleap Software; +3.1.10. You may not represent functionality provided by any Ultraleap hardware or software as +your technology or the technology of any third party. For example (without limitation) +you may not describe any application, technology, or feature developed or distributed +by you that incorporates Ultraleap technology as your gesture or touchless control +technology without providing attribution to Ultraleap; and +3.1.11. You may not allow your Ultraleap Enabled Application to be used for a High Risk Use. +4. Updates +4.1. The terms of this Agreement will apply to any Updates which Ultraleap (in its sole discretion) +makes available to you. You agree that Updates may require you to change or update your +Ultraleap Enabled Application, and may affect your ability to use, access, or interact with the +Ultraleap Software, the Ultraleap Hardware, and/or the SDK. You are solely responsible for +turning off any auto-update functionality of the Ultraleap Software. +5. Trademarks and Marketing +5.1. Conditioned upon compliance with the terms and conditions of this Agreement, Ultraleap grants +you a limited, non-exclusive, personal, license to reproduce and use Ultraleap trademarks solely +to (a) mark the Ultraleap Enabled Application, (b) produce and make available related collateral, +and (c) to promote and market your Ultraleap Enabled Application, in each case solely in +accordance with the Ultraleap trademark guidelines that Ultraleap may provide to you from time +to time. +5.2. For so long as Ultraleap technology is included with the Ultraleap Enabled Application, you must +identify on the packaging of the Ultraleap Enabled Application, the loading screen and start-up +messages for the Ultraleap Enabled Application, and list on your website and marketing collateral +(in each case, where applicable), as prominently as other listed features and functionality, that +Ultraleap technology is included with the Ultraleap Enabled Application, in accordance with the +Ultraleap trademark guidelines that Ultraleap may provide to you from time to time. All +references to Ultraleap or Ultraleap Technology will be subject to Ultraleap’s prior approval, +which will not be unreasonably withheld. +5.3. Ultraleap may at its option mention you and your products using Ultraleap technology in +Ultraleap’s press releases, press briefings, social media accounts, and/or website, and may use +your trademarks for such purpose. You grant to Ultraleap and its affiliates a non-exclusive, +worldwide and royalty-free limited license to use, reproduce, display, perform, publish and +distribute screenshots, elements, assets, photographic, graphic or video reproductions or +fragments of your Ultraleap Enabled Application in any medium or media, solely for purposes of +promotion of your Ultraleap Enabled Application or of Ultraleap and its technology and business. +The rights set out in this section 5.3 will survive termination of this Agreement in respect of +materials already in existence as at the date of termination. +6. EULA and Other Licenses +6.1. Example code made publicly available by Ultraleap on its developer web site may be provided +subject to the Apache 2.0 license, this Agreement, or other licenses, as specified in the notice or +readme files distributed with the example or in related documentation. The SDK may otherwise +include software or other materials that are provided under a separate license agreement, and +that separate license will govern the use of such software or other materials in the event of a +conflict with this Agreement. Any such separate license agreement may be indicated in the +license, notice, or readme files distributed with the applicable software or other materials or in +related documentation. +6.2. You must either require end users of your Ultraleap Enabled Application to affirmatively agree to +the Ultraleap EULA, or require its End Users to affirmatively agree to your own end user license +agreement that protects Ultraleap at least as much as the Ultraleap EULA. +7. High Risk Uses and Waiver +7.1. Notwithstanding anything in this Agreement, you are not licensed to, and you agree not to, use, +copy, sell, offer for sale, or distribute the SDK, Ultraleap Hardware, Ultraleap Software or +Ultraleap Redistributables (whether compiled with, incorporated into, or packaged with your +Ultraleap Enabled Application or otherwise), for or in connection with uses where failure or fault +of the Ultraleap Hardware, Ultraleap Software, Ultraleap Redistributables or your Ultraleap +Enabled Application could lead to death or serious bodily injury of any person, or to severe +physical or environmental damage (“High Risk Use”). Any such use is strictly prohibited. +7.2. You acknowledge the SDK may allow you to develop Ultraleap Enabled Applications that enable +the control of motorized or mechanical equipment, or other systems, machines or devices. If you +elect to use the SDK in such a way, you must take steps to design and test your Ultraleap Enabled +Applications to ensure that your Ultraleap Enabled Applications do not present risks of personal +injury or death, property damage, or other losses. The Ultraleap Hardware, the Ultraleap +Software, the Ultraleap Redistributables and other software in the SDK may not always function +as intended. You must design your Ultraleap Enabled Applications so that any failure of Ultraleap +Technology and/or such other software as Ultraleap may make available from time to time does +not cause personal injury or death, property damage, or other losses. If you choose to use the +SDK, (i) you assume all risk that use of the Ultraleap Technology and/or such other software by +you or by any others causes any harm or loss, including to the end users of your Ultraleap +Enabled Applications or to third parties, (ii) you hereby waive, on behalf of yourself and your +Authorized Users, all claims against Ultraleap and its affiliates related to such use, harm or loss +(including, but not limited to, any claim that Ultraleap Technology or such other software is +defective), and (iii) you agree to hold Ultraleap and its affiliates harmless from such claims. +8. Confidentiality and Data Protection +8.1. Beta Software etc. Obligations. You acknowledge and agree that Ultraleap may share alpha or +beta software or hardware with you that it identifies as non-public. If so, you agree not to +disclose such software or hardware to others without the prior written consent of Ultraleap +until the time, if any, it is made public by Ultraleap, and to use such software or hardware only +as expressly permitted by Ultraleap. Without limitation to the foregoing, the distribution license +set out in section 2.2 shall not apply to any alpha or beta software which may be shared with +you. +8.2. Your Information. Ultraleap may collect personal information provided by you or your +Authorized Users to Ultraleap or any group company of Ultraleap in connection with the SDK, +and may collect other information from you or your Authorized Users, including technical, non- +personally identifiable and/or aggregated information such as usage statistics, hardware +configuration, problem / fault data, IP addresses, version number of the SDK, information about +which tools and/or services in the SDK are being used and how they are being used, and any +other information described in Ultraleap’s privacy policy, currently available at +https://www.ultraleap.com/privacy-policy/. Ultraleap may use the information collected to +facilitate the provision of Updates and other services to you, to verify compliance with, and +enforce, the terms of this Agreement, to improve the SDK and Ultraleap’s other products, and +for any other purposes set out in Ultraleap’s privacy policy (these uses, collectively, are +“Permitted Uses”). The information collected may be transferred to, stored, and processed in a +destination outside the European Economic Area, including (without limitation) by our staff in +the USA, China, Japan, and Hong Kong. By submitting information about you and/or your +Authorized Users to Ultraleap through your access and use of the SDK, you consent to +Ultraleap’s collection and use of the information for the Permitted Uses and represent that you +have obtained all consents and permits necessary under applicable law to disclose your +Authorized Users’ information to Ultraleap for the Permitted Uses. You further agree that +Ultraleap may provide any information collected under this Section 8.2, including your or your +Authorized Users’ user name, IP address or other identifying information to law enforcement +authorities or as required by applicable law or regulation. +9. Ownership and Feedback +9.1. As between you and Ultraleap, Ultraleap owns all right, title, and interest, including all +intellectual property rights, in and to the SDK, the Ultraleap Software, Ultraleap Hardware, the +Ultraleap Redistributables, and all documentation associated with the foregoing, other than any +third party software or materials incorporated into the SDK. You agree not to contest Ultraleap’s +ownership of any of the foregoing. +9.2. Subject to Section 9.1, Ultraleap agrees that it obtains no right, title, or interest from you (or +your licensors) under this Agreement in or to your Ultraleap Enabled Applications, including any +intellectual property rights which subsist in those Ultraleap Enabled Applications. +9.3. Feedback. You may (but are not required to) provide feedback, comments, and suggestions +(collectively “Feedback”) to Ultraleap. You hereby grant to Ultraleap a non-exclusive, perpetual, +irrevocable, paid-up, transferrable, sub-licensable, worldwide license under all intellectual +property rights covering such Feedback to use, disclose, and exploit all such Feedback for any +purpose. +10. Your Obligations and Warranties +In addition to your other obligations under this Agreement, you warrant and agree that: +10.1. you are at least 18 years of age and have the right and authority to enter into this Agreement on +your own behalf and that of your Authorized Users. If you are entering into this Agreement on +behalf of your company or organization, you warrant that you have the right and authority to +legally bind your company or organization and its Authorized Users; +10.2. you will use the SDK only in accordance with all accompanying documentation, and in the +manner expressly permitted by this Agreement; and +10.3. your use of the SDK, and the marketing, sales and distribution of your Ultraleap Enabled +Application, will be in compliance with all applicable laws and regulations and all UK, U.S. and +local or foreign export and re-export restrictions applicable to the technology and +documentation provided under this Agreement (including privacy and data security laws and +regulations), and you will not develop any Ultraleap Enabled Application which would commit or +facilitate the commission of a crime, or other tortious, unlawful, or illegal act. +11. Agreement and Development Program +11.1. We reserve the right to change this Agreement, the SDK or the Ultraleap development and +licensing program at any time in our discretion. Ultraleap may require that you either accept +and agree to the new terms of this Agreement, or, if you do not agree to the new terms, cease +or terminate your use of the SDK. Your continued use of the SDK after changes to this +Agreement take effect will constitute your acceptance of the changes. If you do not agree to a +change, you must stop using the SDK and terminate this Agreement. Any termination of this +Agreement by you under this Section 11 (and only this Section 11) will not affect your right, +subject to your continued compliance with your obligations under this Agreement, to continue +to distribute versions of your Ultraleap Enabled Application created and first distributed before +termination, and will not affect the right of your End Users to continue using such versions of +your Ultraleap Enabled Application, both of which rights will survive termination. +12. Term and Termination +12.1. Term. This Agreement will continue to apply until terminated by either you or Ultraleap as set +out below. +12.2. Termination by You. If you want to terminate this Agreement, you may terminate it by +uninstalling and destroying all copies of the SDK that are in the possession, custody or control of +you, your Authorized Users and your organization. +12.3. Termination by Ultraleap. Ultraleap may at any time, terminate this Agreement with you for +any reason or for no reason in Ultraleap’s sole discretion, including as a result of non- +compliance by you with the restrictions in in this Agreement, or for other reasons. +12.4. Effect of Termination. Upon termination of this Agreement, all rights granted to you under this +Agreement will immediately terminate and you must immediately cease all use and destroy all +copies of the SDK in your and your Authorized Users’ possession, custody or control, and, except +as specifically set out in Section 11, cease your distribution of Ultraleap Enabled Applications. +Sections 3, 8.1, 8.2, 9, 12.4, 14-16, and 17, will survive termination of this Agreement. +Termination of this Agreement will not affect the right of your End Users who have downloaded +your Ultraleap Enabled Application prior to termination to continue using it. +13. Indemnification. +13.1. You agree to indemnify, hold harmless and, at Ultraleap’s option, defend Ultraleap and its +affiliates and their respective officers, directors, employees, agents, and representatives +harmless from any and all judgments, awards, settlements, liabilities, damages, costs, penalties, +fines and other expenses (including court costs and reasonable attorneys’ fees) incurred by +them arising out of or relating to any third party claim (a) with respect to your Ultraleap Enabled +Application, including products liability, privacy, or intellectual property infringement claims, or +(b) based upon your negligence or wilful misconduct or any breach or alleged breach of your +representations, warranties, and covenants under this Agreement. In no event may you enter +into any settlement or like agreement with a third party that affects Ultraleap’s rights or binds +Ultraleap or its affiliates in any way, without the prior written consent of Ultraleap. +14. Warranty Disclaimer. +14.1. THE SDK, THE ULTRALEAP SOFTWARE AND THE ULTRALEAP REDISTRIBUTABLES ARE PROVIDED +"AS IS" WITHOUT WARRANTY OF ANY KIND. ULTRALEAP, ON BEHALF OF ITSELF AND ITS +SUPPLIERS, HEREBY DISCLAIMS ALL REPRESENTATIONS, PROMISES, OR WARRANTIES, WHETHER +EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE, WITH RESPECT TO THE SDK, THE ULTRALEAP +SOFTWARE AND THE ULTRALEAP REDISTRIBUTABLES, INCLUDING THEIR CONDITION, +AVAILABILITY, OR THE EXISTENCE OF ANY LATENT DEFECTS, AND ULTRALEAP SPECIFICALLY +DISCLAIMS ALL IMPLIED WARRANTIES OF MERCHANTABILITY, TITLE, NONINFRINGEMENT, +SUITABILITY, AND FITNESS FOR ANY PURPOSE. ULTRALEAP DOES NOT WARRANT THAT THE SDK, +THE ULTRALEAP SOFTWARE OR THE ULTALEAP REDISTRIBUTABLES WILL BE ERROR-FREE OR +THAT THEY WILL WORK WITHOUT INTERRUPTION. +15. Limitation of Liability. +15.1. ULTRALEAP SHALL NOT IN ANY CIRCUMSTANCES WHATEVER BE LIABLE TO YOU, WHETHER IN +CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF STATUTORY DUTY, OR OTHERWISE, +ARISING UNDER OR IN CONNECTION WITH THE AGREEMENT FOR: +15.1.1. LOSS OF PROFITS, SALES, BUSINESS, OR REVENUE; +15.1.2. BUSINESS INTERRUPTION; +15.1.3. LOSS OF ANTICIPATED SAVINGS; +15.1.4. LOSS OR CORRUPTION OF DATA OR INFORMATION; +15.1.5. LOSS OF BUSINESS OPPORTUNITY, GOODWILL OR REPUTATION; OR +15.1.6. ANY INDIRECT OR CONSEQUENTIAL LOSS OR DAMAGE. +15.2. OTHER THAN THE LOSSES SET OUT ABOVE (FOR WHICH ULTRALEAP IS NOT LIABLE), +ULTRALEAP’S MAXIMUM AGGREGATE LIABILITY UNDER OR IN CONNECTION WITH THE +AGREEMENT WHETHER IN CONTRACT, TORT (INCLUDING NEGLIGENCE), BREACH OF STATUTORY +DUTY, OR OTHERWISE, SHALL IN ALL CIRCUMSTANCES BE LIMITED TO $1,000 (ONE THOUSAND +US DOLLARS). THIS MAXIMUM CAP DOES NOT APPLY TO DEATH OR PERSONAL INJURY +RESULTING FROM ULTRALEAP'S NEGLIGENCE; FRAUD OR FRAUDULENT MISREPRESENTATION; +OR ANY OTHER LIABILITY THAT CANNOT BE EXCLUDED OR LIMITED BY APPLICABLE LAW. +15.3. THE AGREEMENT SETS OUT THE FULL EXTENT OF ULTRALEAP’S OBLIGATIONS AND LIABILITIES IN +RESPECT OF THE SUPPLY OF THE ULTRALEAP DEVICES, DELIVERABLES AND SOFTWARE. EXCEPT +AS EXPRESSLY STATED IN THE AGREEMENT, THERE ARE NO CONDITIONS, WARRANTIES, +REPRESENTATIONS OR OTHER TERMS, EXPRESS OR IMPLIED, THAT ARE BINDING ON +ULTRALEAP. ANY CONDITION, WARRANTY, REPRESENTATION OR OTHER TERM CONCERNING +THE SUPPLY OF THE ULTRALEAP HARDWARE, ULTRALEAP SOFTWARE, THE SDK, THE ULTRALEAP +REDISTRIBUTABLES, OR ANY OTHER ULTRALEAP TECHNOLOGY WHICH MIGHT OTHERWISE BE +IMPLIED INTO, OR INCORPORATED IN THE AGREEMENT WHETHER BY STATUTE, COMMON LAW +OR OTHERWISE, INCLUDING ANY WARRANTY OR CONDITION OF MERCHANTABILITY OR FITNESS +FOR A PARTICULAR PURPOSE, IS EXCLUDED TO THE FULLEST EXTENT PERMITTED BY LAW. THESE +LIMITATIONS WILL APPLY NOTWITHSTANDING ANY FAILURE OF ESSENTIAL PURPOSE OF ANY +LIMITED REMEDY. THE PARTIES AGREE THAT THE FOREGOING LIMITATIONS REPRESENT A +REASONABLE ALLOCATION OF RISK UNDER THIS AGREEMENT. +16. Miscellaneous. +16.1. Assignment. You may not assign this Agreement without the prior written consent of Ultraleap. +Any assignment without such consent is void and of no effect. Ultraleap may assign this +Agreement without your consent in connection with (a) a merger or consolidation of Ultraleap, +(b) a sale or assignment of substantially all its assets, or (c) any other transaction which results +in another entity or person owning substantially all of the assets of Ultraleap, or (d) to any of its +affiliates. In the event of a permitted assignment, this Agreement will inure to the benefit of and +be binding upon the parties and their respective successors and permitted assigns. +16.2. Waiver; Severability. The failure of the other party to enforce any rights under this Agreement +will not be deemed a waiver of any rights. The rights and remedies of the parties in this +Agreement are not exclusive and are in addition to any other rights and remedies provided by +law. If any provision of this Agreement is held by a court of competent jurisdiction to be +contrary to law, the remaining provisions of this Agreement will remain in full force and effect. +16.3. Reservation. All licenses not expressly granted in this Agreement are reserved and no other +licenses, immunity or rights, express or implied, are granted by Ultraleap, by implication, +estoppel, or otherwise. The software in the SDK is licensed, not sold. +16.4. Export Restrictions. The Ultraleap Software is subject to United States and UK export laws and +regulations. You must comply with all domestic and international export laws and regulations +that apply to the Ultraleap Software. These laws include restrictions on destinations, end users, +and end use. +16.5. Governing Law and Jurisdiction. This Agreement will be exclusively governed by and construed +under the laws of the England and Wales, without reference to or application of rules governing +choice of laws. All disputes arising out of or related to this Agreement will be subject to the +exclusive jurisdiction of courts of England and you hereby consent to such jurisdiction. However, +Ultraleap may apply to any court or tribunal worldwide, including but not limited to those +having jurisdiction over you or your Authorized Users, to seek injunctive relief. +16.6. Relationship of the Parties. This Agreement does not create any agency, partnership, or joint +venture relationship between Ultraleap and you. This Agreement is for the sole benefit of +Ultraleap and you (and indemnified parties), and no other persons will have any right or remedy +under this Agreement. +16.7. Notices. The address for notice to Ultraleap under this Agreement is: +Ultraleap Limited +The West Wing +Glass Wharf +Bristol, BS2 0EL +United Kingdom +Ultraleap may provide you notice under this Agreement by email or other electronic +communication or by posting communications to its development community on the Ultraleap +developer portal. You consent to receive such notices in any of the foregoing manners and +agree that any such notices by Ultraleap will satisfy any legal communication requirements. +16.8. Entire Agreement. This Agreement is the entire understanding of the parties with respect to its +subject matter and supersedes any previous or contemporaneous communications, whether +oral or written with respect to such subject matter. +17. Definitions +Whenever capitalized in this Agreement: +“Authorized Users” means your employees and contractors, members of your organization or, if you +are an educational institution, your faculty, staff and registered students, who (a) have a +demonstrable need to know or use the SDK in order to develop and test Ultraleap Enabled +Applications on your behalf and (b) each have written and binding agreements with you to protect +against the unauthorized use and disclosure of the SDK consistent with the terms and conditions of +this Agreement. Authorized Users do not include End Users. +“End User” means your end user customer(s) or licensee(s). +“Non-Redistributable Materials” means the Ultraleap Software, and any other code, files or +materials that are not specifically designated in the SDK as made available for incorporation into +Ultraleap Enabled Applications or that are specifically designated in the SDK as not subject to +distribution. +“SDK” means, collectively, the Ultraleap Redistributables, tools, APIs, sample code, software, +documentation, other materials and any updates to the foregoing that may be provided or made +available to you by Ultraleap in connection with this Agreement, via the Ultraleap developer portal or +otherwise for use in connection with the Ultraleap development program to develop Ultraleap +Enabled Applications. +“Specialized Application” means an Ultraleap Enabled Application which does not fall within the +permitted uses set out in this Agreement. +“Ultraleap” “we” or “us” means Ultraleap Limited, a company registered in England with company +number 08781720, with a principal place of business at The West Wing, Glass Wharf, Bristol, BS2 0EL, +United Kingdom. +“Ultraleap Hardware” means the Leap Motion Controller or Stereo IR 170, each being a device that +detects and reads movements within a 3-D interaction space to precisely interact with and control +software on a computing device, or an Ultraleap-authorized embedded optical module. +“Ultraleap Redistributables” means any .lib code, .dll files, .so files, sample code, or other materials +we specifically designate in the SDK as made available for incorporation into or distribution with +Ultraleap Enabled Applications. +“Ultraleap Software” means the Ultraleap core services application and related applications that +interact with Ultraleap Hardware and an operating system to make motion control functionality +available to Ultraleap Enabled Applications, and includes any Updates thereto. +“Updates” means updates, upgrades, modifications, enhancements, revisions, new releases or new +versions to the SDK that Ultraleap may make available to you in connection with this Agreement. +Other capitalized terms used in this Agreement have the meaning given them elsewhere in this +Agreement. +18. Supplemental Terms Applicable to the Use of Image API +18.1. Purpose. You and/or your Ultraleap Enabled Application may access the Image API and use +image data available through the Image API only for the purpose of developing and testing +Ultraleap Enabled Applications, and only for use with Ultraleap Hardware. You may not use the +Image API to develop or aid development of competing motion tracking hardware or software. +Any use of the Image API is subject to the terms of the Agreement. +18.2. Data Protection. +18.2.1. If you or your Ultraleap Enabled Application collects, uploads, stores, transmits, or +shares images, videos, or other personal information available through the Image API, +either through or in connection with your Ultraleap Enabled Application, you must +expressly provide users with your privacy policy and adhere to it. +18.2.2. You must obtain specific, opt-in consent from the user for any use that is beyond the +limited and express purpose of your Ultraleap Enabled Application. +18.2.3. You and your Ultraleap Enabled Application must use and store information collected +form users securely and only for as long as it is required. +18.2.4. You agree that you will protect the privacy and legal rights of users, and will comply with +all applicable criminal, civil, and statutory privacy and data protection laws and +regulations. diff --git a/vendor/LeapSDK/README.md b/vendor/LeapSDK/README.md new file mode 100644 index 00000000..c60d58e8 --- /dev/null +++ b/vendor/LeapSDK/README.md @@ -0,0 +1,92 @@ +# Ultraleap SDK + +-------------------------------------------------------------------------------- + +## Package contents: + +LeapSDK +- docs + * API reference documentation & guidelines. +- include + * API headers. +- lib + * dynamic API library and CMake scripts. +- samples + * Various samples demonstrating several different usages. +- LICENSE.md + * Ultraleap Tracking SDK license. +- Uninstall.exe + * Program to uninstall the LeapSDK application. + +## Requirements: + +1. Running requires + * Ultraleap Tracking Software https://developer.leapmotion.com/get-started/ + +2. Building Samples requires + * CMake 3.16.3+ (https://cmake.org/) + * Microsoft Visual Studio 15+ + +## Installation: + +1. Execute the LeapSDK installer. + +2. Choose a suitable destination location on your computer. + +3. Read and accept the Ultraleap Tracking SDK Agreement to use the Ultraleap SDK. + +## Usage: + +1. For CMake projects + * Ensure LeapSDK is in a directory considered as a prefix by find_package. + (https://cmake.org/cmake/help/v3.16/command/find_package.html) + * Or : directly set LeapSDK_DIR to /LeapSDK/lib/cmake/LeapSDK + * Or : Pass the LeapSDK's path to find_package with the PATHS option. + * call find_package(LeapSDK 5 [PATHS ...]). + * call target_link_libraries( PUBLIC|PRIVATE LeapSDK::LeapC). + * Ensure LeapC.dll is in your dynamic library search path. + * A popular option is to add a post-build step that copies it to your project's output directory. + +2. For non-CMake projects + * Use a C/C++ compiler such as MSVC, Clang or GCC. + * Add LeapSDK/include to the compiler include search paths. + * Either add a linker reference to LeapC.lib or dynamically load LeapC.dll. + +## Building Samples: + +1. Open CMake using LeapSDK/samples as the source directory + +2. Select a build directory (often LeapSDK/samples/build) to use + +3. Configure & Generate CMake with the generator of your choice + * An example script would be : +```powershell +$env:BUILD_TYPE = 'Release' +$env:REPOS_BUILD_ROOT = 'C:/build' +$env:REPOS_INSTALL_ROOT = 'C:/Program Files' + +cmake -j -S "C:/Program Files/Ultraleap/LeapSDK/samples" -B $env:REPOS_BUILD_ROOT/$env:BUILD_TYPE/LeapSDK/leapc_example ` + -DCMAKE_INSTALL_PREFIX="$env:REPOS_INSTALL_ROOT/leapc_example" ` + -DCMAKE_BUILD_TYPE="$env:BUILD_TYPE" + +cmake --build $env:REPOS_BUILD_ROOT/$env:BUILD_TYPE/LeapSDK/leapc_example -j --config $env:BUILD_TYPE +``` + +4. Open and build the CMake generated project files. For more help, see the CMake documentation. + +## Resources: + +1. Ultraleap For Developers Site (https://developer.leapmotion.com) + provides examples, community forums, Ultraleap news, and documentation + to help you to learn how to develop applications using the Ultraleap Tracking + SDK. + +2. C# and Unity bindings (https://github.com/leapmotion/UnityModules) + +3. C++ bindings matching the old API (https://github.com/leapmotion/LeapCxx) + +-------------------------------------------------------------------------------- + +Copyright © 2012-2020 Ultraleap Ltd. All rights reserved. + +Use subject to the terms of the Ultraleap Tracking SDK Agreement `LICENSE.md` next to this `README.md` file. diff --git a/vendor/LeapSDK/ThirdPartyNotices.md b/vendor/LeapSDK/ThirdPartyNotices.md new file mode 100644 index 00000000..84f828df --- /dev/null +++ b/vendor/LeapSDK/ThirdPartyNotices.md @@ -0,0 +1,5186 @@ +This project uses code from the following third-party projects, listed here +with the full text of their respective licenses. + +abseil (20200225.2) - Apache License (2.0) +=============================================================================== +``` + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +``` +------------------------------------------------------------------------------- + + +Android Core System Libraries - Apache License (2.0) +=============================================================================== +``` +Copyright (C) 2009 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +``` +------------------------------------------------------------------------------- + + +args (6.2.2) - MIT License +=============================================================================== +``` +Copyright (c) 2016-2017 Taylor C. Richberger and Pavel Belikov + + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +asio (1.12.2) - Boost Software License (1.0) +=============================================================================== +``` +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +bzip2 (1.0.8) - Modified combination of Simplified BSD License & zlib/libpng License +=============================================================================== +``` +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2019 Julian R Seward. All +rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Julian Seward, jseward@acm.org +bzip2/libbzip2 version 1.0.8 of 13 July 2019 + +``` +------------------------------------------------------------------------------- + + +catch2 (2.12.1) - Boost Software License (1.0) +=============================================================================== +``` +Boost Software License - Version 1.0 - August 17th, 2003 + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +cctz (2.3) - Apache License (2.0) +=============================================================================== +``` + Apache License + Version 2.0, January 2004 + https://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +``` +------------------------------------------------------------------------------- + + +CLI11 (1.9.1) - New BSD License +=============================================================================== +``` +CLI11 1.8 Copyright (c) 2017-2019 University of Cincinnati, developed by Henry +Schreiner under NSF AWARD 1414736. All rights reserved. + +Redistribution and use in source and binary forms of CLI11, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its contributors + may be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +``` +------------------------------------------------------------------------------- + + +cppyy (1.8.0) - New BSD License (Modified) +=============================================================================== +``` +Copyright (c) 2002-2020, The Regents of the University of California, +through Lawrence Berkeley National Laboratory (subject to receipt of +any required approvals from the U.S. Dept. of Energy). All rights +reserved. Redistribution and use in source and binary forms, with or +without modification, are permitted provided that the following +conditions are met: + +(1) Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. +(2) Redistributions in binary form must reproduce the above copyright +notice, this list of conditions and the following disclaimer in the +documentation and/or other materials provided with the distribution. +(3) Neither the name of the University of California, Lawrence Berkeley +National Laboratory, U.S. Dept. of Energy nor the names of its contributors +may be used to endorse or promote products derived from this software without +specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE +GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +You are under no obligation whatsoever to provide any bug fixes, +patches, or upgrades to the features, functionality or performance of +the source code ("Enhancements") to anyone; however, if you choose to +make your Enhancements available either publicly, or directly to +Lawrence Berkeley National Laboratory, without imposing a separate +written license agreement for such Enhancements, then you hereby grant +the following license: a non-exclusive, royalty-free perpetual license +to install, use, modify, prepare derivative works, incorporate into +other computer software, distribute, and sublicense such Enhancements +or derivative works thereof, in binary and source code form. + + +Additional copyright holders +---------------------------- + +In addition to LBNL/UC Berkeley, this package contains files copyrighted by +one or more of the following people and organizations, and licensed under +the same conditions (except for some compatible licenses as retained in the +source code): + + Lucio Asnaghi + Aditi Dutta + Shaheed Haque + Toby StClere-Smithe + Stefan Wunsch + +Conda-forge recipes were provided by Julian Rueth and Isuru Fernando. + +``` +------------------------------------------------------------------------------- + + +easyloggingpp (9.94.2) - MIT License +=============================================================================== +``` +The MIT License (MIT) + +Copyright (c) 2017 muflihun.com + +https://github.com/muflihun/ +https://muflihun.github.io +https://muflihun.com + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +eigen (3.3.7) - MPL2 +=============================================================================== +``` +Mozilla Public License Version 2.0 +================================== + +1. Definitions +-------------- + +1.1. "Contributor" + means each individual or legal entity that creates, contributes to + the creation of, or owns Covered Software. + +1.2. "Contributor Version" + means the combination of the Contributions of others (if any) used + by a Contributor and that particular Contributor's Contribution. + +1.3. "Contribution" + means Covered Software of a particular Contributor. + +1.4. "Covered Software" + means Source Code Form to which the initial Contributor has attached + the notice in Exhibit A, the Executable Form of such Source Code + Form, and Modifications of such Source Code Form, in each case + including portions thereof. + +1.5. "Incompatible With Secondary Licenses" + means + + (a) that the initial Contributor has attached the notice described + in Exhibit B to the Covered Software; or + + (b) that the Covered Software was made available under the terms of + version 1.1 or earlier of the License, but not also under the + terms of a Secondary License. + +1.6. "Executable Form" + means any form of the work other than Source Code Form. + +1.7. "Larger Work" + means a work that combines Covered Software with other material, in + a separate file or files, that is not Covered Software. + +1.8. "License" + means this document. + +1.9. "Licensable" + means having the right to grant, to the maximum extent possible, + whether at the time of the initial grant or subsequently, any and + all of the rights conveyed by this License. + +1.10. "Modifications" + means any of the following: + + (a) any file in Source Code Form that results from an addition to, + deletion from, or modification of the contents of Covered + Software; or + + (b) any new file in Source Code Form that contains any Covered + Software. + +1.11. "Patent Claims" of a Contributor + means any patent claim(s), including without limitation, method, + process, and apparatus claims, in any patent Licensable by such + Contributor that would be infringed, but for the grant of the + License, by the making, using, selling, offering for sale, having + made, import, or transfer of either its Contributions or its + Contributor Version. + +1.12. "Secondary License" + means either the GNU General Public License, Version 2.0, the GNU + Lesser General Public License, Version 2.1, the GNU Affero General + Public License, Version 3.0, or any later versions of those + licenses. + +1.13. "Source Code Form" + means the form of the work preferred for making modifications. + +1.14. "You" (or "Your") + means an individual or a legal entity exercising rights under this + License. For legal entities, "You" includes any entity that + controls, is controlled by, or is under common control with You. For + purposes of this definition, "control" means (a) the power, direct + or indirect, to cause the direction or management of such entity, + whether by contract or otherwise, or (b) ownership of more than + fifty percent (50%) of the outstanding shares or beneficial + ownership of such entity. + +2. License Grants and Conditions +-------------------------------- + +2.1. Grants + +Each Contributor hereby grants You a world-wide, royalty-free, +non-exclusive license: + +(a) under intellectual property rights (other than patent or trademark) + Licensable by such Contributor to use, reproduce, make available, + modify, display, perform, distribute, and otherwise exploit its + Contributions, either on an unmodified basis, with Modifications, or + as part of a Larger Work; and + +(b) under Patent Claims of such Contributor to make, use, sell, offer + for sale, have made, import, and otherwise transfer either its + Contributions or its Contributor Version. + +2.2. Effective Date + +The licenses granted in Section 2.1 with respect to any Contribution +become effective for each Contribution on the date the Contributor first +distributes such Contribution. + +2.3. Limitations on Grant Scope + +The licenses granted in this Section 2 are the only rights granted under +this License. No additional rights or licenses will be implied from the +distribution or licensing of Covered Software under this License. +Notwithstanding Section 2.1(b) above, no patent license is granted by a +Contributor: + +(a) for any code that a Contributor has removed from Covered Software; + or + +(b) for infringements caused by: (i) Your and any other third party's + modifications of Covered Software, or (ii) the combination of its + Contributions with other software (except as part of its Contributor + Version); or + +(c) under Patent Claims infringed by Covered Software in the absence of + its Contributions. + +This License does not grant any rights in the trademarks, service marks, +or logos of any Contributor (except as may be necessary to comply with +the notice requirements in Section 3.4). + +2.4. Subsequent Licenses + +No Contributor makes additional grants as a result of Your choice to +distribute the Covered Software under a subsequent version of this +License (see Section 10.2) or under the terms of a Secondary License (if +permitted under the terms of Section 3.3). + +2.5. Representation + +Each Contributor represents that the Contributor believes its +Contributions are its original creation(s) or it has sufficient rights +to grant the rights to its Contributions conveyed by this License. + +2.6. Fair Use + +This License is not intended to limit any rights You have under +applicable copyright doctrines of fair use, fair dealing, or other +equivalents. + +2.7. Conditions + +Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted +in Section 2.1. + +3. Responsibilities +------------------- + +3.1. Distribution of Source Form + +All distribution of Covered Software in Source Code Form, including any +Modifications that You create or to which You contribute, must be under +the terms of this License. You must inform recipients that the Source +Code Form of the Covered Software is governed by the terms of this +License, and how they can obtain a copy of this License. You may not +attempt to alter or restrict the recipients' rights in the Source Code +Form. + +3.2. Distribution of Executable Form + +If You distribute Covered Software in Executable Form then: + +(a) such Covered Software must also be made available in Source Code + Form, as described in Section 3.1, and You must inform recipients of + the Executable Form how they can obtain a copy of such Source Code + Form by reasonable means in a timely manner, at a charge no more + than the cost of distribution to the recipient; and + +(b) You may distribute such Executable Form under the terms of this + License, or sublicense it under different terms, provided that the + license for the Executable Form does not attempt to limit or alter + the recipients' rights in the Source Code Form under this License. + +3.3. Distribution of a Larger Work + +You may create and distribute a Larger Work under terms of Your choice, +provided that You also comply with the requirements of this License for +the Covered Software. If the Larger Work is a combination of Covered +Software with a work governed by one or more Secondary Licenses, and the +Covered Software is not Incompatible With Secondary Licenses, this +License permits You to additionally distribute such Covered Software +under the terms of such Secondary License(s), so that the recipient of +the Larger Work may, at their option, further distribute the Covered +Software under the terms of either this License or such Secondary +License(s). + +3.4. Notices + +You may not remove or alter the substance of any license notices +(including copyright notices, patent notices, disclaimers of warranty, +or limitations of liability) contained within the Source Code Form of +the Covered Software, except that You may alter any license notices to +the extent required to remedy known factual inaccuracies. + +3.5. Application of Additional Terms + +You may choose to offer, and to charge a fee for, warranty, support, +indemnity or liability obligations to one or more recipients of Covered +Software. However, You may do so only on Your own behalf, and not on +behalf of any Contributor. You must make it absolutely clear that any +such warranty, support, indemnity, or liability obligation is offered by +You alone, and You hereby agree to indemnify every Contributor for any +liability incurred by such Contributor as a result of warranty, support, +indemnity or liability terms You offer. You may include additional +disclaimers of warranty and limitations of liability specific to any +jurisdiction. + +4. Inability to Comply Due to Statute or Regulation +--------------------------------------------------- + +If it is impossible for You to comply with any of the terms of this +License with respect to some or all of the Covered Software due to +statute, judicial order, or regulation then You must: (a) comply with +the terms of this License to the maximum extent possible; and (b) +describe the limitations and the code they affect. Such description must +be placed in a text file included with all distributions of the Covered +Software under this License. Except to the extent prohibited by statute +or regulation, such description must be sufficiently detailed for a +recipient of ordinary skill to be able to understand it. + +5. Termination +-------------- + +5.1. The rights granted under this License will terminate automatically +if You fail to comply with any of its terms. However, if You become +compliant, then the rights granted under this License from a particular +Contributor are reinstated (a) provisionally, unless and until such +Contributor explicitly and finally terminates Your grants, and (b) on an +ongoing basis, if such Contributor fails to notify You of the +non-compliance by some reasonable means prior to 60 days after You have +come back into compliance. Moreover, Your grants from a particular +Contributor are reinstated on an ongoing basis if such Contributor +notifies You of the non-compliance by some reasonable means, this is the +first time You have received notice of non-compliance with this License +from such Contributor, and You become compliant prior to 30 days after +Your receipt of the notice. + +5.2. If You initiate litigation against any entity by asserting a patent +infringement claim (excluding declaratory judgment actions, +counter-claims, and cross-claims) alleging that a Contributor Version +directly or indirectly infringes any patent, then the rights granted to +You by any and all Contributors for the Covered Software under Section +2.1 of this License shall terminate. + +5.3. In the event of termination under Sections 5.1 or 5.2 above, all +end user license agreements (excluding distributors and resellers) which +have been validly granted by You or Your distributors under this License +prior to termination shall survive termination. + +************************************************************************ +* * +* 6. Disclaimer of Warranty * +* ------------------------- * +* * +* Covered Software is provided under this License on an "as is" * +* basis, without warranty of any kind, either expressed, implied, or * +* statutory, including, without limitation, warranties that the * +* Covered Software is free of defects, merchantable, fit for a * +* particular purpose or non-infringing. The entire risk as to the * +* quality and performance of the Covered Software is with You. * +* Should any Covered Software prove defective in any respect, You * +* (not any Contributor) assume the cost of any necessary servicing, * +* repair, or correction. This disclaimer of warranty constitutes an * +* essential part of this License. No use of any Covered Software is * +* authorized under this License except under this disclaimer. * +* * +************************************************************************ + +************************************************************************ +* * +* 7. Limitation of Liability * +* -------------------------- * +* * +* Under no circumstances and under no legal theory, whether tort * +* (including negligence), contract, or otherwise, shall any * +* Contributor, or anyone who distributes Covered Software as * +* permitted above, be liable to You for any direct, indirect, * +* special, incidental, or consequential damages of any character * +* including, without limitation, damages for lost profits, loss of * +* goodwill, work stoppage, computer failure or malfunction, or any * +* and all other commercial damages or losses, even if such party * +* shall have been informed of the possibility of such damages. This * +* limitation of liability shall not apply to liability for death or * +* personal injury resulting from such party's negligence to the * +* extent applicable law prohibits such limitation. Some * +* jurisdictions do not allow the exclusion or limitation of * +* incidental or consequential damages, so this exclusion and * +* limitation may not apply to You. * +* * +************************************************************************ + +8. Litigation +------------- + +Any litigation relating to this License may be brought only in the +courts of a jurisdiction where the defendant maintains its principal +place of business and such litigation shall be governed by laws of that +jurisdiction, without reference to its conflict-of-law provisions. +Nothing in this Section shall prevent a party's ability to bring +cross-claims or counter-claims. + +9. Miscellaneous +---------------- + +This License represents the complete agreement concerning the subject +matter hereof. If any provision of this License is held to be +unenforceable, such provision shall be reformed only to the extent +necessary to make it enforceable. Any law or regulation which provides +that the language of a contract shall be construed against the drafter +shall not be used to construe this License against a Contributor. + +10. Versions of the License +--------------------------- + +10.1. New Versions + +Mozilla Foundation is the license steward. Except as provided in Section +10.3, no one other than the license steward has the right to modify or +publish new versions of this License. Each version will be given a +distinguishing version number. + +10.2. Effect of New Versions + +You may distribute the Covered Software under the terms of the version +of the License under which You originally received the Covered Software, +or under the terms of any subsequent version published by the license +steward. + +10.3. Modified Versions + +If you create software not governed by this License, and you want to +create a new license for such software, you may create and use a +modified version of this License if you rename the license and remove +any references to the name of the license steward (except to note that +such modified license differs from this License). + +10.4. Distributing Source Code Form that is Incompatible With Secondary +Licenses + +If You choose to distribute Source Code Form that is Incompatible With +Secondary Licenses under the terms of this version of the License, the +notice described in Exhibit B of this License must be attached. + +Exhibit A - Source Code Form License Notice +------------------------------------------- + + This Source Code Form is subject to the terms of the Mozilla Public + License, v. 2.0. If a copy of the MPL was not distributed with this + file, You can obtain one at http://mozilla.org/MPL/2.0/. + +If it is not possible or desirable to put the notice in a particular +file, then You may include the notice in a location (such as a LICENSE +file in a relevant directory) where a recipient would be likely to look +for such a notice. + +You may add additional accurate notices of copyright ownership. + +Exhibit B - "Incompatible With Secondary Licenses" Notice +--------------------------------------------------------- + + This Source Code Form is "Incompatible With Secondary Licenses", as + defined by the Mozilla Public License, v. 2.0. + +``` +------------------------------------------------------------------------------- + + +flatbuffers (1.12.0) - Apache License (2.0) +=============================================================================== +``` + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +``` +------------------------------------------------------------------------------- + + +fmt (7.0.3) - MIT License +=============================================================================== +``` +Copyright (c) 2012 - present, Victor Zverovich + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +--- Optional exception to the license --- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into a machine-executable object form of such +source code, you may redistribute such embedded portions in such object form +without including the above copyright and permission notices. + +``` +------------------------------------------------------------------------------- + + +ghc_filesystem (1.3.2) - MIT License +=============================================================================== +``` +Copyright (c) 2018, Steffen Schümann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +glfw (3.1) - zlib/libpng License +=============================================================================== +``` +Copyright (c) 2002-2006 Marcus Geelnard +Copyright (c) 2006-2010 Camilla Berglund + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would + be appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not + be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source + distribution. + +``` +------------------------------------------------------------------------------- + + +gtest (1.8.1) - New BSD License +=============================================================================== +``` +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +``` +------------------------------------------------------------------------------- + + +imgui (1.49) - MIT License +=============================================================================== +``` +The MIT License (MIT) + +Copyright (c) 2014-2015 Omar Cornut and ImGui contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +jasper (2.0.14) - JasPer License v2.0 +=============================================================================== +``` +JasPer License Version 2.0 + +Copyright (c) 2001-2016 Michael David Adams +Copyright (c) 1999-2000 Image Power, Inc. +Copyright (c) 1999-2000 The University of British Columbia + +All rights reserved. + +Permission is hereby granted, free of charge, to any person (the +"User") obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, and/or sell copies of the Software, and to permit +persons to whom the Software is furnished to do so, subject to the +following conditions: + +1. The above copyright notices and this permission notice (which +includes the disclaimer below) shall be included in all copies or +substantial portions of the Software. + +2. The name of a copyright holder shall not be used to endorse or +promote products derived from the Software without specific prior +written permission. + +THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS +LICENSE. NO USE OF THE SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER +THIS DISCLAIMER. THE SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS +"AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING +BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN NO +EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL +INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. NO ASSURANCES ARE +PROVIDED BY THE COPYRIGHT HOLDERS THAT THE SOFTWARE DOES NOT INFRINGE +THE PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS OF ANY OTHER ENTITY. +EACH COPYRIGHT HOLDER DISCLAIMS ANY LIABILITY TO THE USER FOR CLAIMS +BROUGHT BY ANY OTHER ENTITY BASED ON INFRINGEMENT OF INTELLECTUAL +PROPERTY RIGHTS OR OTHERWISE. AS A CONDITION TO EXERCISING THE RIGHTS +GRANTED HEREUNDER, EACH USER HEREBY ASSUMES SOLE RESPONSIBILITY TO SECURE +ANY OTHER INTELLECTUAL PROPERTY RIGHTS NEEDED, IF ANY. THE SOFTWARE +IS NOT FAULT-TOLERANT AND IS NOT INTENDED FOR USE IN MISSION-CRITICAL +SYSTEMS, SUCH AS THOSE USED IN THE OPERATION OF NUCLEAR FACILITIES, +AIRCRAFT NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL +SYSTEMS, DIRECT LIFE SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH +THE FAILURE OF THE SOFTWARE OR SYSTEM COULD LEAD DIRECTLY TO DEATH, +PERSONAL INJURY, OR SEVERE PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH +RISK ACTIVITIES"). THE COPYRIGHT HOLDERS SPECIFICALLY DISCLAIM ANY +EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR HIGH RISK ACTIVITIES. + + +``` +------------------------------------------------------------------------------- + + +libjpeg (9c) - JPEG software 2018 +=============================================================================== +``` +The Independent JPEG Group's JPEG software +========================================== + +README for release 9c of 14-Jan-2018 +==================================== + +This distribution contains the ninth public release of the Independent JPEG +Group's free JPEG software. You are welcome to redistribute this software and +to use it for any purpose, subject to the conditions under LEGAL ISSUES, below. + +This software is the work of Tom Lane, Guido Vollbeding, Philip Gladstone, +Bill Allombert, Jim Boucher, Lee Crocker, Bob Friesenhahn, Ben Jackson, +Julian Minguillon, Luis Ortiz, George Phillips, Davide Rossi, Ge' Weijers, +and other members of the Independent JPEG Group. + +IJG is not affiliated with the ISO/IEC JTC1/SC29/WG1 standards committee +(previously known as JPEG, together with ITU-T SG16). + + +DOCUMENTATION ROADMAP +===================== + +This file contains the following sections: + +OVERVIEW General description of JPEG and the IJG software. +LEGAL ISSUES Copyright, lack of warranty, terms of distribution. +REFERENCES Where to learn more about JPEG. +ARCHIVE LOCATIONS Where to find newer versions of this software. +ACKNOWLEDGMENTS Special thanks. +FILE FORMAT WARS Software *not* to get. +TO DO Plans for future IJG releases. + +Other documentation files in the distribution are: + +User documentation: + install.txt How to configure and install the IJG software. + usage.txt Usage instructions for cjpeg, djpeg, jpegtran, + rdjpgcom, and wrjpgcom. + *.1 Unix-style man pages for programs (same info as usage.txt). + wizard.txt Advanced usage instructions for JPEG wizards only. + change.log Version-to-version change highlights. +Programmer and internal documentation: + libjpeg.txt How to use the JPEG library in your own programs. + example.c Sample code for calling the JPEG library. + structure.txt Overview of the JPEG library's internal structure. + filelist.txt Road map of IJG files. + coderules.txt Coding style rules --- please read if you contribute code. + +Please read at least the files install.txt and usage.txt. Some information +can also be found in the JPEG FAQ (Frequently Asked Questions) article. See +ARCHIVE LOCATIONS below to find out where to obtain the FAQ article. + +If you want to understand how the JPEG code works, we suggest reading one or +more of the REFERENCES, then looking at the documentation files (in roughly +the order listed) before diving into the code. + + +OVERVIEW +======== + +This package contains C software to implement JPEG image encoding, decoding, +and transcoding. JPEG (pronounced "jay-peg") is a standardized compression +method for full-color and grayscale images. + +This software implements JPEG baseline, extended-sequential, and progressive +compression processes. Provision is made for supporting all variants of these +processes, although some uncommon parameter settings aren't implemented yet. +We have made no provision for supporting the hierarchical or lossless +processes defined in the standard. + +We provide a set of library routines for reading and writing JPEG image files, +plus two sample applications "cjpeg" and "djpeg", which use the library to +perform conversion between JPEG and some other popular image file formats. +The library is intended to be reused in other applications. + +In order to support file conversion and viewing software, we have included +considerable functionality beyond the bare JPEG coding/decoding capability; +for example, the color quantization modules are not strictly part of JPEG +decoding, but they are essential for output to colormapped file formats or +colormapped displays. These extra functions can be compiled out of the +library if not required for a particular application. + +We have also included "jpegtran", a utility for lossless transcoding between +different JPEG processes, and "rdjpgcom" and "wrjpgcom", two simple +applications for inserting and extracting textual comments in JFIF files. + +The emphasis in designing this software has been on achieving portability and +flexibility, while also making it fast enough to be useful. In particular, +the software is not intended to be read as a tutorial on JPEG. (See the +REFERENCES section for introductory material.) Rather, it is intended to +be reliable, portable, industrial-strength code. We do not claim to have +achieved that goal in every aspect of the software, but we strive for it. + +We welcome the use of this software as a component of commercial products. +No royalty is required, but we do ask for an acknowledgement in product +documentation, as described under LEGAL ISSUES. + + +LEGAL ISSUES +============ + +In plain English: + +1. We don't promise that this software works. (But if you find any bugs, + please let us know!) +2. You can use this software for whatever you want. You don't have to pay us. +3. You may not pretend that you wrote this software. If you use it in a + program, you must acknowledge somewhere in your documentation that + you've used the IJG code. + +In legalese: + +The authors make NO WARRANTY or representation, either express or implied, +with respect to this software, its quality, accuracy, merchantability, or +fitness for a particular purpose. This software is provided "AS IS", and you, +its user, assume the entire risk as to its quality and accuracy. + +This software is copyright (C) 1991-2018, Thomas G. Lane, Guido Vollbeding. +All Rights Reserved except as specified below. + +Permission is hereby granted to use, copy, modify, and distribute this +software (or portions thereof) for any purpose, without fee, subject to these +conditions: +(1) If any part of the source code for this software is distributed, then this +README file must be included, with this copyright and no-warranty notice +unaltered; and any additions, deletions, or changes to the original files +must be clearly indicated in accompanying documentation. +(2) If only executable code is distributed, then the accompanying +documentation must state that "this software is based in part on the work of +the Independent JPEG Group". +(3) Permission for use of this software is granted only if the user accepts +full responsibility for any undesirable consequences; the authors accept +NO LIABILITY for damages of any kind. + +These conditions apply to any software derived from or based on the IJG code, +not just to the unmodified library. If you use our work, you ought to +acknowledge us. + +Permission is NOT granted for the use of any IJG author's name or company name +in advertising or publicity relating to this software or products derived from +it. This software may be referred to only as "the Independent JPEG Group's +software". + +We specifically permit and encourage the use of this software as the basis of +commercial products, provided that all warranty or liability claims are +assumed by the product vendor. + + +The Unix configuration script "configure" was produced with GNU Autoconf. +It is copyright by the Free Software Foundation but is freely distributable. +The same holds for its supporting scripts (config.guess, config.sub, +ltmain.sh). Another support script, install-sh, is copyright by X Consortium +but is also freely distributable. + +The IJG distribution formerly included code to read and write GIF files. +To avoid entanglement with the Unisys LZW patent (now expired), GIF reading +support has been removed altogether, and the GIF writer has been simplified +to produce "uncompressed GIFs". This technique does not use the LZW +algorithm; the resulting GIF files are larger than usual, but are readable +by all standard GIF decoders. + + +REFERENCES +========== + +We recommend reading one or more of these references before trying to +understand the innards of the JPEG software. + +The best short technical introduction to the JPEG compression algorithm is + Wallace, Gregory K. "The JPEG Still Picture Compression Standard", + Communications of the ACM, April 1991 (vol. 34 no. 4), pp. 30-44. +(Adjacent articles in that issue discuss MPEG motion picture compression, +applications of JPEG, and related topics.) If you don't have the CACM issue +handy, a PDF file containing a revised version of Wallace's article is +available at http://www.ijg.org/files/Wallace.JPEG.pdf. The file (actually +a preprint for an article that appeared in IEEE Trans. Consumer Electronics) +omits the sample images that appeared in CACM, but it includes corrections +and some added material. Note: the Wallace article is copyright ACM and IEEE, +and it may not be used for commercial purposes. + +A somewhat less technical, more leisurely introduction to JPEG can be found in +"The Data Compression Book" by Mark Nelson and Jean-loup Gailly, published by +M&T Books (New York), 2nd ed. 1996, ISBN 1-55851-434-1. This book provides +good explanations and example C code for a multitude of compression methods +including JPEG. It is an excellent source if you are comfortable reading C +code but don't know much about data compression in general. The book's JPEG +sample code is far from industrial-strength, but when you are ready to look +at a full implementation, you've got one here... + +The best currently available description of JPEG is the textbook "JPEG Still +Image Data Compression Standard" by William B. Pennebaker and Joan L. +Mitchell, published by Van Nostrand Reinhold, 1993, ISBN 0-442-01272-1. +Price US$59.95, 638 pp. The book includes the complete text of the ISO JPEG +standards (DIS 10918-1 and draft DIS 10918-2). +Although this is by far the most detailed and comprehensive exposition of +JPEG publicly available, we point out that it is still missing an explanation +of the most essential properties and algorithms of the underlying DCT +technology. +If you think that you know about DCT-based JPEG after reading this book, +then you are in delusion. The real fundamentals and corresponding potential +of DCT-based JPEG are not publicly known so far, and that is the reason for +all the mistaken developments taking place in the image coding domain. + +The original JPEG standard is divided into two parts, Part 1 being the actual +specification, while Part 2 covers compliance testing methods. Part 1 is +titled "Digital Compression and Coding of Continuous-tone Still Images, +Part 1: Requirements and guidelines" and has document numbers ISO/IEC IS +10918-1, ITU-T T.81. Part 2 is titled "Digital Compression and Coding of +Continuous-tone Still Images, Part 2: Compliance testing" and has document +numbers ISO/IEC IS 10918-2, ITU-T T.83. +IJG JPEG 8 introduced an implementation of the JPEG SmartScale extension +which is specified in two documents: A contributed document at ITU and ISO +with title "ITU-T JPEG-Plus Proposal for Extending ITU-T T.81 for Advanced +Image Coding", April 2006, Geneva, Switzerland. The latest version of this +document is Revision 3. And a contributed document ISO/IEC JTC1/SC29/WG1 N +5799 with title "Evolution of JPEG", June/July 2011, Berlin, Germany. +IJG JPEG 9 introduces a reversible color transform for improved lossless +compression which is described in a contributed document ISO/IEC JTC1/SC29/ +WG1 N 6080 with title "JPEG 9 Lossless Coding", June/July 2012, Paris, +France. + +The JPEG standard does not specify all details of an interchangeable file +format. For the omitted details we follow the "JFIF" conventions, version 2. +JFIF version 1 has been adopted as Recommendation ITU-T T.871 (05/2011) : +Information technology - Digital compression and coding of continuous-tone +still images: JPEG File Interchange Format (JFIF). It is available as a +free download in PDF file format from http://www.itu.int/rec/T-REC-T.871. +A PDF file of the older JFIF document is available at +http://www.w3.org/Graphics/JPEG/jfif3.pdf. + +The TIFF 6.0 file format specification can be obtained by FTP from +ftp://ftp.sgi.com/graphics/tiff/TIFF6.ps.gz. The JPEG incorporation scheme +found in the TIFF 6.0 spec of 3-June-92 has a number of serious problems. +IJG does not recommend use of the TIFF 6.0 design (TIFF Compression tag 6). +Instead, we recommend the JPEG design proposed by TIFF Technical Note #2 +(Compression tag 7). Copies of this Note can be obtained from +http://www.ijg.org/files/. It is expected that the next revision +of the TIFF spec will replace the 6.0 JPEG design with the Note's design. +Although IJG's own code does not support TIFF/JPEG, the free libtiff library +uses our library to implement TIFF/JPEG per the Note. + + +ARCHIVE LOCATIONS +================= + +The "official" archive site for this software is www.ijg.org. +The most recent released version can always be found there in +directory "files". This particular version will be archived as +http://www.ijg.org/files/jpegsrc.v9c.tar.gz, and in Windows-compatible +"zip" archive format as http://www.ijg.org/files/jpegsr9c.zip. + +The JPEG FAQ (Frequently Asked Questions) article is a source of some +general information about JPEG. +It is available on the World Wide Web at http://www.faqs.org/faqs/jpeg-faq/ +and other news.answers archive sites, including the official news.answers +archive at rtfm.mit.edu: ftp://rtfm.mit.edu/pub/usenet/news.answers/jpeg-faq/. +If you don't have Web or FTP access, send e-mail to mail-server@rtfm.mit.edu +with body + send usenet/news.answers/jpeg-faq/part1 + send usenet/news.answers/jpeg-faq/part2 + + +ACKNOWLEDGMENTS +=============== + +Thank to Juergen Bruder for providing me with a copy of the common DCT +algorithm article, only to find out that I had come to the same result +in a more direct and comprehensible way with a more generative approach. + +Thank to Istvan Sebestyen and Joan L. Mitchell for inviting me to the +ITU JPEG (Study Group 16) meeting in Geneva, Switzerland. + +Thank to Thomas Wiegand and Gary Sullivan for inviting me to the +Joint Video Team (MPEG & ITU) meeting in Geneva, Switzerland. + +Thank to Thomas Richter and Daniel Lee for inviting me to the +ISO/IEC JTC1/SC29/WG1 (previously known as JPEG, together with ITU-T SG16) +meeting in Berlin, Germany. + +Thank to John Korejwa and Massimo Ballerini for inviting me to +fruitful consultations in Boston, MA and Milan, Italy. + +Thank to Hendrik Elstner, Roland Fassauer, Simone Zuck, Guenther +Maier-Gerber, Walter Stoeber, Fred Schmitz, and Norbert Braunagel +for corresponding business development. + +Thank to Nico Zschach and Dirk Stelling of the technical support team +at the Digital Images company in Halle for providing me with extra +equipment for configuration tests. + +Thank to Richard F. Lyon (then of Foveon Inc.) for fruitful +communication about JPEG configuration in Sigma Photo Pro software. + +Thank to Andrew Finkenstadt for hosting the ijg.org site. + +Thank to Thomas G. Lane for the original design and development of +this singular software package. + +Thank to Lars Goehler, Andreas Heinecke, Sebastian Fuss, Yvonne Roebert, +Andrej Werner, and Ulf-Dietrich Braumann for support and public relations. + + +FILE FORMAT WARS +================ + +The ISO/IEC JTC1/SC29/WG1 standards committee (previously known as JPEG, +together with ITU-T SG16) currently promotes different formats containing +the name "JPEG" which is misleading because these formats are incompatible +with original DCT-based JPEG and are based on faulty technologies. +IJG therefore does not and will not support such momentary mistakes +(see REFERENCES). +There exist also distributions under the name "OpenJPEG" promoting such +kind of formats which is misleading because they don't support original +JPEG images. +We have no sympathy for the promotion of inferior formats. Indeed, one of +the original reasons for developing this free software was to help force +convergence on common, interoperable format standards for JPEG files. +Don't use an incompatible file format! +(In any case, our decoder will remain capable of reading existing JPEG +image files indefinitely.) + +The ISO committee pretends to be "responsible for the popular JPEG" in their +public reports which is not true because they don't respond to actual +requirements for the maintenance of the original JPEG specification. +Furthermore, the ISO committee pretends to "ensure interoperability" with +their standards which is not true because their "standards" support only +application-specific and proprietary use cases and contain mathematically +incorrect code. + +There are currently different distributions in circulation containing the +name "libjpeg" which is misleading because they don't have the features and +are incompatible with formats supported by actual IJG libjpeg distributions. +One of those fakes is released by members of the ISO committee and just uses +the name of libjpeg for misdirection of people, similar to the abuse of the +name JPEG as described above, while having nothing in common with actual IJG +libjpeg distributions and containing mathematically incorrect code. +The other one claims to be a "derivative" or "fork" of the original libjpeg, +but violates the license conditions as described under LEGAL ISSUES above +and violates basic C programming properties. +We have no sympathy for the release of misleading, incorrect and illegal +distributions derived from obsolete code bases. +Don't use an obsolete code base! + +According to the UCC (Uniform Commercial Code) law, IJG has the lawful and +legal right to foreclose on certain standardization bodies and other +institutions or corporations that knowingly perform substantial and +systematic deceptive acts and practices, fraud, theft, and damaging of the +value of the people of this planet without their knowing, willing and +intentional consent. +The titles, ownership, and rights of these institutions and all their assets +are now duly secured and held in trust for the free people of this planet. +People of the planet, on every country, may have a financial interest in +the assets of these former principals, agents, and beneficiaries of the +foreclosed institutions and corporations. +IJG asserts what is: that each man, woman, and child has unalienable value +and rights granted and deposited in them by the Creator and not any one of +the people is subordinate to any artificial principality, corporate fiction +or the special interest of another without their appropriate knowing, +willing and intentional consent made by contract or accommodation agreement. +IJG expresses that which already was. +The people have already determined and demanded that public administration +entities, national governments, and their supporting judicial systems must +be fully transparent, accountable, and liable. +IJG has secured the value for all concerned free people of the planet. + +A partial list of foreclosed institutions and corporations ("Hall of Shame") +is currently prepared and will be published later. + + +TO DO +===== + +Version 9 is the second release of a new generation JPEG standard +to overcome the limitations of the original JPEG specification, +and is the first true source reference JPEG codec. +More features are being prepared for coming releases... + +Please send bug reports, offers of help, etc. to jpeg-info@jpegclub.org. + +``` +------------------------------------------------------------------------------- + + +libpng (1.6.37) - PNG Reference Library License 2.0 +=============================================================================== +``` +COPYRIGHT NOTICE, DISCLAIMER, and LICENSE +========================================= + +PNG Reference Library License version 2 +--------------------------------------- + + * Copyright (c) 1995-2019 The PNG Reference Library Authors. + * Copyright (c) 2018-2019 Cosmin Truta. + * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. + * Copyright (c) 1996-1997 Andreas Dilger. + * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +The software is supplied "as is", without warranty of any kind, +express or implied, including, without limitation, the warranties +of merchantability, fitness for a particular purpose, title, and +non-infringement. In no event shall the Copyright owners, or +anyone distributing the software, be liable for any damages or +other liability, whether in contract, tort or otherwise, arising +from, out of, or in connection with the software, or the use or +other dealings in the software, even if advised of the possibility +of such damage. + +Permission is hereby granted to use, copy, modify, and distribute +this software, or portions hereof, for any purpose, without fee, +subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you + use this software in a product, an acknowledgment in the product + documentation would be appreciated, but is not required. + + 2. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + + +PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) +----------------------------------------------------------------------- + +libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are +Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are +derived from libpng-1.0.6, and are distributed according to the same +disclaimer and license as libpng-1.0.6 with the following individuals +added to the list of Contributing Authors: + + Simon-Pierre Cadieux + Eric S. Raymond + Mans Rullgard + Cosmin Truta + Gilles Vollant + James Yu + Mandar Sahastrabuddhe + Google Inc. + Vadim Barkov + +and with the following additions to the disclaimer: + + There is no warranty against interference with your enjoyment of + the library or against infringement. There is no warranty that our + efforts or the library will fulfill any of your particular purposes + or needs. This library is provided with all faults, and the entire + risk of satisfactory quality, performance, accuracy, and effort is + with the user. + +Some files in the "contrib" directory and some configure-generated +files that are distributed with libpng have other copyright owners, and +are released under other open source licenses. + +libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are +Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from +libpng-0.96, and are distributed according to the same disclaimer and +license as libpng-0.96, with the following individuals added to the +list of Contributing Authors: + + Tom Lane + Glenn Randers-Pehrson + Willem van Schaik + +libpng versions 0.89, June 1996, through 0.96, May 1997, are +Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, +and are distributed according to the same disclaimer and license as +libpng-0.88, with the following individuals added to the list of +Contributing Authors: + + John Bowler + Kevin Bracey + Sam Bushell + Magnus Holmgren + Greg Roelofs + Tom Tanner + +Some files in the "scripts" directory have other copyright owners, +but are released under this license. + +libpng versions 0.5, May 1995, through 0.88, January 1996, are +Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + +For the purposes of this copyright and license, "Contributing Authors" +is defined as the following set of individuals: + + Andreas Dilger + Dave Martindale + Guy Eric Schalnat + Paul Schmidt + Tim Wegner + +The PNG Reference Library is supplied "AS IS". The Contributing +Authors and Group 42, Inc. disclaim all warranties, expressed or +implied, including, without limitation, the warranties of +merchantability and of fitness for any purpose. The Contributing +Authors and Group 42, Inc. assume no liability for direct, indirect, +incidental, special, exemplary, or consequential damages, which may +result from the use of the PNG Reference Library, even if advised of +the possibility of such damage. + +Permission is hereby granted to use, copy, modify, and distribute this +source code, or portions hereof, for any purpose, without fee, subject +to the following restrictions: + + 1. The origin of this source code must not be misrepresented. + + 2. Altered versions must be plainly marked as such and must not + be misrepresented as being the original source. + + 3. This Copyright notice may not be removed or altered from any + source or altered source distribution. + +The Contributing Authors and Group 42, Inc. specifically permit, +without fee, and encourage the use of this source code as a component +to supporting the PNG file format in commercial products. If you use +this source code in a product, acknowledgment is not required but would +be appreciated. + +``` +------------------------------------------------------------------------------- + + +libtm - Apache License (2.0) +=============================================================================== +``` + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +``` +------------------------------------------------------------------------------- + + +libusb (1.0.23) - GNU LGPL (2.1) +=============================================================================== +``` + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish) that you receive source code or can get +it if you want it that you can change the software and use pieces of +it in new free programs and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty keep intact +all the notices that refer to this License and to the absence of any +warranty and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above) and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + +``` +------------------------------------------------------------------------------- + + +libwebp (1.0.3) - New BSD License +=============================================================================== +``` +Copyright (c) 2010, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + * Neither the name of Google nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +``` +------------------------------------------------------------------------------- + + +opencv (4.1.1) - New BSD License, Apache License (2.0), MIT License (Modified), ISC License +=============================================================================== +``` +By downloading, copying, installing or using the software you agree to this license. +If you do not agree to this license, do not download, install, +copy or use the software. + + + License Agreement + For Open Source Computer Vision Library + (3-clause BSD License) + +Copyright (C) 2000-2019, Intel Corporation, all rights reserved. +Copyright (C) 2009-2011, Willow Garage Inc., all rights reserved. +Copyright (C) 2009-2016, NVIDIA Corporation, all rights reserved. +Copyright (C) 2010-2013, Advanced Micro Devices, Inc., all rights reserved. +Copyright (C) 2015-2016, OpenCV Foundation, all rights reserved. +Copyright (C) 2015-2016, Itseez Inc., all rights reserved. +Third party copyrights are property of their respective owners. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the names of the copyright holders nor the names of the contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as is" and +any express or implied warranties, including, but not limited to, the implied +warranties of merchantability and fitness for a particular purpose are disclaimed. +In no event shall copyright holders or contributors be liable for any direct, +indirect, incidental, special, exemplary, or consequential damages +(including, but not limited to, procurement of substitute goods or services; +loss of use, data, or profits; or business interruption) however caused +and on any theory of liability, whether in contract, strict liability, +or tort (including negligence or otherwise) arising in any way out of +the use of this software, even if advised of the possibility of such damage. + +``` +------------------------------------------------------------------------------- + + +opencv (4.1.1) - New BSD License, Apache License (2.0), MIT License (Modified), ISC License +=============================================================================== +``` + +License for Berkeley SoftFloat Release 3c + +John R. Hauser +2017 February 10 + +The following applies to the whole of SoftFloat Release 3c as well as to +each source file individually. + +Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the +University of California. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions, and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +``` +------------------------------------------------------------------------------- + + +opencv (4.1.1) - New BSD License, Apache License (2.0), MIT License (Modified), ISC License +=============================================================================== +``` +Copyright (c) 2008-2015 The Khronos Group Inc. + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and/or associated documentation files (the +"Materials"), to deal in the Materials without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Materials, and to +permit persons to whom the Materials are furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Materials. + +MODIFICATIONS TO THIS FILE MAY MEAN IT NO LONGER ACCURATELY REFLECTS +KHRONOS STANDARDS. THE UNMODIFIED, NORMATIVE VERSIONS OF KHRONOS +SPECIFICATIONS AND HEADER INFORMATION ARE LOCATED AT + https://www.khronos.org/registry/ + +THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. + +``` +------------------------------------------------------------------------------- + + +opencv (4.1.1) - New BSD License, Apache License (2.0), MIT License (Modified), ISC License +=============================================================================== +``` +quirc -- QR-code recognition library +Copyright (C) 2010-2012 Daniel Beer + +Permission to use, copy, modify, and/or distribute this software for +any purpose with or without fee is hereby granted, provided that the +above copyright notice and this permission notice appear in all +copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL +DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR +PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +openssl (1.1.1) - OpenSSL License 2019, SSLeay License 1998 +=============================================================================== +``` + LICENSE ISSUES + ============== + + The OpenSSL toolkit stays under a double license, i.e. both the conditions of + the OpenSSL License and the original SSLeay license apply to the toolkit. + See below for the actual license texts. + + OpenSSL License + --------------- + +/* ==================================================================== + * Copyright (c) 1998-2019 The OpenSSL Project. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * 3. All advertising materials mentioning features or use of this + * software must display the following acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" + * + * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to + * endorse or promote products derived from this software without + * prior written permission. For written permission, please contact + * openssl-core@openssl.org. + * + * 5. Products derived from this software may not be called "OpenSSL" + * nor may "OpenSSL" appear in their names without prior written + * permission of the OpenSSL Project. + * + * 6. Redistributions of any form whatsoever must retain the following + * acknowledgment: + * "This product includes software developed by the OpenSSL Project + * for use in the OpenSSL Toolkit (http://www.openssl.org/)" + * + * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY + * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR + * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * ==================================================================== + * + * This product includes cryptographic software written by Eric Young + * (eay@cryptsoft.com). This product includes software written by Tim + * Hudson (tjh@cryptsoft.com). + * + */ + + Original SSLeay License + ----------------------- + +/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) + * All rights reserved. + * + * This package is an SSL implementation written + * by Eric Young (eay@cryptsoft.com). + * The implementation was written so as to conform with Netscapes SSL. + * + * This library is free for commercial and non-commercial use as long as + * the following conditions are aheared to. The following conditions + * apply to all code found in this distribution, be it the RC4, RSA, + * lhash, DES, etc., code; not just the SSL code. The SSL documentation + * included with this distribution is covered by the same copyright terms + * except that the holder is Tim Hudson (tjh@cryptsoft.com). + * + * Copyright remains Eric Young's, and as such any Copyright notices in + * the code are not to be removed. + * If this package is used in a product, Eric Young should be given attribution + * as the author of the parts of the library used. + * This can be in the form of a textual message at program startup or + * in documentation (online or textual) provided with the package. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * "This product includes cryptographic software written by + * Eric Young (eay@cryptsoft.com)" + * The word 'cryptographic' can be left out if the rouines from the library + * being used are not cryptographic related :-). + * 4. If you include any Windows specific code (or a derivative thereof) from + * the apps directory (application code) you must include an acknowledgement: + * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)" + * + * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * The licence and distribution terms for any publically available version or + * derivative of this code cannot be changed. i.e. this code cannot simply be + * copied and put under another distribution licence + * [including the GNU Public Licence.] + */ + + +``` +------------------------------------------------------------------------------- + + +protobuf (3.6.1) - New BSD License (with exception) +=============================================================================== +``` +Copyright 2008 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + +``` +------------------------------------------------------------------------------- + + +rapidjson (1.1.0) - MIT License, New BSD License, & JSON License +=============================================================================== +``` +Tencent is pleased to support the open source community by making RapidJSON available. + +Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. + +If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License. +If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license. +A copy of the MIT License is included in this file. + +Other dependencies and licenses: + +Open Source Software Licensed Under the BSD License: +-------------------------------------------------------------------- + +The msinttypes r29 +Copyright (c) 2006-2013 Alexander Chemeris +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name of copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Open Source Software Licensed Under the JSON License: +-------------------------------------------------------------------- + +json.org +Copyright (c) 2002 JSON.org +All Rights Reserved. + +JSON_checker +Copyright (c) 2002 JSON.org +All Rights Reserved. + + +Terms of the JSON License: +--------------------------------------------------- + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +The Software shall be used for Good, not Evil. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +Terms of the MIT License: +-------------------------------------------------------------------- + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +rapidxml (1.13) - Boost Software License (1.0) & MIT License +=============================================================================== +``` +Use of this software is granted under one of the following two licenses, +to be chosen freely by the user. + +1. Boost Software License - Version 1.0 - August 17th, 2003 +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person or organization +obtaining a copy of the software and accompanying documentation covered by +this license (the "Software") to use, reproduce, display, distribute, +execute, and transmit the Software, and to prepare derivative works of the +Software, and to permit third-parties to whom the Software is furnished to +do so, all subject to the following: + +The copyright notices in the Software and this entire statement, including +the above license grant, this restriction and the following disclaimer, +must be included in all copies of the Software, in whole or in part, and +all derivative works of the Software, unless such copies or derivative +works are solely in the form of machine-executable object code generated by +a source language processor. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT +SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. + +2. The MIT License +=============================================================================== + +Copyright (c) 2006, 2007 Marcin Kalicinski + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE.The MIT License (MIT) + +Copyright (c) 2014-2015 Omar Cornut and ImGui contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +readerwriterqueue (1.0.1) - Simplified BSD License +=============================================================================== +``` +This license applies to all the code in this repository except that written by third +parties, namely the files in benchmarks/ext, which have their own licenses, and Jeff +Preshing's semaphore implementation (used in the blocking queue) which has a zlib +license (embedded in atomicops.h). + +Simplified BSD License: + +Copyright (c) 2013-2015, Cameron Desrochers +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of +conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this list of +conditions and the following disclaimer in the documentation and/or other materials +provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +``` +------------------------------------------------------------------------------- + + +librealsense - Apache License (2.0) +=============================================================================== +``` + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Intel Corporation + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this project except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +``` +------------------------------------------------------------------------------- + + +Remotery - Apache License (2.0) +=============================================================================== +``` + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +``` +------------------------------------------------------------------------------- + + +spdlog (1.8.0) - MIT License +=============================================================================== +``` +The MIT License (MIT) + +Copyright (c) 2016 Gabi Melman. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +-- NOTE: Third party dependency used by this software -- +This software depends on the fmt lib (MIT License), +and users must comply to its license: https://github.com/fmtlib/fmt/blob/master/LICENSE.rst + + +``` +------------------------------------------------------------------------------- + + +sqlite (3.13.0) - SQLite Blessing +=============================================================================== +``` +The author disclaims copyright to this source code. In place of +a legal notice, here is a blessing: + + May you do good and not evil. + May you find forgiveness for yourself and forgive others. + May you share freely, never taking more than you give. + +``` +------------------------------------------------------------------------------- + + +tclap (1.2.1) - MIT License +=============================================================================== +``` + + +Copyright (c) 2003 Michael E. Smoot + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without restriction, +including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, +and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS +BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN +AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +tensorflowlite (2.2.0) - Apache License (2.0) +=============================================================================== +``` +Copyright 2019 The TensorFlow Authors. All rights reserved. + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +``` +------------------------------------------------------------------------------- + + +websocketpp (0.8.2) - WebSocket++ 2014 +=============================================================================== +``` +Main Library: + +Copyright (c) 2014, Peter Thorson. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the WebSocket++ Project nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL PETER THORSON BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Bundled Libraries: + +****** Base 64 Library (base64/base64.hpp) ****** +base64.hpp is a repackaging of the base64.cpp and base64.h files into a +single header suitable for use as a header only library. This conversion was +done by Peter Thorson (webmaster@zaphoyd.com) in 2012. All modifications to +the code are redistributed under the same license as the original, which is +listed below. + +base64.cpp and base64.h + +Copyright (C) 2004-2008 René Nyffenegger + +This source code is provided 'as-is', without any express or implied +warranty. In no event will the author be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this source code must not be misrepresented; you must not + claim that you wrote the original source code. If you use this source code + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original source code. + +3. This notice may not be removed or altered from any source distribution. + +René Nyffenegger rene.nyffenegger@adp-gmbh.ch + +****** SHA1 Library (sha1/sha1.hpp) ****** +sha1.hpp is a repackaging of the sha1.cpp and sha1.h files from the shallsha1 +library (http://code.google.com/p/smallsha1/) into a single header suitable for +use as a header only library. This conversion was done by Peter Thorson +(webmaster@zaphoyd.com) in 2013. All modifications to the code are redistributed +under the same license as the original, which is listed below. + + Copyright (c) 2011, Micael Hildenborg + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of Micael Hildenborg nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY Micael Hildenborg ''AS IS'' AND ANY + EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL Micael Hildenborg BE LIABLE FOR ANY + DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +****** MD5 Library (common/md5.hpp) ****** +md5.hpp is a reformulation of the md5.h and md5.c code from +http://www.opensource.apple.com/source/cups/cups-59/cups/md5.c to allow it to +function as a component of a header only library. This conversion was done by +Peter Thorson (webmaster@zaphoyd.com) in 2012 for the WebSocket++ project. The +changes are released under the same license as the original (listed below) + +Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +L. Peter Deutsch +ghost@aladdin.com + +****** UTF8 Validation logic (utf8_validation.hpp) ****** +utf8_validation.hpp is adapted from code originally written by Bjoern Hoehrmann +. See http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ for +details. + +The original license: + +Copyright (c) 2008-2009 Bjoern Hoehrmann + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +``` +------------------------------------------------------------------------------- + + +zlib (1.2.11) - The zlib/libpng License (Zlib) +=============================================================================== +``` + zlib.h -- interface of the 'zlib' general purpose compression library + version 1.2.11, January 15th, 2017 + + Copyright (C) 1995-2017 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files http://tools.ietf.org/html/rfc1950 + (zlib format), rfc1951 (deflate format) and rfc1952 (gzip format). + +``` +------------------------------------------------------------------------------- + + +Qt (5.15.2) - GNU LGPL (3.0) +=============================================================================== +``` + GNU LESSER GENERAL PUBLIC LICENSE + + The Qt Toolkit is Copyright (C) 2015 The Qt Company Ltd. + Contact: http://www.qt.io/licensing/ + + You may use, distribute and copy the Qt Toolkit under the terms of + GNU Lesser General Public License version 3, which is displayed below. + This license makes reference to the version 3 of the GNU General + Public License, which you can find in the LICENSE.GPLv3 file. + +------------------------------------------------------------------------- + + GNU LESSER GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright © 2007 Free Software Foundation, Inc. +Everyone is permitted to copy and distribute verbatim copies of this +licensedocument, but changing it is not allowed. + +This version of the GNU Lesser General Public License incorporates +the terms and conditions of version 3 of the GNU General Public +License, supplemented by the additional permissions listed below. + +0. Additional Definitions. + + As used herein, “this License” refers to version 3 of the GNU Lesser +General Public License, and the “GNU GPL” refers to version 3 of the +GNU General Public License. + + “The Library” refers to a covered work governed by this License, +other than an Application or a Combined Work as defined below. + + An “Application” is any work that makes use of an interface provided +by the Library, but which is not otherwise based on the Library. +Defining a subclass of a class defined by the Library is deemed a mode +of using an interface provided by the Library. + + A “Combined Work” is a work produced by combining or linking an +Application with the Library. The particular version of the Library +with which the Combined Work was made is also called the “Linked +Version”. + + The “Minimal Corresponding Source” for a Combined Work means the +Corresponding Source for the Combined Work, excluding any source code +for portions of the Combined Work that, considered in isolation, are +based on the Application, and not on the Linked Version. + + The “Corresponding Application Code” for a Combined Work means the +object code and/or source code for the Application, including any data +and utility programs needed for reproducing the Combined Work from the +Application, but excluding the System Libraries of the Combined Work. + +1. Exception to Section 3 of the GNU GPL. + + You may convey a covered work under sections 3 and 4 of this License +without being bound by section 3 of the GNU GPL. + +2. Conveying Modified Versions. + + If you modify a copy of the Library, and, in your modifications, a +facility refers to a function or data to be supplied by an Application +that uses the facility (other than as an argument passed when the +facility is invoked), then you may convey a copy of the modified +version: + + a) under this License, provided that you make a good faith effort + to ensure that, in the event an Application does not supply the + function or data, the facility still operates, and performs + whatever part of its purpose remains meaningful, or + + b) under the GNU GPL, with none of the additional permissions of + this License applicable to that copy. + +3. Object Code Incorporating Material from Library Header Files. + + The object code form of an Application may incorporate material from +a header file that is part of the Library. You may convey such object +code under terms of your choice, provided that, if the incorporated +material is not limited to numerical parameters, data structure +layouts and accessors, or small macros, inline functions and templates +(ten or fewer lines in length), you do both of the following: + + a) Give prominent notice with each copy of the object code that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the object code with a copy of the GNU GPL and this + license document. + +4. Combined Works. + + You may convey a Combined Work under terms of your choice that, taken +together, effectively do not restrict modification of the portions of +the Library contained in the Combined Work and reverse engineering for +debugging such modifications, if you also do each of the following: + + a) Give prominent notice with each copy of the Combined Work that + the Library is used in it and that the Library and its use are + covered by this License. + + b) Accompany the Combined Work with a copy of the GNU GPL and this + license document. + + c) For a Combined Work that displays copyright notices during + execution, include the copyright notice for the Library among + these notices, as well as a reference directing the user to the + copies of the GNU GPL and this license document. + + d) Do one of the following: + + 0) Convey the Minimal Corresponding Source under the terms of + this License, and the Corresponding Application Code in a form + suitable for, and under terms that permit, the user to + recombine or relink the Application with a modified version of + the Linked Version to produce a modified Combined Work, in the + manner specified by section 6 of the GNU GPL for conveying + Corresponding Source. + + 1) Use a suitable shared library mechanism for linking with + the Library. A suitable mechanism is one that (a) uses at run + time a copy of the Library already present on the user's + computer system, and (b) will operate properly with a modified + version of the Library that is interface-compatible with the + Linked Version. + + e) Provide Installation Information, but only if you would + otherwise be required to provide such information under section 6 + of the GNU GPL, and only to the extent that such information is + necessary to install and execute a modified version of the + Combined Work produced by recombining or relinking the Application + with a modified version of the Linked Version. (If you use option + 4d0, the Installation Information must accompany the Minimal + Corresponding Source and Corresponding Application Code. If you + use option 4d1, you must provide the Installation Information in + the manner specified by section 6 of the GNU GPL for conveying + Corresponding Source.) + +5. Combined Libraries. + + You may place library facilities that are a work based on the Library +side by side in a single library together with other library +facilities that are not Applications and are not covered by this +License, and convey such a combined library under terms of your +choice, if you do both of the following: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities, conveyed under the terms of this License. + + b) Give prominent notice with the combined library that part of + it is a work based on the Library, and explaining where to find + the accompanying uncombined form of the same work. + +6. Revised Versions of the GNU Lesser General Public License. + + The Free Software Foundation may publish revised and/or new versions +of the GNU Lesser General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +as you received it specifies that a certain numbered version of the +GNU Lesser General Public License “or any later version” applies to +it, you have the option of following the terms and conditions either +of that published version or of any later version published by the +Free Software Foundation. If the Library as you received it does not +specify a version number of the GNU Lesser General Public License, +you may choose any version of the GNU Lesser General Public License +ever published by the Free Software Foundation. + +If the Library as you received it specifies that a proxy can decide +whether future versions of the GNU Lesser General Public License shall +apply, that proxy's public statement of acceptance of any version is +permanent authorization for you to choose that version for the Library. + +``` +------------------------------------------------------------------------------- + + +PCRE (10.36) - BSD-3-Clause +=============================================================================== +``` +PCRE2 LICENCE +------------- + +PCRE2 is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Releases 10.00 and above of PCRE2 are distributed under the terms of the "BSD" +licence, as specified below, with one exemption for certain binary +redistributions. The documentation for PCRE2, supplied in the "doc" directory, +is distributed under the same terms as the software itself. The data in the +testdata directory is not copyrighted and is in the public domain. + +The basic library functions are written in C and are freestanding. Also +included in the distribution is a just-in-time compiler that can be used to +optimize pattern matching. This is an optional feature that can be omitted when +the library is built. + + +THE BASIC LIBRARY FUNCTIONS +--------------------------- + +Written by: Philip Hazel +Email local part: Philip.Hazel +Email domain: gmail.com + +University of Cambridge Computing Service, +Cambridge, England. + +Copyright (c) 1997-2020 University of Cambridge +All rights reserved. + + +PCRE2 JUST-IN-TIME COMPILATION SUPPORT +-------------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Email domain: freemail.hu + +Copyright(c) 2010-2020 Zoltan Herczeg +All rights reserved. + + +STACK-LESS JUST-IN-TIME COMPILER +-------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Email domain: freemail.hu + +Copyright(c) 2009-2020 Zoltan Herczeg +All rights reserved. + + +THE "BSD" LICENCE +----------------- + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notices, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notices, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the names of any + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +EXEMPTION FOR BINARY LIBRARY-LIKE PACKAGES +------------------------------------------ + +The second condition in the BSD licence (covering binary redistributions) does +not apply all the way down a chain of software. If binary package A includes +PCRE2, it must respect the condition, but if package B is software that +includes package A, the condition is not imposed on package B unless it uses +PCRE2 independently. + +End + +``` +------------------------------------------------------------------------------- + + +Double-Conversion (3.1.5) - BSD-3-Clause +=============================================================================== +``` + +Copyright 2006-2011, the V8 project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +``` +------------------------------------------------------------------------------- + + +Freetype (2.10.4) - FTL +=============================================================================== +``` + + + The FreeType Project LICENSE + ---------------------------- + + 2006-Jan-27 + + Copyright 1996-2002, 2006 by + David Turner, Robert Wilhelm, and Werner Lemberg + + + +Introduction +============ + + The FreeType Project is distributed in several archive packages; + some of them may contain, in addition to the FreeType font engine, + various tools and contributions which rely on, or relate to, the + FreeType Project. + + This license applies to all files found in such packages, and + which do not fall under their own explicit license. The license + affects thus the FreeType font engine, the test programs, + documentation and makefiles, at the very least. + + This license was inspired by the BSD, Artistic, and IJG + (Independent JPEG Group) licenses, which all encourage inclusion + and use of free software in commercial and freeware products + alike. As a consequence, its main points are that: + + o We don't promise that this software works. However, we will be + interested in any kind of bug reports. (`as is' distribution) + + o You can use this software for whatever you want, in parts or + full form, without having to pay us. (`royalty-free' usage) + + o You may not pretend that you wrote this software. If you use + it, or only parts of it, in a program, you must acknowledge + somewhere in your documentation that you have used the + FreeType code. (`credits') + + We specifically permit and encourage the inclusion of this + software, with or without modifications, in commercial products. + We disclaim all warranties covering The FreeType Project and + assume no liability related to The FreeType Project. + + + Finally, many people asked us for a preferred form for a + credit/disclaimer to use in compliance with this license. We thus + encourage you to use the following text: + + """ + Portions of this software are copyright © The FreeType + Project (www.freetype.org). All rights reserved. + """ + + Please replace with the value from the FreeType version you + actually use. + + +Legal Terms +=========== + +0. Definitions +-------------- + + Throughout this license, the terms `package', `FreeType Project', + and `FreeType archive' refer to the set of files originally + distributed by the authors (David Turner, Robert Wilhelm, and + Werner Lemberg) as the `FreeType Project', be they named as alpha, + beta or final release. + + `You' refers to the licensee, or person using the project, where + `using' is a generic term including compiling the project's source + code as well as linking it to form a `program' or `executable'. + This program is referred to as `a program using the FreeType + engine'. + + This license applies to all files distributed in the original + FreeType Project, including all source code, binaries and + documentation, unless otherwise stated in the file in its + original, unmodified form as distributed in the original archive. + If you are unsure whether or not a particular file is covered by + this license, you must contact us to verify this. + + The FreeType Project is copyright (C) 1996-2000 by David Turner, + Robert Wilhelm, and Werner Lemberg. All rights reserved except as + specified below. + +1. No Warranty +-------------- + + THE FREETYPE PROJECT IS PROVIDED `AS IS' WITHOUT WARRANTY OF ANY + KIND, EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + PURPOSE. IN NO EVENT WILL ANY OF THE AUTHORS OR COPYRIGHT HOLDERS + BE LIABLE FOR ANY DAMAGES CAUSED BY THE USE OR THE INABILITY TO + USE, OF THE FREETYPE PROJECT. + +2. Redistribution +----------------- + + This license grants a worldwide, royalty-free, perpetual and + irrevocable right and license to use, execute, perform, compile, + display, copy, create derivative works of, distribute and + sublicense the FreeType Project (in both source and object code + forms) and derivative works thereof for any purpose; and to + authorize others to exercise some or all of the rights granted + herein, subject to the following conditions: + + o Redistribution of source code must retain this license file + (`FTL.TXT') unaltered; any additions, deletions or changes to + the original files must be clearly indicated in accompanying + documentation. The copyright notices of the unaltered, + original files must be preserved in all copies of source + files. + + o Redistribution in binary form must provide a disclaimer that + states that the software is based in part of the work of the + FreeType Team, in the distribution documentation. We also + encourage you to put an URL to the FreeType web page in your + documentation, though this isn't mandatory. + + These conditions apply to any software derived from or based on + the FreeType Project, not just the unmodified files. If you use + our work, you must acknowledge us. However, no fee need be paid + to us. + +3. Advertising +-------------- + + Neither the FreeType authors and contributors nor you shall use + the name of the other for commercial, advertising, or promotional + purposes without specific prior written permission. + + We suggest, but do not require, that you use one or more of the + following phrases to refer to this software in your documentation + or advertising materials: `FreeType Project', `FreeType Engine', + `FreeType library', or `FreeType Distribution'. + + As you have not signed this license, you are not required to + accept it. However, as the FreeType Project is copyrighted + material, only this license, or another one contracted with the + authors, grants you the right to use, distribute, and modify it. + Therefore, by using, distributing, or modifying the FreeType + Project, you indicate that you understand and accept all the terms + of this license. + +4. Contacts +----------- + + There are two mailing lists related to FreeType: + + o freetype@nongnu.org + + Discusses general use and applications of FreeType, as well as + future and wanted additions to the library and distribution. + If you are looking for support, start in this list if you + haven't found anything to help you in the documentation. + + o freetype-devel@nongnu.org + + Discusses bugs, as well as engine internals, design issues, + specific licenses, porting, etc. + + Our home page can be found at + + https://www.freetype.org + + +--- end of FTL.TXT --- +``` +------------------------------------------------------------------------------- + + +libpq (13.2) - Postgres SQL +=============================================================================== +``` + +PostgreSQL Database Management System +(formerly known as Postgres, then as Postgres95) + +Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this +paragraph and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS +DOCUMENTATION, EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS TO +PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +``` +------------------------------------------------------------------------------- + + +zstd (1.5.0) - BSD-3-Clause +=============================================================================== +``` +BSD License + +For Zstandard software + +Copyright (c) 2016-present, Facebook, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + + * Neither the name Facebook nor the names of its contributors may be used to + endorse or promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +``` +------------------------------------------------------------------------------- + + +brotli (1.0.9) - MIT +=============================================================================== +``` +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +``` +------------------------------------------------------------------------------- + + +Font - Now (OFL 1.1) +=============================================================================== +``` +Copyright (c) 2015, Alfredo Marco Pradil (), with Reserved Font Name Now. + +OFL FAQ - Frequently Asked Questions about the SIL Open Font License (OFL) +Version 1.1-update4 - Sept 2014 +(See http://scripts.sil.org/OFL for updates) + + +CONTENTS OF THIS FAQ +1 USING AND DISTRIBUTING FONTS LICENSED UNDER THE OFL +2 USING OFL FONTS FOR WEB PAGES AND ONLINE WEB FONT SERVICES +3 MODIFYING OFL-LICENSED FONTS +4 LICENSING YOUR ORIGINAL FONTS UNDER THE OFL +5 CHOOSING RESERVED FONT NAMES +6 ABOUT THE FONTLOG +7 MAKING CONTRIBUTIONS TO OFL PROJECTS +8 ABOUT THE LICENSE ITSELF +9 ABOUT SIL INTERNATIONAL +APPENDIX A - FONTLOG EXAMPLE + +1 USING AND DISTRIBUTING FONTS LICENSED UNDER THE OFL + +1.1 Can I use the fonts for a book or other print publication, to create logos or other graphics or even to manufacture objects based on their outlines? +Yes. You are very welcome to do so. Authors of fonts released under the OFL allow you to use their font software as such for any kind of design work. No additional license or permission is required, unlike with some other licenses. Some examples of these uses are: logos, posters, business cards, stationery, video titling, signage, t-shirts, personalised fabric, 3D-printed/laser-cut shapes, sculptures, rubber stamps, cookie cutters and lead type. + +1.1.1 Does that restrict the license or distribution of that artwork? +No. You remain the author and copyright holder of that newly derived graphic or object. You are simply using an open font in the design process. It is only when you redistribute, bundle or modify the font itself that other conditions of the license have to be respected (see below for more details). + +1.1.2 Is any kind of acknowledgement required? +No. Font authors may appreciate being mentioned in your artwork's acknowledgements alongside the name of the font, possibly with a link to their website, but that is not required. + +1.2 Can the fonts be included with Free/Libre and Open Source Software collections such as GNU/Linux and BSD distributions and repositories? +Yes! Fonts licensed under the OFL can be freely included alongside other software under FLOSS (Free/Libre and Open Source Software) licenses. Since fonts are typically aggregated with, not merged into, existing software, there is little need to be concerned about incompatibility with existing software licenses. You may also repackage the fonts and the accompanying components in a .rpm or .deb package (or other similar package formats or installers) and include them in distribution CD/DVDs and online repositories. (Also see section 5.9 about rebuilding from source.) + +1.3 I want to distribute the fonts with my program. Does this mean my program also has to be Free/Libre and Open Source Software? +No. Only the portions based on the Font Software are required to be released under the OFL. The intent of the license is to allow aggregation or bundling with software under restricted licensing as well. + +1.4 Can I sell a software package that includes these fonts? +Yes, you can do this with both the Original Version and a Modified Version of the fonts. Examples of bundling made possible by the OFL would include: word processors, design and publishing applications, training and educational software, games and entertainment software, mobile device applications, etc. + +1.5 Can I include the fonts on a CD of freeware or commercial fonts? +Yes, as long some other font or software is also on the disk, so the OFL font is not sold by itself. + +1.6 Why won't the OFL let me sell the fonts alone? +The intent is to keep people from making money by simply redistributing the fonts. The only people who ought to profit directly from the fonts should be the original authors, and those authors have kindly given up potential direct income to distribute their fonts under the OFL. Please honour and respect their contribution! + +1.7 What about sharing OFL fonts with friends on a CD, DVD or USB stick? +You are very welcome to share open fonts with friends, family and colleagues through removable media. Just remember to include the full font package, including any copyright notices and licensing information as available in OFL.txt. In the case where you sell the font, it has to come bundled with software. + +1.8 Can I host the fonts on a web site for others to use? +Yes, as long as you make the full font package available. In most cases it may be best to point users to the main site that distributes the Original Version so they always get the most recent stable and complete version. See also discussion of web fonts in Section 2. + +1.9 Can I host the fonts on a server for use over our internal network? +Yes. If the fonts are transferred from the server to the client computer by means that allow them to be used even if the computer is no longer attached to the network, the full package (copyright notices, licensing information, etc.) should be included. + +1.10 Does the full OFL license text always need to accompany the font? +The only situation in which an OFL font can be distributed without the text of the OFL (either in a separate file or in font metadata), is when a font is embedded in a document or bundled within a program. In the case of metadata included within a font, it is legally sufficient to include only a link to the text of the OFL on http://scripts.sil.org/OFL, but we strongly recommend against this. Most modern font formats include metadata fields that will accept the full OFL text, and full inclusion increases the likelihood that users will understand and properly apply the license. + +1.11 What do you mean by 'embedding'? How does that differ from other means of distribution? +By 'embedding' we mean inclusion of the font in a document or file in a way that makes extraction (and redistribution) difficult or clearly discouraged. In many cases the names of embedded fonts might also not be obvious to those reading the document, the font data format might be altered, and only a subset of the font - only the glyphs required for the text - might be included. Any other means of delivering a font to another person is considered 'distribution', and needs to be accompanied by any copyright notices and licensing information available in OFL.txt. + +1.12 So can I embed OFL fonts in my document? +Yes, either in full or a subset. The restrictions regarding font modification and redistribution do not apply, as the font is not intended for use outside the document. + +1.13 Does embedding alter the license of the document itself? +No. Referencing or embedding an OFL font in any document does not change the license of the document itself. The requirement for fonts to remain under the OFL does not apply to any document created using the fonts and their derivatives. Similarly, creating any kind of graphic using a font under OFL does not make the resulting artwork subject to the OFL. + +1.14 If OFL fonts are extracted from a document in which they are embedded (such as a PDF file), what can be done with them? Is this a risk to author(s)? +The few utilities that can extract fonts embedded in a PDF will typically output limited amounts of outlines - not a complete font. To create a working font from this method is much more difficult and time consuming than finding the source of the original OFL font. So there is little chance that an OFL font would be extracted and redistributed inappropriately through this method. Even so, copyright laws address any misrepresentation of authorship. All Font Software released under the OFL and marked as such by the author(s) is intended to remain under this license regardless of the distribution method, and cannot be redistributed under any other license. We strongly discourage any font extraction - we recommend directly using the font sources instead - but if you extract font outlines from a document, please be considerate: respect the work of the author(s) and the licensing model. + +1.15 What about distributing fonts with a document? Within a compressed folder structure? Is it distribution, bundling or embedding? +Certain document formats may allow the inclusion of an unmodified font within their file structure which may consist of a compressed folder containing the various resources forming the document (such as pictures and thumbnails). Including fonts within such a structure is understood as being different from embedding but rather similar to bundling (or mere aggregation) which the license explicitly allows. In this case the font is conveyed unchanged whereas embedding a font usually transforms it from the original format. The OFL does not allow anyone to extract the font from such a structure to then redistribute it under another license. The explicit permission to redistribute and embed does not cancel the requirement for the Font Software to remain under the license chosen by its author(s). Even if the font travels inside the document as one of its assets, it should not lose its authorship information and licensing. + +1.16 What about ebooks shipping with open fonts? +The requirements differ depending on whether the fonts are linked, embedded or distributed (bundled or aggregated). Some ebook formats use web technologies to do font linking via @font-face, others are designed for font embedding, some use fonts distributed with the document or reading software, and a few rely solely on the fonts already present on the target system. The license requirements depend on the type of inclusion as discussed in 1.15. + +1.17 Can Font Software released under the OFL be subject to URL-based access restrictions methods or DRM (Digital Rights Management) mechanisms? +Yes, but these issues are out-of-scope for the OFL. The license itself neither encourages their use nor prohibits them since such mechanisms are not implemented in the components of the Font Software but through external software. Such restrictions are put in place for many different purposes corresponding to various usage scenarios. One common example is to limit potentially dangerous cross-site scripting attacks. However, in the spirit of libre/open fonts and unrestricted writing systems, we strongly encourage open sharing and reuse of OFL fonts, and the establishment of an environment where such restrictions are unnecessary. Note that whether you wish to use such mechanisms or you prefer not to, you must still abide by the rules set forth by the OFL when using fonts released by their authors under this license. Derivative fonts must be licensed under the OFL, even if they are part of a service for which you charge fees and/or for which access to source code is restricted. You may not sell the fonts on their own - they must be part of a larger software package, bundle or subscription plan. For example, even if the OFL font is distributed in a software package or via an online service using a DRM mechanism, the user would still have the right to extract that font, use, study, modify and redistribute it under the OFL. + +1.18 I've come across a font released under the OFL. How can I easily get more information about the Original Version? How can I know where it stands compared to the Original Version or other Modified Versions? +Consult the copyright statement(s) in the license for ways to contact the original authors. Consult the FONTLOG (see section 6 for more details and examples) for information on how the font differs from the Original Version, and get in touch with the various contributors via the information in the acknowledgement section. Please consider using the Original Versions of the fonts whenever possible. + +1.19 What do you mean in condition 4 of the OFL's permissions and conditions? Can you provide examples of abusive promotion / endorsement / advertisement vs. normal acknowledgement? +The intent is that the goodwill and reputation of the author(s) should not be used in a way that makes it sound like the original author(s) endorse or approve of a specific Modified Version or software bundle. For example, it would not be right to advertise a word processor by naming the author(s) in a listing of software features, or to promote a Modified Version on a web site by saying "designed by ...". However, it would be appropriate to acknowledge the author(s) if your software package has a list of people who deserve thanks. We realize that this can seem to be a grey area, but the standard used to judge an acknowledgement is that if the acknowledgement benefits the author(s) it is allowed, but if it primarily benefits other parties, or could reflect poorly on the author(s), then it is not. + +1.20 I'm writing a small app for mobile platforms, do I need to include the whole package? +If you bundle a font under the OFL with your mobile app you must comply with the terms of the license. At a minimum you must include the copyright statement, the license notice and the license text. A mention of this information in your About box or Changelog, with a link to where the font package is from, is good practice, and the extra space needed to carry these items is very small. You do not, however, need to include the full contents of the font package - only the fonts you use and the copyright and license that apply to them. For example, if you only use the regular weight in your app, you do not need to include the italic and bold versions. + +1.21 What about including OFL fonts by default in my firmware or dedicated operating system? +Many such systems are restricted and turned into appliances so that users cannot study or modify them. Using open fonts to increase quality and language coverage is a great idea, but you need to be aware that if there is a way for users to extract fonts you cannot legally prevent them from doing that. The fonts themselves, including any changes you make to them, must be distributed under the OFL even if your firmware has a more restrictive license. If you do transform the fonts and change their formats when you include them in your firmware you must respect any names reserved by the font authors via the RFN mechanism and pick your own font name. Alternatively if you directly add a font under the OFL to the font folder of your firmware without modifying or optimizing it you are simply bundling the font like with any other software collection, and do not need to make any further changes. + +1.22 Can I make and publish CMS themes or templates that use OFL fonts? Can I include the fonts themselves in the themes or templates? Can I sell the whole package? +Yes, you are very welcome to integrate open fonts into themes and templates for your preferred CMS and make them more widely available. Remember that you can only sell the fonts and your CMS add-on as part of a software bundle. (See 1.4 for details and examples about selling bundles). + +1.23 Can OFL fonts be included in services that deliver fonts to the desktop from remote repositories? Even if they contain both OFL and non-OFL fonts? +Yes. Some foundries have set up services to deliver fonts to subscribers directly to desktops from their online repositories; similarly, plugins are available to preview and use fonts directly in your design tool or publishing suite. These services may mix open and restricted fonts in the same channel, however they should make a clear distinction between them to users. These services should also not hinder users (such as through DRM or obfuscation mechanisms) from extracting and using the OFL fonts in other environments, or continuing to use OFL fonts after subscription terms have ended, as those uses are specifically allowed by the OFL. + +1.24 Can services that provide or distribute OFL fonts restrict my use of them? +No. The terms of use of such services cannot replace or restrict the terms of the OFL, as that would be the same as distributing the fonts under a different license, which is not allowed. You are still entitled to use, modify and redistribute them as the original authors have intended outside of the sole control of that particular distribution channel. Note, however, that the fonts provided by these services may differ from the Original Versions. + + +2 USING OFL FONTS FOR WEBPAGES AND ONLINE WEB FONT SERVICES + +NOTE: This section often refers to a separate paper on 'Web Fonts & RFNs'. This is available at http://scripts.sil.org/OFL_web_fonts_and_RFNs + +2.1 Can I make webpages using these fonts? +Yes! Go ahead! Using CSS (Cascading Style Sheets) is recommended. Your three best options are: +- referring directly in your stylesheet to open fonts which may be available on the user's system +- providing links to download the full package of the font - either from your own website or from elsewhere - so users can install it themselves +- using @font-face to distribute the font directly to browsers. This is recommended and explicitly allowed by the licensing model because it is distribution. The font file itself is distributed with other components of the webpage. It is not embedded in the webpage but referenced through a web address which will cause the browser to retrieve and use the corresponding font to render the webpage (see 1.11 and 1.15 for details related to embedding fonts into documents). As you take advantage of the @font-face cross-platform standard, be aware that web fonts are often tuned for a web environment and not intended for installation and use outside a browser. The reasons in favour of using web fonts are to allow design of dynamic text elements instead of static graphics, to make it easier for content to be localized and translated, indexed and searched, and all this with cross-platform open standards without depending on restricted extensions or plugins. You should check the CSS cascade (the order in which fonts are being called or delivered to your users) when testing. + +2.2 Can I make and use WOFF (Web Open Font Format) versions of OFL fonts? +Yes, but you need to be careful. A change in font format normally is considered modification, and Reserved Font Names (RFNs) cannot be used. Because of the design of the WOFF format, however, it is possible to create a WOFF version that is not considered modification, and so would not require a name change. You are allowed to create, use and distribute a WOFF version of an OFL font without changing the font name, but only if: + +- the original font data remains unchanged except for WOFF compression, and +- WOFF-specific metadata is either omitted altogether or present and includes, unaltered, the contents of all equivalent metadata in the original font. + +If the original font data or metadata is changed, or the WOFF-specific metadata is incomplete, the font must be considered a Modified Version, the OFL restrictions would apply and the name of the font must be changed: any RFNs cannot be used and copyright notices and licensing information must be included and cannot be deleted or modified. You must come up with a unique name - we recommend one corresponding to your domain or your particular web application. Be aware that only the original author(s) can use RFNs. This is to prevent collisions between a derivative tuned to your audience and the original upstream version and so to reduce confusion. + +Please note that most WOFF conversion tools and online services do not meet the two requirements listed above, and so their output must be considered a Modified Version. So be very careful and check to be sure that the tool or service you're using is compressing unchanged data and completely and accurately reflecting the original font metadata. + +2.3 What about other web font formats such as EOT/EOTLite/CWT/etc.? +In most cases these formats alter the original font data more than WOFF, and do not completely support appropriate metadata, so their use must be considered modification and RFNs may not be used. However, there may be certain formats or usage scenarios that may allow the use of RFNs. See http://scripts.sil.org/OFL_web_fonts_and_RFNs + +2.4 Can I make OFL fonts available through web font online services? +Yes, you are welcome to include OFL fonts in online web font services as long as you properly meet all the conditions of the license. The origin and open status of the font should be clear among the other fonts you are hosting. Authorship, copyright notices and license information must be sufficiently visible to your users or subscribers so they know where the font comes from and the rights granted by the author(s). Make sure the font file contains the needed copyright notice(s) and licensing information in its metadata. Please double-check the accuracy of every field to prevent contradictory information. Other font formats, including EOT/EOTLite/CWT and superior alternatives like WOFF, already provide fields for this information. Remember that if you modify the font within your library or convert it to another format for any reason the OFL restrictions apply and you need to change the names accordingly. Please respect the author's wishes as expressed in the OFL and do not misrepresent original designers and their work. Don't lump quality open fonts together with dubious freeware or public domain fonts. Consider how you can best work with the original designers and foundries, support their efforts and generate goodwill that will benefit your service. (See 1.17 for details related to URL-based access restrictions methods or DRM mechanisms). + +2.5 Some web font formats and services provide ways of "optimizing" the font for a particular website or web application; is that allowed? +Yes, it is permitted, but remember that these optimized versions are Modified Versions and so must follow OFL requirements like appropriate renaming. Also you need to bear in mind the other important parameters beyond compression, speed and responsiveness: you need to consider the audience of your particular website or web application, as choosing some optimization parameters may turn out to be less than ideal for them. Subsetting by removing certain glyphs or features may seriously limit functionality of the font in various languages that your users expect. It may also introduce degradation of quality in the rendering or specific bugs on the various target platforms compared to the original font from upstream. In other words, remember that one person's optimized font may be another person's missing feature. Various advanced typographic features (OpenType, Graphite or AAT) are also available through CSS and may provide the desired effects without the need to modify the font. + +2.6 Is subsetting a web font considered modification? +Yes. Removing any parts of the font when delivering a web font to a browser, including unused glyphs and smart font code, is considered modification. This is permitted by the OFL but would not normally allow the use of RFNs. Some newer subsetting technologies may be able to subset in a way that allows users to effectively have access to the complete font, including smart font behaviour. See 2.8 and http://scripts.sil.org/OFL_web_fonts_and_RFNs + +2.7 Are there any situations in which a modified web font could use RFNs? +Yes. If a web font is optimized only in ways that preserve Functional Equivalence (see 2.8), then it may use RFNs, as it reasonably represents the Original Version and respects the intentions of the author(s) and the main purposes of the RFN mechanism (avoids collisions, protects authors, minimizes support, encourages derivatives). However this is technically very difficult and often impractical, so a much better scenario is for the web font service or provider to sign a separate agreement with the author(s) that allows the use of RFNs for Modified Versions. + +2.8 How do you know if an optimization to a web font preserves Functional Equivalence? +Functional Equivalence is described in full in the 'Web fonts and RFNs' paper at http://scripts.sil.org/OFL_web_fonts_and_RFNs, in general, an optimized font is deemed to be Functionally Equivalent (FE) to the Original Version if it: + +- Supports the same full character inventory. If a character can be properly displayed using the Original Version, then that same character, encoded correctly on a web page, will display properly. +- Provides the same smart font behavior. Any dynamic shaping behavior that works with the Original Version should work when optimized, unless the browser or environment does not support it. There does not need to be guaranteed support in the client, but there should be no forced degradation of smart font or shaping behavior, such as the removal or obfuscation of OpenType, Graphite or AAT tables. +- Presents text with no obvious degradation in visual quality. The lettershapes should be equally (or more) readable, within limits of the rendering platform. +- Preserves original author, project and license metadata. At a minimum, this should include: Copyright and authorship; The license as stated in the Original Version, whether that is the full text of the OFL or a link to the web version; Any RFN declarations; Information already present in the font or documentation that points back to the Original Version, such as a link to the project or the author's website. + +If an optimized font meets these requirements, and so is considered to be FE, then it's very likely that the original author would feel that the optimized font is a good and reasonable equivalent. If it falls short of any of these requirements, the optimized font does not reasonably represent the Original Version, and so should be considered to be a Modified Version. Like other Modified Versions, it would not be allowed to use any RFNs and you simply need to pick your own font name. + +2.9 Isn't use of web fonts another form of embedding? +No. Unlike embedded fonts in a PDF, web fonts are not an integrated part of the document itself. They are not specific to a single document and are often applied to thousands of documents around the world. The font data is not stored alongside the document data and often originates from a different location. The ease by which the web fonts used by a document may be identified and downloaded for desktop use demonstrates that they are philosophically and technically separate from the web pages that specify them. See http://scripts.sil.org/OFL_web_fonts_and_RFNs + +2.10 So would it be better to not use RFNs at all if you want your font to be distributed by a web fonts service? +No. Although the OFL does not require authors to use RFNs, the RFN mechanism is an important part of the OFL model and completely compatible with web font services. If that web font service modifies the fonts, then the best solution is to sign a separate agreement for the use of any RFNs. It is perfectly valid for an author to not declare any RFNs, but before they do so they need to fully understand the benefits they are giving up, and the overall negative effect of allowing many different versions bearing the same name to be widely distributed. As a result, we don't generally recommend it. + +2.11 What should an agreement for the use of RFNs say? Are there any examples? +There is no prescribed format for this agreement, as legal systems vary, and no recommended examples. Authors may wish to add specific clauses to further restrict use, require author review of Modified Versions, establish user support mechanisms or provide terms for ending the agreement. Such agreements are usually not public, and apply only to the main parties. However, it would be very beneficial for web font services to clearly state when they have established such agreements, so that the public understands clearly that their service is operating appropriately. + +See the separate paper on 'Web Fonts & RFNs' for in-depth discussion of issues related to the use of RFNs for web fonts. This is available at http://scripts.sil.org/OFL_web_fonts_and_RFNs + + +3 MODIFYING OFL-LICENSED FONTS + +3.1 Can I change the fonts? Are there any limitations to what things I can and cannot change? +You are allowed to change anything, as long as such changes do not violate the terms of the license. In other words, you are not allowed to remove the copyright statement(s) from the font, but you could put additional information into it that covers your contribution. See the placeholders in the OFL header template for recommendations on where to add your own statements. (Remember that, when authors have reserved names via the RFN mechanism, you need to change the internal names of the font to your own font name when making your modified version even if it is just a small change.) + +3.2 I have a font that needs a few extra glyphs - can I take them from an OFL licensed font and copy them into mine? +Yes, but if you distribute that font to others it must be under the OFL, and include the information mentioned in condition 2 of the license. + +3.3 Can I charge people for my additional work? In other words, if I add a bunch of special glyphs or OpenType/Graphite/AAT code, can I sell the enhanced font? +Not by itself. Derivative fonts must be released under the OFL and cannot be sold by themselves. It is permitted, however, to include them in a larger software package (such as text editors, office suites or operating systems), even if the larger package is sold. In that case, you are strongly encouraged, but not required, to also make that derived font easily and freely available outside of the larger package. + +3.4 Can I pay someone to enhance the fonts for my use and distribution? +Yes. This is a good way to fund the further development of the fonts. Keep in mind, however, that if the font is distributed to others it must be under the OFL. You won't be able to recover your investment by exclusively selling the font, but you will be making a valuable contribution to the community. Please remember how you have benefited from the contributions of others. + +3.5 I need to make substantial revisions to the font to make it work with my program. It will be a lot of work, and a big investment, and I want to be sure that it can only be distributed with my program. Can I restrict its use? +No. If you redistribute a Modified Version of the font it must be under the OFL. You may not restrict it in any way beyond what the OFL permits and requires. This is intended to ensure that all released improvements to the fonts become available to everyone. But you will likely get an edge over competitors by being the first to distribute a bundle with the enhancements. Again, please remember how you have benefited from the contributions of others. + +3.6 Do I have to make any derivative fonts (including extended source files, build scripts, documentation, etc.) publicly available? +No, but please consider sharing your improvements with others. You may find that you receive in return more than what you gave. + +3.7 If a trademark is claimed in the OFL font, does that trademark need to remain in modified fonts? +Yes. Any trademark notices must remain in any derivative fonts to respect trademark laws, but you may add any additional trademarks you claim, officially registered or not. For example if an OFL font called "Foo" contains a notice that "Foo is a trademark of Acme", then if you rename the font to "Bar" when creating a Modified Version, the new trademark notice could say "Foo is a trademark of Acme Inc. - Bar is a trademark of Roadrunner Technologies Ltd.". Trademarks work alongside the OFL and are not subject to the terms of the licensing agreement. The OFL does not grant any rights under trademark law. Bear in mind that trademark law varies from country to country and that there are no international trademark conventions as there are for copyright. You may need to significantly invest in registering and defending a trademark for it to remain valid in the countries you are interested in. This may be costly for an individual independent designer. + +3.8 If I commit changes to a font (or publish a branch in a DVCS) as part of a public open source software project, do I have to change the internal font names? +Only if there are declared RFNs. Making a public commit or publishing a public branch is effectively redistributing your modifications, so any change to the font will require that you do not use the RFNs. Even if there are no RFNs, it may be useful to change the name or add a suffix indicating that a particular version of the font is still in development and not released yet. This will clearly indicate to users and fellow designers that this particular font is not ready for release yet. See section 5 for more details. + + +4 LICENSING YOUR ORIGINAL FONTS UNDER THE OFL + +4.1 Can I use the SIL OFL for my own fonts? +Yes! We heartily encourage everyone to use the OFL to distribute their own original fonts. It is a carefully constructed license that allows great freedom along with enough artistic integrity protection for the work of the authors as well as clear rules for other contributors and those who redistribute the fonts. The licensing model is used successfully by various organisations, both for-profit and not-for-profit, to release fonts of varying levels of scope and complexity. + +4.2 What do I have to do to apply the OFL to my font? +If you want to release your fonts under the OFL, we recommend you do the following: + +4.2.1 Put your copyright and Reserved Font Names information at the beginning of the main OFL.txt file in place of the dedicated placeholders (marked with the <> characters). Include this file in your release package. + +4.2.2 Put your copyright and the OFL text with your chosen Reserved Font Name(s) into your font files (the copyright and license fields). A link to the OFL text on the OFL web site is an acceptable (but not recommended) alternative. Also add this information to any other components (build scripts, glyph databases, documentation, test files, etc). Accurate metadata in your font files is beneficial to you as an increasing number of applications are exposing this information to the user. For example, clickable links can bring users back to your website and let them know about other work you have done or services you provide. Depending on the format of your fonts and sources, you can use template human-readable headers or machine-readable metadata. You should also double-check that there is no conflicting metadata in the font itself contradicting the license, such as the fstype bits in the os2 table or fields in the name table. + +4.2.3 Write an initial FONTLOG.txt for your font and include it in the release package (see Section 6 and Appendix A for details including a template). + +4.2.4 Include the relevant practical documentation on the license by adding the current OFL-FAQ.txt file in your package. + +4.2.5 If you wish you can use the OFL graphics (http://scripts.sil.org/OFL_logo) on your website. + +4.3 Will you make my font OFL for me? +We won't do the work for you. We can, however, try to answer your questions, unfortunately we do not have the resources to review and check your font packages for correct use of the OFL. We recommend you turn to designers, foundries or consulting companies with experience in doing open font design to provide this service to you. + +4.4 Will you distribute my OFL font for me? +No, although if the font is of sufficient quality and general interest we may include a link to it on our partial list of OFL fonts on the OFL web site. You may wish to consider other open font catalogs or hosting services, such as the Unifont Font Guide (http://unifont.org/fontguide), The League of Movable Type (http://theleagueofmovabletype.com) or the Open Font Library (http://openfontlibrary.org/), which despite the name has no direct relationship to the OFL or SIL. We do not endorse any particular catalog or hosting service - it is your responsibility to determine if the service is right for you and if it treats authors with fairness. + +4.5 Why should I use the OFL for my fonts? +- to meet needs for fonts that can be modified to support lesser-known languages +- to provide a legal and clear way for people to respect your work but still use it (and reduce piracy) +- to involve others in your font project +- to enable your fonts to be expanded with new weights and improved writing system/language support +- to allow more technical font developers to add features to your design (such as OpenType, Graphite or AAT support) +- to renew the life of an old font lying on your hard drive with no business model +- to allow your font to be included in Libre Software operating systems like Ubuntu +- to give your font world status and wide, unrestricted distribution +- to educate students about quality typeface and font design +- to expand your test base and get more useful feedback +- to extend your reach to new markets when users see your metadata and go to your website +- to get your font more easily into one of the web font online services +- to attract attention for your commercial fonts +- to make money through web font services +- to make money by bundling fonts with applications +- to make money adjusting and extending existing open fonts +- to get a better chance that foundations/NGOs/charities/companies who commission fonts will pick you +- to be part of a sharing design and development community +- to give back and contribute to a growing body of font sources + + +5 CHOOSING RESERVED FONT NAMES + +5.1 What are Reserved Font Names? +These are font names, or portions of font names, that the author has chosen to reserve for use only with the Original Version of the font, or for Modified Version(s) created by the original author. + +5.2 Why can't I use the Reserved Font Names in my derivative font names? I'd like people to know where the design came from. +The best way to acknowledge the source of the design is to thank the original authors and any other contributors in the files that are distributed with your revised font (although no acknowledgement is required). The FONTLOG is a natural place to do this. Reserved Font Names ensure that the only fonts that have the original names are the unmodified Original Versions. This allows designers to maintain artistic integrity while allowing collaboration to happen. It eliminates potential confusion and name conflicts. When choosing a name, be creative and avoid names that reuse almost all the same letters in the same order or sound like the original. It will help everyone if Original Versions and Modified Versions can easily be distinguished from one another and from other derivatives. Any substitution and matching mechanism is outside the scope of the license. + +5.3 What do you mean by "primary name as presented to the user"? Are you referring to the font menu name? +Yes, this applies to the font menu name and other mechanisms that specify a font in a document. It would be fine, however, to keep a text reference to the original fonts in the description field, in your modified source file or in documentation provided alongside your derivative as long as no one could be confused that your modified source is the original. But you cannot use the Reserved Font Names in any way to identify the font to the user (unless the Copyright Holder(s) allow(s) it through a separate agreement). Users who install derivatives (Modified Versions) on their systems should not see any of the original Reserved Font Names in their font menus, for example. Again, this is to ensure that users are not confused and do not mistake one font for another and so expect features only another derivative or the Original Version can actually offer. + +5.4 Am I not allowed to use any part of the Reserved Font Names? +You may not use individual words from the Reserved Font Names, but you would be allowed to use parts of words, as long as you do not use any word from the Reserved Font Names entirely. We do not recommend using parts of words because of potential confusion, but it is allowed. For example, if "Foobar" was a Reserved Font Name, you would be allowed to use "Foo" or "bar", although we would not recommend it. Such an unfortunate choice would confuse the users of your fonts as well as make it harder for other designers to contribute. + +5.5 So what should I, as an author, identify as Reserved Font Names? +Original authors are encouraged to name their fonts using clear, distinct names, and only declare the unique parts of the name as Reserved Font Names. For example, the author of a font called "Foobar Sans" would declare "Foobar" as a Reserved Font Name, but not "Sans", as that is a common typographical term, and may be a useful word to use in a derivative font name. Reserved Font Names should also be single words for simplicity and legibility. A font called "Flowing River" should have Reserved Font Names "Flowing" and "River", not "Flowing River". You also need to be very careful about reserving font names which are already linked to trademarks (whether registered or not) which you do not own. + +5.6 Do I, as an author, have to identify any Reserved Font Names? +No. RFNs are optional and not required, but we encourage you to use them. This is primarily to avoid confusion between your work and Modified Versions. As an author you can release a font under the OFL and not declare any Reserved Font Names. There may be situations where you find that using no RFNs and letting your font be changed and modified - including any kind of modification - without having to change the original name is desirable. However you need to be fully aware of the consequences. There will be no direct way for end-users and other designers to distinguish your Original Version from many Modified Versions that may be created. You have to trust whoever is making the changes and the optimizations to not introduce problematic changes. The RFNs you choose for your own creation have value to you as an author because they allow you to maintain artistic integrity and keep some control over the distribution channel to your end-users. For discussion of RFNs and web fonts see section 2. + +5.7 Are any names (such as the main font name) reserved by default? +No. That is a change to the license as of version 1.1. If you want any names to be Reserved Font Names, they must be specified after the copyright statement(s). + +5.8 Is there any situation in which I can use Reserved Font Names for a Modified Version? +The Copyright Holder(s) can give certain trusted parties the right to use any of the Reserved Font Names through separate written agreements. For example, even if "Foobar" is a RFN, you could write up an agreement to give company "XYZ" the right to distribute a modified version with a name that includes "Foobar". This allows for freedom without confusion. The existence of such an agreement should be made as clear as possible to downstream users and designers in the distribution package and the relevant documentation. They need to know if they are a party to the agreement or not and what they are practically allowed to do or not even if all the details of the agreement are not public. + +5.9 Do font rebuilds require a name change? Do I have to change the name of the font when my packaging workflow includes a full rebuild from source? +Yes, all rebuilds which change the font data and the smart code are Modified Versions and the requirements of the OFL apply: you need to respect what the Author(s) have chosen in terms of Reserved Font Names. However if a package (or installer) is simply a wrapper or a compressed structure around the final font - leaving them intact on the inside - then no name change is required. Please get in touch with the author(s) and copyright holder(s) to inquire about the presence of font sources beyond the final font file(s) and the recommended build path. That build path may very well be non-trivial and hard to reproduce accurately by the maintainer. If a full font build path is made available by the upstream author(s) please be aware that any regressions and changes you may introduce when doing a rebuild for packaging purposes is your own responsibility as a package maintainer since you are effectively creating a separate branch. You should make it very clear to your users that your rebuilt version is not the canonical one from upstream. + +5.10 Can I add other Reserved Font Names when making a derivative font? +Yes. List your additional Reserved Font Names after your additional copyright statement, as indicated with example placeholders at the top of the OFL.txt file. Be sure you do not remove any existing RFNs but only add your own. RFN statements should be placed next to the copyright statement of the relevant author as indicated in the OFL.txt template to make them visible to designers wishing to make their separate version. + + +6 ABOUT THE FONTLOG + +6.1 What is this FONTLOG thing exactly? +It has three purposes: 1) to provide basic information on the font to users and other designers and developers, 2) to document changes that have been made to the font or accompanying files, either by the original authors or others, and 3) to provide a place to acknowledge authors and other contributors. Please use it! + +6.2 Is the FONTLOG required? +It is not a requirement of the license, but we strongly recommend you have one. + +6.3 Am I required to update the FONTLOG when making Modified Versions? +No, but users, designers and other developers might get very frustrated with you if you don't. People need to know how derivative fonts differ from the original, and how to take advantage of the changes, or build on them. There are utilities that can help create and maintain a FONTLOG, such as the FONTLOG support in FontForge. + +6.4 What should the FONTLOG look like? +It is typically a separate text file (FONTLOG.txt), but can take other formats. It commonly includes these four sections: + +- brief header describing the FONTLOG itself and name of the font family +- Basic Font Information - description of the font family, purpose and breadth +- ChangeLog - chronological listing of changes +- Acknowledgements - list of authors and contributors with contact information + +It could also include other sections, such as: where to find documentation, how to make contributions, information on contributing organizations, source code details, and a short design guide. See Appendix A for an example FONTLOG. + + +7 MAKING CONTRIBUTIONS TO OFL PROJECTS + +7.1 Can I contribute work to OFL projects? +In many cases, yes. It is common for OFL fonts to be developed by a team of people who welcome contributions from the wider community. Contact the original authors for specific information on how to participate in their projects. + +7.2 Why should I contribute my changes back to the original authors? +It would benefit many people if you contributed back in response to what you've received. Your contributions and improvements to the fonts and other components could be a tremendous help and would encourage others to contribute as well and 'give back'. You will then benefit from other people's contributions as well. Sometimes maintaining your own separate version takes more effort than merging back with the original. Be aware that any contributions, however, must be either your own original creation or work that you own, and you may be asked to affirm that clearly when you contribute. + +7.3 I've made some very nice improvements to the font. Will you consider adopting them and putting them into future Original Versions? +Most authors would be very happy to receive such contributions. Keep in mind that it is unlikely that they would want to incorporate major changes that would require additional work on their end. Any contributions would likely need to be made for all the fonts in a family and match the overall design and style. Authors are encouraged to include a guide to the design with the fonts. It would also help to have contributions submitted as patches or clearly marked changes - the use of smart source revision control systems like subversion, mercurial, git or bzr is a good idea. Please follow the recommendations given by the author(s) in terms of preferred source formats and configuration parameters for sending contributions. If this is not indicated in a FONTLOG or other documentation of the font, consider asking them directly. Examples of useful contributions are bug fixes, additional glyphs, stylistic alternates (and the smart font code to access them) or improved hinting. Keep in mind that some kinds of changes (esp. hinting) may be technically difficult to integrate. + +7.4 How can I financially support the development of OFL fonts? +It is likely that most authors of OFL fonts would accept financial contributions - contact them for instructions on how to do this. Such contributions would support future development. You can also pay for others to enhance the fonts and contribute the results back to the original authors for inclusion in the Original Version. + + +8 ABOUT THE LICENSE ITSELF + +8.1 I see that this is version 1.1 of the license. Will there be later changes? +Version 1.1 is the first minor revision of the OFL. We are confident that version 1.1 will meet most needs, but are open to future improvements. Any revisions would be for future font releases, and previously existing licenses would remain in effect. No retroactive changes are possible, although the Copyright Holder(s) can re-release the font under a revised OFL. All versions will be available on our web site: http://scripts.sil.org/OFL. + +8.2 Does this license restrict the rights of the Copyright Holder(s)? +No. The Copyright Holder(s) still retain(s) all the rights to their creation; they are only releasing a portion of it for use in a specific way. For example, the Copyright Holder(s) may choose to release a 'basic' version of their font under the OFL, but sell a restricted 'enhanced' version under a different license. They may also choose to release the same font under both the OFL and some other license. Only the Copyright Holder(s) can do this, and doing so does not change the terms of the OFL as it applies to that font. + +8.3 Is the OFL a contract or a license? +The OFL is a worldwide license based on international copyright agreements and conventions. It is not a contract and so does not require you to sign it to have legal validity. By using, modifying and redistributing components under the OFL you indicate that you accept the license. + +8.4 I really like the terms of the OFL, but want to change it a little. Am I allowed to take ideas and actual wording from the OFL and put them into my own custom license for distributing my fonts? +We strongly recommend against creating your very own unique open licensing model. Using a modified or derivative license will likely cut you off - along with the font(s) under that license - from the community of designers using the OFL, potentially expose you and your users to legal liabilities, and possibly put your work and rights at risk. The OFL went though a community and legal review process that took years of effort, and that review is only applicable to an unmodified OFL. The text of the OFL has been written by SIL (with review and consultation from the community) and is copyright (c) 2005-2013 SIL International. You may re-use the ideas and wording (in part, not in whole) in another non-proprietary license provided that you call your license by another unambiguous name, that you do not use the preamble, that you do not mention SIL and that you clearly present your license as different from the OFL so as not to cause confusion by being too similar to the original. If you feel the OFL does not meet your needs for an open license, please contact us. + +8.5 Can I translate the license and the FAQ into other languages? +SIL certainly recognises the need for people who are not familiar with English to be able to understand the OFL and its use. Making the license very clear and readable has been a key goal for the OFL, but we know that people understand their own language best. + +If you are an experienced translator, you are very welcome to translate the OFL and OFL-FAQ so that designers and users in your language community can understand the license better. But only the original English version of the license has legal value and has been approved by the community. Translations do not count as legal substitutes and should only serve as a way to explain the original license. SIL - as the author and steward of the license for the community at large - does not approve any translation of the OFL as legally valid because even small translation ambiguities could be abused and create problems. + +SIL gives permission to publish unofficial translations into other languages provided that they comply with the following guidelines: + +- Put the following disclaimer in both English and the target language stating clearly that the translation is unofficial: + +"This is an unofficial translation of the SIL Open Font License into . It was not published by SIL International, and does not legally state the distribution terms for fonts that use the OFL. A release under the OFL is only valid when using the original English text. However, we recognize that this unofficial translation will help users and designers not familiar with English to better understand and use the OFL. We encourage designers who consider releasing their creation under the OFL to read the OFL-FAQ in their own language if it is available. Please go to http://scripts.sil.org/OFL for the official version of the license and the accompanying OFL-FAQ." + +- Keep your unofficial translation current and update it at our request if needed, for example if there is any ambiguity which could lead to confusion. + +If you start such a unofficial translation effort of the OFL and OFL-FAQ please let us know. + +8.6 Does the OFL have an explicit expiration term? +No, the implicit intent of the OFL is that the permissions granted are perpetual and irrevocable. + + +9 ABOUT SIL INTERNATIONAL + +9.1 Who is SIL International and what do they do? +SIL serves language communities worldwide, building their capacity for sustainable language development, by means of research, translation, training and materials development. SIL makes its services available to all without regard to religious belief, political ideology, gender, race, or ethnic background. SIL's members and volunteers share a Christian commitment. + +9.2 What does this have to do with font licensing? +The ability to read, write, type and publish in one's own language is one of the most critical needs for millions of people around the world. This requires fonts that are widely available and support lesser-known languages. SIL develops - and encourages others to develop - a complete stack of writing systems implementation components available under open licenses. This open stack includes input methods, smart fonts, smart rendering libraries and smart applications. There has been a need for a common open license that is specifically applicable to fonts and related software (a crucial component of this stack), so SIL developed the SIL Open Font License with the help of the Free/Libre and Open Source Software community. + +9.3 How can I contact SIL? +Our main web site is: http://www.sil.org/ +Our site about complex scripts is: http://scripts.sil.org/ +Information about this license (and contact information) is at: http://scripts.sil.org/OFL + + +APPENDIX A - FONTLOG EXAMPLE + +Here is an example of the recommended format for a FONTLOG, although other formats are allowed. + +----- +FONTLOG for the GlobalFontFamily fonts + +This file provides detailed information on the GlobalFontFamily Font Software. This information should be distributed along with the GlobalFontFamily fonts and any derivative works. + +Basic Font Information + +GlobalFontFamily is a Unicode typeface family that supports all languages that use the Latin script and its variants, and could be expanded to support other scripts. + +NewWorldFontFamily is based on the GlobalFontFamily and also supports Greek, Hebrew, Cyrillic and Armenian. + +More specifically, this release supports the following Unicode ranges... +This release contains... +Documentation can be found at... +To contribute to the project... + +ChangeLog + +10 December 2010 (Fred Foobar) GlobalFontFamily-devel version 1.4 +- fix new build and testing system (bug #123456) + +1 August 2008 (Tom Parker) GlobalFontFamily version 1.2.1 +- Tweaked the smart font code (Branch merged with trunk version) +- Provided improved build and debugging environment for smart behaviours + +7 February 2007 (Pat Johnson) NewWorldFontFamily Version 1.3 +- Added Greek and Cyrillic glyphs + +7 March 2006 (Fred Foobar) NewWorldFontFamily Version 1.2 +- Tweaked contextual behaviours + +1 Feb 2005 (Jane Doe) NewWorldFontFamily Version 1.1 +- Improved build script performance and verbosity +- Extended the smart code documentation +- Corrected minor typos in the documentation +- Fixed position of combining inverted breve below (U+032F) +- Added OpenType/Graphite smart code for Armenian +- Added Armenian glyphs (U+0531 -> U+0587) +- Released as "NewWorldFontFamily" + +1 Jan 2005 (Joe Smith) GlobalFontFamily Version 1.0 +- Initial release + +Acknowledgements + +If you make modifications be sure to add your name (N), email (E), web-address (if you have one) (W) and description (D). This list is in alphabetical order. + +N: Jane Doe +E: jane@university.edu +W: http://art.university.edu/projects/fonts +D: Contributor - Armenian glyphs and code + +N: Fred Foobar +E: fred@foobar.org +W: http://foobar.org +D: Contributor - misc Graphite fixes + +N: Pat Johnson +E: pat@fontstudio.org +W: http://pat.fontstudio.org +D: Designer - Greek & Cyrillic glyphs based on Roman design + +N: Tom Parker +E: tom@company.com +W: http://www.company.com/tom/projects/fonts +D: Engineer - original smart font code + +N: Joe Smith +E: joe@fontstudio.org +W: http://joe.fontstudio.org +D: Designer - original Roman glyphs + +Fontstudio.org is an not-for-profit design group whose purpose is... +Foobar.org is a distributed community of developers... +Company.com is a small business who likes to support community designers... +University.edu is a renowned educational institution with a strong design department... +----- +``` +------------------------------------------------------------------------------- diff --git a/vendor/LeapSDK/include/LeapC.h b/vendor/LeapSDK/include/LeapC.h new file mode 100644 index 00000000..b302f49b --- /dev/null +++ b/vendor/LeapSDK/include/LeapC.h @@ -0,0 +1,2659 @@ +/* Copyright (C) 2012-2017 Ultraleap Limited. All rights reserved. + * + * Use of this code is subject to the terms of the Ultraleap SDK agreement + * available at https://central.leapmotion.com/agreements/SdkAgreement unless + * Ultraleap has signed a separate license agreement with you or your + * organisation. + * + */ + +#ifndef _LEAP_C_H +#define _LEAP_C_H + +#ifndef LEAP_EXPORT +# ifdef _MSC_VER +# define LEAP_EXPORT __declspec(dllimport) +# else +# define LEAP_EXPORT +# endif +#endif + +#ifdef _MSC_VER +# define LEAP_CALL __stdcall +#else +# define LEAP_CALL +#endif + +#if defined(__cplusplus) && __cplusplus >= 201103L +# define LEAP_STATIC_ASSERT static_assert +#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L +# define LEAP_STATIC_ASSERT _Static_assert +#else +# define LEAP_STATIC_ASSERT(x, y) +#endif + +// Define integer types for Visual Studio 2008 and earlier +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef __int32 int32_t; +typedef __int64 int64_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +#else +#include +#endif + +#include + +#pragma pack(1) + +#ifdef __cplusplus +extern "C" { +#endif + +/** \defgroup Functions Functions + * Functions exported by the LeapC library. + * \defgroup Enum Enumerations + * Enumerations used by the LeapC functions and data structures. + * \defgroup Structs Data Structures + * Structs passed to and received from LeapC functions. + */ + +/** \ingroup Enum + * Defines the codes returned by all LeapC functions. + * @since 3.0.0 + */ +typedef enum _eLeapRS { + /** + * The operation completed successfully. + */ + eLeapRS_Success = 0x00000000, + + /** + * An undetermined error has occurred. + * This is usually the result of an abnormal operating condition in LeapC, + * the Ultraleap Tracking Service, or the host computer itself. + * @since 3.0.0 + */ + eLeapRS_UnknownError = 0xE2010000, + + /** + * An invalid argument was specified. + * @since 3.0.0 + */ + eLeapRS_InvalidArgument = 0xE2010001, + + /** + * Insufficient resources existed to complete the request. + * @since 3.0.0 + */ + eLeapRS_InsufficientResources = 0xE2010002, + + /** + * The specified buffer was not large enough to complete the request. + * @since 3.0.0 + */ + eLeapRS_InsufficientBuffer = 0xE2010003, + + /** + * The requested operation has timed out. + * @since 3.0.0 + */ + eLeapRS_Timeout = 0xE2010004, + + /** + * The operation is invalid because there is no current connection. + * @since 3.0.0 + */ + eLeapRS_NotConnected = 0xE2010005, + + /** + * The operation is invalid because the connection is not complete. + * @since 3.0.0 + */ + eLeapRS_HandshakeIncomplete = 0xE2010006, + + /** + * The specified buffer size is too large. + * @since 3.0.0 + */ + eLeapRS_BufferSizeOverflow = 0xE2010007, + + /** + * A communications protocol error occurred. + * @since 3.0.0 + */ + eLeapRS_ProtocolError = 0xE2010008, + + /** + * The server incorrectly specified zero as a client ID. + * @since 3.0.0 + */ + eLeapRS_InvalidClientID = 0xE2010009, + + /** + * The connection to the service was unexpectedly closed while reading or writing a message. + * The server may have terminated. + * @since 3.0.0 + */ + eLeapRS_UnexpectedClosed = 0xE201000A, + + /** + * The specified request token does not appear to be valid + * + * Provided that the token value which identifies the request itself was, at one point, valid, this + * error condition occurs when the request to which the token refers has already been satisfied or + * is currently being satisfied. + * @since 3.0.0 + */ + eLeapRS_UnknownImageFrameRequest = 0xE201000B, + + /** + * The specified frame ID is not valid or is no longer valid + * + * Provided that frame ID was, at one point, valid, this error condition occurs when the identifier + * refers to a frame that occurred further in the past than is currently recorded in the rolling + * frame window. + * @since 3.0.0 + */ + eLeapRS_UnknownTrackingFrameID = 0xE201000C, + + /** + * The specified timestamp references a future point in time + * + * The related routine can only operate on time points having occurred in the past, and the + * provided timestamp occurs in the future. + * @since 3.1.2 + */ + eLeapRS_RoutineIsNotSeer = 0xE201000D, + + /** + * The specified timestamp references a point too far in the past + * + * The related routine can only operate on time points occurring within its immediate record of + * the past. + * @since 3.1.2 + */ + eLeapRS_TimestampTooEarly = 0xE201000E, + + /** + * LeapPollConnection is called concurrently. + * @since 3.1.2 + */ + eLeapRS_ConcurrentPoll = 0xE201000F, + + /** + * A connection to the Ultraleap Tracking Service could not be established. + @since 3.0.0 + */ + eLeapRS_NotAvailable = 0xE7010002, + + /** + * The requested operation can only be performed while the device is sending data. + * @since 3.0.0 + */ + eLeapRS_NotStreaming = 0xE7010004, + + /** + * The specified device could not be opened. It is possible that the device identifier + * is invalid, or that the device has been disconnected since being enumerated. + * @since 3.0.0 + */ + eLeapRS_CannotOpenDevice = 0xE7010005, +} eLeapRS; +LEAP_STATIC_ASSERT(sizeof(eLeapRS) == 4, "Incorrect enum size"); + +/** \ingroup Enum + * Enumerates values for the tracking mode. + */ +typedef enum _eLeapTrackingMode { + /** The tracking mode optimised for desktop devices @since 5.0.0 */ + eLeapTrackingMode_Desktop = 0, + + /** The tracking mode optimised for head-mounted devices @since 5.0.0 */ + eLeapTrackingMode_HMD = 1, + + /** The tracking mode optimised for screen top-mounted devices @since 5.0.0 */ + eLeapTrackingMode_ScreenTop = 2, + + /** Tracking mode is not known (allows triggering of a new LEAP_TRACKING_MODE_EVENT) @since 5.0.0 */ + eLeapTrackingMode_Unknown = 3 +} eLeapTrackingMode; +LEAP_STATIC_ASSERT(sizeof(eLeapTrackingMode) == 4, "Incorrect enum size"); + +/** + * Evaluates to true if the specified return code is a success code + * @since 3.1.3 + */ +#define LEAP_SUCCEEDED(rs) ((rs & 0x80000000) == 0) + + /** + * Evaluates to true if the specified return code is a failure code + * @since 3.1.3 + */ +#define LEAP_FAILED(rs) ((rs & 0x80000000) != 0) + +/** \ingroup Structs + * \struct LEAP_CONNECTION + * A handle to the Leap connection object. + * Use this handle to specify the connection for an operation. + * @since 3.0.0 + */ +typedef struct _LEAP_CONNECTION *LEAP_CONNECTION; + +/** \ingroup Structs + * \struct LEAP_DEVICE + * A handle to a Leap device object. + * Use this handle to specify the device for an operation. + * @since 3.0.0 + */ +typedef struct _LEAP_DEVICE *LEAP_DEVICE; + +/** \ingroup Structs + * Represents a calibration object. + * Not currently of any particular use. + * @since 3.0.0 + */ +typedef struct _LEAP_CALIBRATION *LEAP_CALIBRATION; + +/** \ingroup Structs + * A reference to a Leap device. + * + * Get a LEAP_DEVICE_REF by calling LeapGetDeviceList(). Access a device by + * calling LeapOpenDevice() with this reference. LeapOpenDevice() provides a + * LEAP_DEVICE struct, which is a handle to an open device. + */ +typedef struct _LEAP_DEVICE_REF { + /** An opaque handle. @since 3.0.0 */ + void* handle; + /** a generic identifier. @since 3.0.0 */ + uint32_t id; +} LEAP_DEVICE_REF; + +typedef enum _eLeapConnectionConfig { + /** + * The client is aware of how to handle multiple devices through the API. + * @since 4.1.0 + */ + eLeapConnectionConfig_MultiDeviceAware = 0x00000001, +} eLeapConnectionConfig; +LEAP_STATIC_ASSERT(sizeof(eLeapConnectionConfig) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * Specifies the configuration for a connection. + * @since 3.0.0 + */ +typedef struct _LEAP_CONNECTION_CONFIG { + /** Set to the final size of the structure. @since 3.0.0 */ + uint32_t size; + + /** + * A combination of eLeapConnectionConfig flags. Set to 0 to indicate no + * special flags. @since 3.0.0 + */ + uint32_t flags; + + /** + * Specifies the server namespace to be used. Leave NULL to use the default namespace. + * + * It is possible to launch the service with a different IPC connection namespace + * (using internal service functions). Clients wishing to connect to a different + * server namespace may specify that namespace here. + * + * The default connection namespace is "Leap Service". + */ + /** For internal use. @since 3.0.0 */ + const char* server_namespace; +} LEAP_CONNECTION_CONFIG; + +/** \ingroup Enum + * Defines the various types of data that may be allocated using the allocator. + * @since 4.0.0 + */ +typedef enum _eLeapAllocatorType { + /** Signed 8-bit integer (char) @since 4.0.0 */ + eLeapAllocatorType_Int8 = 0, + /** Unsigned 8-bit integer (byte) @since 4.0.0 */ + eLeapAllocatorType_Uint8 = 1, + /** Signed 16-bit integer @since 4.0.0 */ + eLeapAllocatorType_Int16 = 2, + /** Unsigned 16-bit integer @since 4.0.0 */ + eLeapAllocatorType_UInt16 = 3, + /** Signed 32-bit integer @since 4.0.0 */ + eLeapAllocatorType_Int32 = 4, + /** Unsigned 32-bit integer @since 4.0.0 */ + eLeapAllocatorType_UInt32 = 5, + /** Single-precision 32-bit floating-point @since 4.0.0 */ + eLeapAllocatorType_Float = 6, + /** Signed 64-bit integer @since 4.0.0 */ + eLeapAllocatorType_Int64 = 8, + /** Unsigned 64-bit integer @since 4.0.0 */ + eLeapAllocatorType_UInt64 = 9, + /** Double-precision 64-bit floating-point @since 4.0.0 */ + eLeapAllocatorType_Double = 10, +} eLeapAllocatorType; +LEAP_STATIC_ASSERT(sizeof(eLeapAllocatorType) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * Specifies the allocator/deallocator functions to be used when the library + * needs to dynamically manage memory. + * @since 4.0.0 + */ +typedef struct LEAP_ALLOCATOR { + /** + * Function pointer to an allocator function that is expected to return a + * pointer to memory of at least the specified size in bytes. This will be + * called when the library needs a block of memory that will be provided + * back to the client in a subsequent event or response. A type hint is + * provided in the case where the underlying buffer type needs to be known + * at allocation time. + */ + void* (*allocate)(uint32_t size, eLeapAllocatorType typeHint, void* state); + + /** + * Function pointer to a deallocator function. The function receives the + * address of a previously allocated block of memory from the ``allocate`` + * function pointer. The caller is not required to deallocate the memory, + * but rather this call is used by the library to indicate to the client + * that it will no longer reference the memory at this address, and that + * the callee _may_ deallocate the memory when it is ready to do so. + */ + void (*deallocate)(void* ptr, void* state); + + /** + * Pointer to state to be passed to the allocate and deallocate functions. + */ + void* state; +} LEAP_ALLOCATOR; + +/** \ingroup Functions + * Samples the universal clock used by the system to timestamp image and tracking frames. + * + * The returned counter value is given in microseconds since an epoch time. The clock used for the + * counter itself is implementation-defined, but generally speaking, it is global, monotonic, and + * makes use of the most accurate high-performance counter available on the system. + * @returns microseconds since an unspecified epoch. + * @since 3.0.0 + */ +LEAP_EXPORT int64_t LEAP_CALL LeapGetNow(void); + +/** \ingroup Functions + * Creates a new LEAP_CONNECTION object. + * + * Pass the LEAP_CONNECTION pointer to LeapOpenConnection() to establish a + * connection to the Ultraleap Tracking Service; and to subsequent operations + * on the same connection. + * + * @param pConfig The configuration to be used with the newly created connection. + * If pConfig is null, a connection is created with a default configuration. + * @param[out] phConnection Receives a pointer to the connection object, set to invalid on failure + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapCreateConnection(const LEAP_CONNECTION_CONFIG* pConfig, LEAP_CONNECTION* phConnection); + +/** \ingroup Functions + * Opens a connection to the service. + * + * This routine will not block. A connection to the service will not be established until the first + * invocation of LeapPollConnection. + * + * @param hConnection A handle to the connection object, created by LeapCreateConnection(). + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapOpenConnection(LEAP_CONNECTION hConnection); + +typedef enum _eLeapServiceDisposition { + /** + * The service cannot receive frames fast enough from the underlying hardware. + * @since 3.1.3 + */ + eLeapServiceState_LowFpsDetected = 0x00000001, + + /** + * The service has paused itself due to an insufficient frame rate from the hardware. + * @since 3.1.3 + */ + eLeapServiceState_PoorPerformancePause = 0x00000002, + + /** + * The service has failed to start tracking due to unknown reasons. + * @since 5.1.16 + */ + eLeapServiceState_TrackingErrorUnknown = 0x00000004, + + /** + * The combination of all valid flags in this enumeration + */ + eLeapServiceState_ALL = eLeapServiceState_LowFpsDetected + | eLeapServiceState_PoorPerformancePause + | eLeapServiceState_TrackingErrorUnknown +} eLeapServiceDisposition; +LEAP_STATIC_ASSERT(sizeof(eLeapServiceDisposition) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * Received from LeapPollConnection() when a connection to the Ultraleap Tracking Service is established. + * @since 3.0.0 + */ +typedef struct _LEAP_CONNECTION_EVENT { + /** A combination of eLeapServiceDisposition flags. @since 3.1.3 */ + uint32_t flags; +} LEAP_CONNECTION_EVENT; + +/** \ingroup Structs + * Received from LeapPollConnection() when a connection to the Ultraleap Tracking Service is lost. + * + * If a LeapC function that performs a transaction with the Ultraleap Tracking Service is called + * after the connection is lost, the next call to LeapPollConnection() will return + * this event. Otherwise, it can take up to 5 seconds of polling the connection to + * receive this event. + * @since 3.0.0 + */ +typedef struct _LEAP_CONNECTION_LOST_EVENT { + /** Reserved for future use. @since 3.0.0 */ + uint32_t flags; +} LEAP_CONNECTION_LOST_EVENT; + +/** \ingroup Enums + * The connection status codes. + * These codes can be read from the LEAP_CONNECTION_INFO struct created by + * a call to LeapGetConnectionInfo(). + * @since 3.0.0 + */ +typedef enum _eLeapConnectionStatus { + /** + * The connection is not open. + * Call LeapOpenConnection() to open a connection to the Ultraleap Tracking Service. + * @since 3.0.0 + */ + eLeapConnectionStatus_NotConnected = 0, + + /** + * The connection is open. + * @since 3.0.0 + */ + eLeapConnectionStatus_Connected, + + /** + * Opening the connection is underway, but not complete. + * @since 3.0.0 + */ + eLeapConnectionStatus_HandshakeIncomplete, + + /** + * The connection could not be opened because the Ultraleap Tracking Service does not + * appear to be running. + * @since 3.0.0 + */ + eLeapConnectionStatus_NotRunning = 0xE7030004 +} eLeapConnectionStatus; +LEAP_STATIC_ASSERT(sizeof(eLeapConnectionStatus) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * Information about a connection. + * + * Call LeapCreateConnection() to generate the handle for the connection; + * call LeapOpenConnection() to establish the connection; then call + * LeapGetConnectionInfo(), which creates this struct, to check the connection status. + * @since 3.0.0 + */ +typedef struct _LEAP_CONNECTION_INFO { + /** The size of this structure. @since 3.0.0 */ + uint32_t size; + + /** The current status of this connection. @since 3.0.0 */ + eLeapConnectionStatus status; +} LEAP_CONNECTION_INFO; + +/** \ingroup Functions + * Retrieves status information about the specified connection. + * + * Call LeapCreateConnection() to generate the handle for the connection; + * call LeapOpenConnection() to establish the connection; then call + * this function to check the connection status. + * + * @param hConnection The handle of the connection of interest. Created by LeapCreateConnection. + * @param[out] pInfo A pointer to a buffer that receives additional connection information. One input, + * the size field of pInfo is the size of the buffer(i.e. the size of a LEAP_CONNECTION_INFO + * struct); On output, the size field of pInfo receives the size necessary to hold + * the entire information block. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapGetConnectionInfo(LEAP_CONNECTION hConnection, LEAP_CONNECTION_INFO* pInfo); + + +/** \ingroup Enum + * Enumerates flags for the service policies. + */ +typedef enum _eLeapPolicyFlag { + /** The policy allowing an application to receive frames in the background. @since 3.0.0 */ + eLeapPolicyFlag_BackgroundFrames = 0x00000001, + + /** The policy specifying whether to automatically stream images from the device. @since 4.0.0 */ + eLeapPolicyFlag_Images = 0x00000002, + + /** The policy specifying whether to optimize tracking for head-mounted device. @since 3.0.0 */ + eLeapPolicyFlag_OptimizeHMD = 0x00000004, + + /** The policy allowing an application to pause or resume service tracking. @since 3.0.0 */ + eLeapPolicyFlag_AllowPauseResume = 0x00000008, + + /** The policy allowing an application to receive per-frame map points. @since 4.0.0 */ + eLeapPolicyFlag_MapPoints = 0x00000080, + + /** The policy specifying whether to optimize tracking for screen-top device. @since 5.0.0 */ + eLeapPolicyFlag_OptimizeScreenTop = 0x00000100, +} eLeapPolicyFlag; +LEAP_STATIC_ASSERT(sizeof(eLeapPolicyFlag) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * The response from a request to get or set a policy. + * LeapPollConnection() creates this struct when the response becomes available. + * @since 3.0.0 + */ +typedef struct _LEAP_POLICY_EVENT { + /** Reserved for future use. @since 3.0.0 */ + uint32_t reserved; + + /** + * A bitfield containing the policies effective at the + * time the policy event was processed. @since 3.0.0 + */ + uint32_t current_policy; +} LEAP_POLICY_EVENT; + +/** \ingroup Structs + * The response from a request to get or set a policy. + * LeapPollConnection() creates this struct when the response becomes available. + * @since 3.0.0 + */ + +typedef struct _LEAP_TRACKING_MODE_EVENT { + /** Reserved for future use. @since 5.0.0 */ + uint32_t reserved; + + /** + * An enum specifying the tracking mode effective at the + * time the tracking mode event was processed. @since 5.0.0 + */ + eLeapTrackingMode current_tracking_mode; +} LEAP_TRACKING_MODE_EVENT; + + +/** \ingroup Functions + * Sets or clears one or more policy flags. + * + * Changing policies is asynchronous. After you call this function, a subsequent + * call to LeapPollConnection provides a LEAP_POLICY_EVENT containing the current + * policies, reflecting any changes. + * + * To get the current policies without changes, specify zero for both the set + * and clear parameters. When ready, LeapPollConnection() provides the + * a LEAP_POLICY_EVENT containing the current settings. + * + * The eLeapPolicyFlag enumeration defines the policy flags. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param set A bitwise combination of flags to be set. Set to 0 if not setting any flags. + * @param clear A bitwise combination of flags to be cleared. Set to 0 to if not clearing any flags. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapSetPolicyFlags(LEAP_CONNECTION hConnection, uint64_t set, uint64_t clear); + +/** \ingroup Functions + * Requests a tracking mode. + * + * Changing tracking modes is asynchronous. After you call this function, a subsequent + * call to LeapPollConnection provides a LEAP_POLICY_EVENT containing the current + * policies, reflecting any changes. + * + * The eLeapTrackingMode enumeration defines the tracking mode. + *. + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param mode The enum value specifying the requested tracking mode + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 5.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapSetTrackingMode(LEAP_CONNECTION hConnection, eLeapTrackingMode mode); + +/** \ingroup Functions + * Requests the currently set tracking mode. + * + * Requesting the current tracking mode is asynchronous. After you call this function, a subsequent + * call to LeapPollConnection provides a LEAP_TRACKING_MODE_EVENT containing the current + * tracking mode, reflecting any changes. + * + * The eLeapTrackingMode enumeration defines the tracking mode. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 5.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapGetTrackingMode(LEAP_CONNECTION hConnection); + +/** \ingroup Functions + * Pauses the service + * + * Attempts to pause or unpause the service depending on the argument. + * This is treated as a 'user pause', as though a user had requested a pause through the + * Leap Control Panel. The connection must have the AllowPauseResume policy set + * or it will fail with eLeapRS_InvalidArgument. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param pause Set to 'true' to pause, or 'false' to unpause + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 4.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapSetPause(LEAP_CONNECTION hConnection, bool pause); + +/** \ingroup Functions + * Sets the allocator functions to use for a particular connection. + * + * If user-supplied allocator functions are not supplied, the functions that require + * dynamic memory allocation will not be available. + * + * @param hConnection A handle to the connection object, created by LeapCreateConnection(). + * @param allocator A pointer to a structure containing the allocator functions to be called + * as needed by the library. + * @since 4.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapSetAllocator(LEAP_CONNECTION hConnection, const LEAP_ALLOCATOR* allocator); + +/** \ingroup Enum +* Identifies the operative data type of a LEAP_VARIANT struct instance. +* @since 3.0.0 +*/ +typedef enum _eLeapValueType { + /** The type is unknown (which is an abnormal condition). @since 3.0.0 */ + eLeapValueType_Unknown, + /** A boolean value. @since 3.0.0 */ + eLeapValueType_Boolean, + /** An integer value. @since 3.0.0 */ + eLeapValueType_Int32, + /** A floating point value. @since 3.0.0 */ + eLeapValueType_Float, + /** A string value. @since 3.0.0 */ + eLeapValueType_String, + FORCE_DWORD = 0x7FFFFFFF +} eLeapValueType; +LEAP_STATIC_ASSERT(sizeof(eLeapValueType) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * A variant data type used to get and set service configuration values. + * @since 3.0.0 + */ +typedef struct _LEAP_VARIANT { + /** The active data type in this instance. @since 3.0.0 */ + eLeapValueType type; + union { + /** A Boolean value. @since 3.0.0 */ + bool boolValue; + /** An integer value. @since 3.0.0 */ + int32_t iValue; + /** A floating point value. @since 3.0.0 */ + float fValue; + /** A pointer to a string buffer. @since 3.0.0 */ + const char* strValue; + }; +} LEAP_VARIANT; + +/** \ingroup Structs + * Contains the response to a configuration value request. + * Call LeapRequestConfigValue() to request a service config value. The value is + * fetched asynchronously since it requires a service transaction. LeapPollConnection() + * returns this event structure when the request has been processed. Use the requestID + * value to correlate the response to the originating request. + * @since 3.0.0 + */ +typedef struct _LEAP_CONFIG_RESPONSE_EVENT { + /** An identifier for correlating the request and response. @since 3.0.0 */ + uint32_t requestID; + + /** + * The configuration value retrieved from the service. Do not free any memory pointed to by + * this member. The value held is only valid until the next call to LeapPollConnection(). + * @since 3.0.0 + */ + LEAP_VARIANT value; +} LEAP_CONFIG_RESPONSE_EVENT; + +/** \ingroup Structs + * The result of a configuration change request. Contains a status of true for a + * successful change. + * Call LeapSaveConfigValue() to request a service config change. The change is + * performed asynchronously -- and may fail. LeapPollConnection() + * returns this event structure when the request has been processed. Use the requestID + * value to correlate the response to the originating request. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +typedef struct _LEAP_CONFIG_CHANGE_EVENT { + /** An identifier for correlating the request and response. @since 3.0.0 */ + uint32_t requestID; + + /** The result of the change operation: true on success; false on failure. @since 3.0.0 */ + bool status; +} LEAP_CONFIG_CHANGE_EVENT; + +/** \ingroup Functions + * Causes the client to commit a configuration change to the Ultraleap Tracking Service. + * + * The change is performed asynchronously -- and may fail. LeapPollConnection() + * returns this event structure when the request has been processed. Use the pRequestID + * value to correlate the response to the originating request. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param key The key of the configuration to commit. + * @param value The value of the configuration to commit. + * @param[out] pRequestID A pointer to a memory location to which the id for this request is written, or nullptr if this value is not needed. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapSaveConfigValue(LEAP_CONNECTION hConnection, const char* key, const LEAP_VARIANT* value, uint32_t* pRequestID); + +/** \ingroup Functions + * Requests the current value of a service configuration setting. + * The value is fetched asynchronously since it requires a service transaction. LeapPollConnection() + * returns this event structure when the request has been processed. Use the pRequestID + * value to correlate the response to the originating request. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param key The key of the configuration to request + * @param[out] pRequestID A pointer to a memory location to which the id for this request is written. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapRequestConfigValue(LEAP_CONNECTION hConnection, const char* key, uint32_t* pRequestID); + +/** \ingroup Functions + * Retrieves a list of Ultraleap Tracking camera devices currently attached to the system. + * + * To get the number of connected devices, call this function with the pArray parameter + * set to null. The number of devices is written to the memory specified by pnArray. + * Use the device count to create an array of LEAP_DEVICE_REF structs large enough to + * hold the number of connected devices. Finally, call LeapGetDeviceList() with this + * array and known count to get the list of Leap devices. A device must be opened with + * LeapOpenDevice() before device properties can be queried. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param[out] pArray A pointer to an array that LeapC fills with the device list. + * @param[in,out] pnArray On input, set to the number of elements in pArray; on output, + * LeapC sets this to the number of valid device handles. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapGetDeviceList(LEAP_CONNECTION hConnection, LEAP_DEVICE_REF* pArray, uint32_t* pnArray); + +/** \ingroup Functions + * Opens a device reference and retrieves a handle to the device. + * + * To ensure resources are properly freed, users must call LeapCloseDevice() + * when finished with the device, even if the retrieved device has problems + * or cannot stream. + * + * @param rDevice A device reference. + * @param[out] phDevice A pointer that receives the opened device handle. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapOpenDevice(LEAP_DEVICE_REF rDevice, LEAP_DEVICE* phDevice); + +LEAP_EXPORT eLeapRS LEAP_CALL LeapSetPrimaryDevice(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, bool unsubscribeOthers); + +LEAP_EXPORT eLeapRS LEAP_CALL LeapSubscribeEvents(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice); + +LEAP_EXPORT eLeapRS LEAP_CALL LeapUnsubscribeEvents(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice); + +/** \ingroup Enum + * Flags enumerating Leap device capabilities. @since 3.0.0 + */ +enum eLeapDeviceCaps { + /** The device can send color images. @since 3.0.0 */ + eLeapDeviceCaps_Color = 0x00000001, +}; + +/** \ingroup Enum + * Device hardware types. @since 3.0.0 + */ +typedef enum _eLeapDevicePID { + /** An unknown device that is compatible with the tracking software. @since 3.1.3 */ + eLeapDevicePID_Unknown = 0x0000, + + /** The Leap Motion Controller (the first consumer peripheral). @since 3.0.0 */ + eLeapDevicePID_Peripheral = 0x0003, + + /** Internal research product codename "Dragonfly". @since 3.0.0 */ + eLeapDevicePID_Dragonfly = 0x1102, + + /** Internal research product codename "Nightcrawler". @since 3.0.0 */ + eLeapDevicePID_Nightcrawler = 0x1201, + + /** Research product codename "Rigel". @since 4.0.0 */ + eLeapDevicePID_Rigel = 0x1202, + + /** The Ultraleap Stereo IR 170 (SIR170) hand tracking module. @since 5.3.0 */ + eLeapDevicePID_SIR170 = 0x1203, + + /** The Ultraleap 3Di hand tracking camera. @since 5.3.0 */ + eLeapDevicePID_3Di = 0x1204, + + /** An invalid device type. Not currently in use. @since 3.1.3 */ + eLeapDevicePID_Invalid = 0xFFFFFFFF +} eLeapDevicePID; +LEAP_STATIC_ASSERT(sizeof(eLeapDevicePID) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * Properties of a Leap device. + * Get a LEAP_DEVICE_INFO by calling LeapGetDeviceInfo() with the handle for + * device. The device must be open. + * @since 3.0.0 + **/ +typedef struct _LEAP_DEVICE_INFO { + /** Size of this structure. @since 3.0.0 */ + uint32_t size; + + /** A combination of eLeapDeviceStatus flags. @since 3.0.0 */ + uint32_t status; + + /** A combination of eLeapDeviceCaps flags. @since 3.0.0 */ + uint32_t caps; + + /** One of the eLeapDevicePID members. @since 3.0.0 */ + eLeapDevicePID pid; + + /** + * The device baseline, in micrometers. + * + * The baseline is defined as the distance between the center axis of each lens in a stereo camera + * system. For other camera systems, this value is set to zero. + * @since 3.0.0 + */ + uint32_t baseline; + + /** The required length of the serial number char buffer including the null character. @since 3.0.0 */ + uint32_t serial_length; + + /** A pointer to the null-terminated device serial number string. @since 3.0.0 */ + char* serial; + + /** The horizontal field of view of this device in radians. @since 3.0.0 */ + float h_fov; + + /** The vertical field of view of this device in radians. @since 3.0.0 */ + float v_fov; + + /** The maximum range for this device, in micrometers. @since 3.0.0 */ + uint32_t range; +} LEAP_DEVICE_INFO; + +/** \ingroup Functions + * Gets device properties. + * + * To get the device serial number, you must supply a LEAP_DEVICE_INFO struct whose + * serial member points to a char array large enough to hold the null-terminated + * serial number string. To get the required length, call LeapGetDeviceInfo() using + * a LEAP_DEVICE_INFO struct that has serial set to NULL. LeapC sets serial_length field of + * the struct to the required length. You can then allocate memory for the string, + * set the serial field, and call this function again. + * + * @param hDevice A handle to the device to be queried. + * @param[out] info The struct to receive the device property data. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapGetDeviceInfo(LEAP_DEVICE hDevice, LEAP_DEVICE_INFO* info); + +/** \ingroup Structs + * Device event information. + * + * LeapPollConnection() produces a message containing this event when a new + * device is detected. You can use the handle provided by the device filed to + * open a device so that you can access its properties. + * @since 3.0.0 + */ +typedef struct _LEAP_DEVICE_EVENT { + /** Reserved for future use. @since 3.0.0 */ + uint32_t flags; + + /** The handle reference of to the newly attached device. @since 3.0.0 */ + LEAP_DEVICE_REF device; + + /** The status of the connected device. A combination of flags from the eLeapDeviceStatus collection. */ + uint32_t status; +} LEAP_DEVICE_EVENT; + +/** \ingroup Enum + * Enumerates the device status codes. + * @since 3.0.0 + */ +typedef enum _eLeapDeviceStatus { + /** The device is sending out frames. @since 3.0.0*/ + eLeapDeviceStatus_Streaming = 0x00000001, + + /** Device streaming has been paused. @since 3.0.0 */ + eLeapDeviceStatus_Paused = 0x00000002, + + /** + * There are known sources of infrared interference. Device has transitioned to + * robust mode in order to compensate. @since 3.1.3 + */ + eLeapDeviceStatus_Robust = 0x00000004, + + /** The device's window is smudged, tracking may be degraded. @since 3.1.3 */ + eLeapDeviceStatus_Smudged = 0x00000008, + + /** The device has entered low-resource mode. @since 4.0.0 */ + eLeapDeviceStatus_LowResource = 0x00000010, + + /** The device has failed, but the failure reason is not known. @since 3.0.0 */ + eLeapDeviceStatus_UnknownFailure = 0xE8010000, + + /** The device has a bad calibration record and cannot send frames. @since 3.0.0 */ + eLeapDeviceStatus_BadCalibration = 0xE8010001, + + /** The device reports corrupt firmware or cannot install a required firmware update. @since 3.0.0 */ + eLeapDeviceStatus_BadFirmware = 0xE8010002, + + /** The device USB connection is faulty. @since 3.0.0 */ + eLeapDeviceStatus_BadTransport = 0xE8010003, + + /** The device USB control interfaces failed to initialize. @since 3.0.0 */ + eLeapDeviceStatus_BadControl = 0xE8010004, +} eLeapDeviceStatus; +LEAP_STATIC_ASSERT(sizeof(eLeapDeviceStatus) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * Device failure information. + * LeapPollConnection() produces a message containing this event when a + * device fails. Only partial information may be available. If hDevice is + * non-null, then you can use it to identify the failed device with a known, + * open device. + * @since 3.0.0 + */ +typedef struct _LEAP_DEVICE_FAILURE_EVENT { + /** The status of this failure event. @since 3.0.0 */ + eLeapDeviceStatus status; + + /** + * A handle to the device generating this failure event, if available, otherwise NULL. + * + * You are not responsible for closing this handle. + * @since 3.0.0 + */ + LEAP_DEVICE hDevice; +} LEAP_DEVICE_FAILURE_EVENT; + +/** \ingroup Structs + * Identifying information for a frame of tracking data. @since 3.0.0 + */ +typedef struct _LEAP_FRAME_HEADER { + /** Reserved, set to zero. @since 3.0.0 */ + void* reserved; + + /** + * A unique identifier for this frame + * + * All frames carrying this frame ID are part of the same unit of processing. This counter + * is generally an increasing counter, but may reset to another value if the user stops and + * restarts streaming. + * + * For interpolated frames, this value corresponds to the identifier of the frame upper bound. + * @since 3.0.0 + */ + int64_t frame_id; + + /** + * The timestamp for this image, in microseconds, referenced against LeapGetNow(). + * @since 3.0.0 + */ + int64_t timestamp; +} LEAP_FRAME_HEADER; + +/** \ingroup Enum + * Functional image types (not data formats). + */ +typedef enum _eLeapImageType { + /** An invalid or unknown type. @since 3.0.0 */ + eLeapImageType_UNKNOWN = 0, + + /** Default, processed IR images. @since 3.0.0 */ + eLeapImageType_Default, + + /** Raw images from the device. @since 3.0.0 */ + eLeapImageType_Raw +} eLeapImageType; +LEAP_STATIC_ASSERT(sizeof(eLeapImageType) == 4, "Incorrect enum size"); + +/** \ingroup Enum + * Image formats. + * @since 3.0.0 + */ +typedef enum _eLeapImageFormat { + /** An invalid or unknown format. @since 3.0.0 */ + eLeapImageFormat_UNKNOWN = 0, + + /** An infrared image. @since 3.0.0 */ + eLeapImageFormat_IR = 0x317249, + + /** A Bayer RGBIr image with uncorrected RGB channels. @since 3.0.0 */ + eLeapImageFormat_RGBIr_Bayer = 0x49425247, +} eLeapImageFormat; +LEAP_STATIC_ASSERT(sizeof(eLeapImageFormat) == 4, "Incorrect enum size"); + +/** \ingroup Enum + * Camera perspective types. + * @since 3.0.0 + */ +typedef enum _eLeapPerspectiveType { + /** An unknown or invalid type. @since 3.0.0 */ + eLeapPerspectiveType_invalid = 0, + + /** A canonically left image. @since 3.0.0 */ + eLeapPerspectiveType_stereo_left = 1, + + /** A canonically right image. @since 3.0.0 */ + eLeapPerspectiveType_stereo_right = 2, + + /** Reserved for future use. @since 3.0.0 */ + eLeapPerspectiveType_mono = 3, +} eLeapPerspectiveType; +LEAP_STATIC_ASSERT(sizeof(eLeapPerspectiveType) == 4, "Incorrect enum size"); + +/** \ingroup Enum + * Camera calibration types. + * @since 3.0.0 + */ +typedef enum _eLeapCameraCalibrationType { + /** Infrared calibration (default). @since 4.1.0 */ + eLeapCameraCalibrationType_infrared = 0, + + /** Visual calibration. @since 4.1.0 */ + eLeapCameraCalibrationType_visual = 1, +} eLeapCameraCalibrationType; +LEAP_STATIC_ASSERT(sizeof(eLeapCameraCalibrationType) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * Properties of a sensor image. + * @since 3.0.0 + */ +typedef struct _LEAP_IMAGE_PROPERTIES { + /** The type of this image. @since 3.0.0 */ + eLeapImageType type; + + /** The format of this image. @since 3.0.0 */ + eLeapImageFormat format; + + /** The number of bytes per image pixel. @since 3.0.0 */ + uint32_t bpp; + + /** The number of horizontal pixels in the image. @since 3.0.0 */ + uint32_t width; + + /** The number of rows of pixels in the image. @since 3.0.0 */ + uint32_t height; + + /** Reserved for future use. @since 3.0.0 */ + float x_scale; + /** Reserved for future use. @since 3.0.0 */ + float y_scale; + + /** Reserved for future use. @since 3.0.0 */ + float x_offset; + /** Reserved for future use. @since 3.0.0 */ + float y_offset; +} LEAP_IMAGE_PROPERTIES; + +#define LEAP_DISTORTION_MATRIX_N 64 +/** \ingroup Structs + * A matrix containing lens distortion correction coordinates. + * + * Each point in the grid contains the coordinates of the pixel in the image buffer that + * contains the data for the pixel in the undistorted image corresponding + * to that point in the grid. + * Interpolate between points in the matrix to correct image pixels that don't + * fall directly underneath a point in the distortion grid. + * + * Current devices use a 64x64 point distortion grid. + * @since 3.0.0 + */ +typedef struct _LEAP_DISTORTION_MATRIX { + /** A point in the distortion grid. @since 3.0.0 */ + struct { + /** The x-pixel coordinate. @since 3.0.0 */ + float x; + /** The y-pixel coordinate. @since 3.0.0 */ + float y; + } + /** A grid of 2D points. @since 3.0.0 */ + matrix[LEAP_DISTORTION_MATRIX_N][LEAP_DISTORTION_MATRIX_N]; +} LEAP_DISTORTION_MATRIX; + +/** \ingroup Structs + * Describes the image to request. + * Pass this struct to the LeapImageRequest() function. + * @since 3.0.0 + */ +typedef struct _LEAP_IMAGE_FRAME_DESCRIPTION { + /** + * The ID of the frame corresponding to the desired image. @since 3.0.0 + */ + int64_t frame_id; + + /** + * The type of the desired image. @since 3.0.0 + */ + eLeapImageType type; + + /** + * Length of your image buffer. The buffer must be large enough to + * hold the request image. + */ + uint64_t buffer_len; + + /** + * An allocated buffer large enough to contain the requested image. The buffer + * must remain valid until the image request completes or fails. + * @since 3.0.0 + */ + void* pBuffer; +} LEAP_IMAGE_FRAME_DESCRIPTION; + +/** \ingroup Structs + * A three element, floating-point vector. + * @since 3.0.0 + */ +typedef struct _LEAP_VECTOR { + /** You can access the vector members as either an array or individual float values. */ + union { + /** The vector as an array. @since 3.0.0 */ + float v[3]; + struct { + /** The x spatial coordinate. @since 3.0.0 */ + float x; + /** The y spatial coordinate. @since 3.0.0 */ + float y; + /** The z spatial coordinate. @since 3.0.0 */ + float z; + }; + }; +} LEAP_VECTOR; + +typedef struct _LEAP_MATRIX_3x3 { + LEAP_VECTOR m[3]; +} LEAP_MATRIX_3x3; + +/** \ingroup Structs + * A four element, floating point quaternion. @since 3.1.2 + */ +typedef struct _LEAP_QUATERNION { + union { + /** The quaternion as an array. @since 3.1.3 */ + float v[4]; + + struct { + /** The x coefficient of the vector portion of the quaternion. @since 3.1.2 */ + float x; + /** The y coefficient of the vector portion of the quaternion. @since 3.1.2 */ + float y; + /** The z coefficient of the vector portion of the quaternion. @since 3.1.2 */ + float z; + /** The scalar portion of the quaternion. @since 3.1.2 */ + float w; + }; + }; +} LEAP_QUATERNION; + +/** \ingroup Structs + * Describes a bone's position and orientation. + * + * Bones are members of the LEAP_DIGIT struct. + * @since 3.0.0 + */ +typedef struct _LEAP_BONE { + /** The base of the bone, closer to the heart. The bones origin. @since 3.0.0 */ + LEAP_VECTOR prev_joint; + + /** The end of the bone, further from the heart. @since 3.0.0 */ + LEAP_VECTOR next_joint; + + /** The average width of the flesh around the bone in millimeters. @since 3.0.0 */ + float width; + + /** Rotation in world space from the forward direction. + * Convert the quaternion to a matrix to derive the basis vectors. + * @since 3.1.2 + */ + LEAP_QUATERNION rotation; +} LEAP_BONE; + +/** \ingroup Structs + * Describes the digit of a hand. + * Digits are members of the LEAP_HAND struct. + * @since 3.0.0 + */ +typedef struct _LEAP_DIGIT { + /** The Leap identifier of this finger. @since 3.0.0 */ + int32_t finger_id; + + union { + /** All the bones of a digit as an iterable collection. @since 3.0.0 */ + LEAP_BONE bones[4]; + + struct { + /** + * The finger bone wholly inside the hand. + * For thumbs, this bone is set to have zero length and width, an identity basis matrix, + * and its joint positions are equal. + * Note that this is anatomically incorrect; in anatomical terms, the intermediate phalange + * is absent in a real thumb, rather than the metacarpal bone. In the Ultraleap Tracking model, + * however, we use a "zero" metacarpal bone instead for ease of programming. + * @since 3.0.0 + */ + LEAP_BONE metacarpal; + + /** The phalange extending from the knuckle. @since 3.0.0 */ + LEAP_BONE proximal; + + /** The bone between the proximal phalange and the distal phalange. @since 3.0.0 */ + LEAP_BONE intermediate; + + /** The distal phalange terminating at the finger tip. @since 3.0.0 */ + LEAP_BONE distal; + }; + }; + + /** Reports whether the finger is more or less straight. @since 3.0.0 */ + uint32_t is_extended; +} LEAP_DIGIT; + +/** \ingroup Structs + * Properties associated with the palm of the hand. + * The Palm is a member of the LEAP_HAND struct. + * @since 3.0.0 + */ +typedef struct _LEAP_PALM { + /** + * The center position of the palm in millimeters from the Ultraleap Tracking camera device origin. + * @since 3.0.0 + */ + LEAP_VECTOR position; + + /** + * The time-filtered and stabilized position of the palm. + * + * Smoothing and stabilization is performed in order to make + * this value more suitable for interaction with 2D content. The stabilized + * position lags behind the palm position by a variable amount, depending + * primarily on the speed of movement. + * @since 3.0.0 + */ + LEAP_VECTOR stabilized_position; + + /** + * The rate of change of the palm position in millimeters per second. + * @since 3.0.0 + */ + LEAP_VECTOR velocity; + + /** + * The normal vector to the palm. If your hand is flat, this vector will + * point downward, or "out" of the front surface of your palm. + * @since 3.0.0 + */ + LEAP_VECTOR normal; + + /** + * The estimated width of the palm when the hand is in a flat position. + * @since 3.0.0 + */ + float width; + + /** + * The unit direction vector pointing from the palm position toward the fingers. + * @since 3.0.0 + */ + LEAP_VECTOR direction; + + /** + * The quaternion representing the palm's orientation + * corresponding to the basis {normal x direction, -normal, -direction} + * @since 3.1.3 + */ + LEAP_QUATERNION orientation; +} LEAP_PALM; + +/** \ingroup Enum + * The Hand chirality types. + * Used in the LEAP_HAND struct. + * @since 3.0.0 + */ +typedef enum _eLeapHandType { + /** A left hand. @since 3.0.0 */ + eLeapHandType_Left, + + /** A right hand. @since 3.0.0 */ + eLeapHandType_Right +} eLeapHandType; +LEAP_STATIC_ASSERT(sizeof(eLeapHandType) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * Describes a tracked hand. @since 3.0.0 + */ +typedef struct _LEAP_HAND { + /** + * A unique ID for a hand tracked across frames. + * If tracking of a physical hand is lost, a new ID is assigned when + * tracking is reacquired. + * @since 3.0.0 + */ + uint32_t id; + + /** + * Reserved for future use. @since 3.0.0 + */ + uint32_t flags; + + /** + * Identifies the chirality of this hand. @since 3.0.0 + */ + eLeapHandType type; + + /** + * How confident we are with a given hand pose. Not currently used (always 1.0). + * @since 3.0.0 + */ + float confidence; + + /** + * The total amount of time this hand has been tracked, in microseconds. + * @since 3.0.0 + */ + uint64_t visible_time; + + /** + * The distance between index finger and thumb. @since 3.0.0 + */ + float pinch_distance; + + /** + * The average angle of fingers to palm. @since 3.0.0 + */ + float grab_angle; + + /** + * The normalized estimate of the pinch pose. + * Zero is not pinching; one is fully pinched. + * @since 3.0.0 + */ + float pinch_strength; + + /** + * The normalized estimate of the grab hand pose. + * Zero is not grabbing; one is fully grabbing. + * @since 3.0.0 + */ + float grab_strength; + + /** + * Additional information associated with the palm. @since 3.0.0 + */ + LEAP_PALM palm; + + /** The fingers of this hand. @since 3.0.0 */ + union { + struct { + /** The thumb. @since 3.0.0 */ + LEAP_DIGIT thumb; + /** The index finger. @since 3.0.0 */ + LEAP_DIGIT index; + /** The middle finger. @since 3.0.0 */ + LEAP_DIGIT middle; + /** The ring finger. @since 3.0.0 */ + LEAP_DIGIT ring; + /** The pinky finger. @since 3.0.0 */ + LEAP_DIGIT pinky; + }; + /** The fingers of the hand as an array. @since 3.0.0 */ + LEAP_DIGIT digits[5]; + }; + + /** + * The arm to which this hand is attached. + * An arm consists of a single LEAP_BONE struct. + * @since 3.0.0 + */ + LEAP_BONE arm; +} LEAP_HAND; + +/** \ingroup Structs + * A snapshot, or frame of data, containing the tracking data for a single moment in time. + * The LEAP_FRAME struct is the container for all the tracking data. + * @since 3.0.0 + */ +typedef struct _LEAP_TRACKING_EVENT { + /** A universal frame identification header. @since 3.0.0 */ + LEAP_FRAME_HEADER info; + + /** + * An identifier for this tracking frame. This identifier is meant to be monotonically + * increasing, but values may be skipped if the client application does not poll for messages + * fast enough. This number also generally increases at the same rate as info.frame_id, but + * if the server cannot process every image received from the device cameras, the info.frame_id + * identifier may increase faster. + * @since 3.0.0 + */ + int64_t tracking_frame_id; + + /** The number of hands tracked in this frame, i.e. the number of elements in + * the pHands array. + * @since 3.0.0 + */ + uint32_t nHands; + + /** + * A pointer to the array of hands tracked in this frame. + * @since 3.0.0 + */ + LEAP_HAND* pHands; + + /** + * Current tracking frame rate in hertz. + * + * This frame rate is distinct from the image frame rate, which is the rate that images are + * being read from the device. Depending on host CPU limitations, the tracking frame rate + * may be substantially less than the device frame rate. + * + * This number is generally equal to or less than the device frame rate, but there is one + * case where this number may be _higher_ than the device frame rate: When the device rate + * drops. In this case, the device frame rate will fall sooner than the tracking frame rate. + * + * This number is equal to zero if there are not enough frames to estimate frame rate. + * + * This number cannot be negative. + * @since 3.0.0 + */ + float framerate; +} LEAP_TRACKING_EVENT; + +/** \ingroup Enum + * System message severity types. @since 3.0.0 + */ +typedef enum _eLeapLogSeverity { + /** The message severity is not known or was not specified. @since 3.0.0 */ + eLeapLogSeverity_Unknown = 0, + /** A message about a fault that could render the software or device non-functional. @since 3.0.0 */ + eLeapLogSeverity_Critical, + /** A message warning about a condition that could degrade device capabilities. @since 3.0.0 */ + eLeapLogSeverity_Warning, + /** A system status message. @since 3.0.0 */ + eLeapLogSeverity_Information +} eLeapLogSeverity; +LEAP_STATIC_ASSERT(sizeof(eLeapLogSeverity) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * A system log message. @since 3.0.0 + */ +typedef struct _LEAP_LOG_EVENT { + /** The type of message. @since 4.0.0 */ + eLeapLogSeverity severity; + /** + * The timestamp of the message in microseconds. + * Compare with the current values of LeapGetNow() and the system clock to + * calculate the absolute time of the message. + * @since 4.0.0 + */ + int64_t timestamp; + /** + * A pointer to a null-terminated string containing the current log message. + * @since 4.0.0 + */ + const char* message; +} LEAP_LOG_EVENT; + +typedef struct _LEAP_LOG_EVENTS { + /** The number of log events being pointed to by the events field. + * @since 4.0.0 + */ + uint32_t nEvents; + + /** An array of ``nEvent`` LEAP_LOG_EVENT structures. + * @since 4.0.0 + */ + LEAP_LOG_EVENT* events; +} LEAP_LOG_EVENTS; + +/** \ingroup Structs + * A notification that a device's status has changed. One of these messages is received by the client + * as soon as the service is connected, or when a new device is attached. + * @since 3.1.3 + */ +typedef struct _LEAP_DEVICE_STATUS_CHANGE_EVENT { + /** A reference to the device whose status has changed */ + LEAP_DEVICE_REF device; + + /** The last known status of the device. This is a combination of eLeapDeviceStatus flags. @since 3.1.3*/ + uint32_t last_status; + + /** The current status of the device. This is a combination of eLeapDeviceStatus flags. @since 3.1.3*/ + uint32_t status; +} LEAP_DEVICE_STATUS_CHANGE_EVENT; + +typedef enum _eLeapDroppedFrameType { + eLeapDroppedFrameType_PreprocessingQueue, + eLeapDroppedFrameType_TrackingQueue, + eLeapDroppedFrameType_Other +} eLeapDroppedFrameType; +LEAP_STATIC_ASSERT(sizeof(eLeapDroppedFrameType) == 4, "Incorrect enum size"); + +typedef struct _LEAP_DROPPED_FRAME_EVENT { + int64_t frame_id; + eLeapDroppedFrameType type; +} LEAP_DROPPED_FRAME_EVENT; + +/** \ingroup Structs + * An image associated with a frame of data. + * @since 4.0.0 + */ +typedef struct _LEAP_IMAGE { + /** The properties of the received image. */ + LEAP_IMAGE_PROPERTIES properties; + + /** + * A version number for the distortion matrix. When the distortion matrix + * changes, this number is updated. This number is guaranteed not to repeat + * for the lifetime of the connection. This version number is also guaranteed + * to be distinct for each perspective of an image. + * + * This value is guaranteed to be nonzero if it is valid. + * + * The distortion matrix only changes when the streaming device changes or when the + * device orientation flips -- inverting the image and the distortion grid. + * Since building a matrix to undistort an image can be a time-consuming task, + * you can optimize the process by only rebuilding this matrix (or whatever + * data type you use to correct image distortion) when the grid actually changes. + */ + uint64_t matrix_version; + + /** Pointers to the camera's distortion matrix. */ + LEAP_DISTORTION_MATRIX* distortion_matrix; + + /** A pointer to the image data. */ + void* data; + + /** Offset, in bytes, from the beginning of the data ptr to the actual beginning of the image data */ + uint32_t offset; +} LEAP_IMAGE; + +typedef struct _LEAP_POINT_MAPPING_CHANGE_EVENT { + /** The ID of the frame corresponding to the source of the currently tracked points. @since 4.0.0 */ + int64_t frame_id; + /** The timestamp of the frame, in microseconds, referenced against LeapGetNow(). @since 4.0.0 */ + int64_t timestamp; + /** The number of points being tracked. @since 4.0.0 */ + uint32_t nPoints; +} LEAP_POINT_MAPPING_CHANGE_EVENT; + +typedef struct _LEAP_POINT_MAPPING { + /** The ID of the frame corresponding to the source of the currently tracked points. @since 4.0.0 */ + int64_t frame_id; + /** The timestamp of the frame, in microseconds, referenced against LeapGetNow(). @since 4.0.0 */ + int64_t timestamp; + /** The number of points being tracked. @since 4.0.0 */ + uint32_t nPoints; + /** The 3D points being mapped. @since 4.0.0 */ + LEAP_VECTOR* pPoints; + /** The IDs of the 3D points being mapped. @since 4.0.0 */ + uint32_t* pIDs; +} LEAP_POINT_MAPPING; + +typedef struct _LEAP_HEAD_POSE_EVENT { + /** + * The timestamp for this image, in microseconds, referenced against LeapGetNow(). + * @since 4.1.0 + */ + int64_t timestamp; + /** + * The position and orientation of the user's head. Positional tracking must be enabled. + * @since 4.1.0 + */ + LEAP_VECTOR head_position; + LEAP_QUATERNION head_orientation; + /** + * The linear and angular velocity of the user's head. Positional tracking must be enabled. + * @since 4.1.0 + */ + LEAP_VECTOR head_linear_velocity; + LEAP_VECTOR head_angular_velocity; +} LEAP_HEAD_POSE_EVENT; + +typedef struct _LEAP_EYE_EVENT { + + /** + * The ID of the frame corresponding to the source of the currently tracked + * eye positions. + * @since 4.1.0 + */ + int64_t frame_id; + + /** + * The timestamp for this image, in microseconds, referenced against + * LeapGetNow(). + * @since 4.1.0 + */ + int64_t timestamp; + + /** + * The position of the user's left eye. + * @since 4.1.0 + */ + LEAP_VECTOR left_eye_position; + + /** + * The position of the user's right eye. + * @since 4.1.0 + */ + LEAP_VECTOR right_eye_position; + + /** + * An error estimate of the tracked left eye position. Higher values indicate + * uncertain tracking and a higher likelihood of there being no such eye in + * view of the sensor. + * @since 4.1.0 + */ + float left_eye_estimated_error; + + /** + * An error estimate of the tracked right eye position. Higher values indicate + * uncertain tracking and a higher likelihood of there being no such eye in + * view of the sensor. + * @since 4.1.0 + */ + float right_eye_estimated_error; + +} LEAP_EYE_EVENT; + +typedef enum _eLeapIMUFlag { + /** Has accelerometer measurements. @since 4.1.0 */ + eLeapIMUFlag_HasAccelerometer = 0x00000001, + /** Has gyroscope measurements. @since 4.1.0 */ + eLeapIMUFlag_HasGyroscope = 0x00000002, + /** Has a temperature measurement. @since 4.1.0 */ + eLeapIMUFlag_HasTemperature = 0x00000004, +} eLeapIMUFlag; +LEAP_STATIC_ASSERT(sizeof(eLeapIMUFlag) == 4, "Incorrect enum size"); + +typedef struct _LEAP_IMU_EVENT { + /** + * The timestamp for these measurements, in microseconds, referenced against + * LeapGetNow(). + * @since 4.1.0 + */ + int64_t timestamp; + + /** + * The timestamp for these measurements, in microseconds, referenced against + * the device's internal clock. + * @since 4.1.0 + */ + int64_t timestamp_hw; + + /** + * A combination of eLeapIMUFlag flags. + * @since 4.1.0 + */ + uint32_t flags; + + /** + * The accelerometer measurements, in m/s^2. + * @since 4.1.0 + */ + LEAP_VECTOR accelerometer; + + /** + * The gyroscope measurements, in rad/s. + * @since 4.1.0 + */ + LEAP_VECTOR gyroscope; + + /** + * The measured temperature, in deg C. + * @since 4.1.0 + */ + float temperature; +} LEAP_IMU_EVENT; + +/** \ingroup Structs + * Streaming stereo image pairs from the device. + * + * LeapPollConnection() produces this message when an image is available. + * The struct contains image properties, the distortion grid, and a pointer to + * the buffer containing the image data -- which was allocated using the allocator + * function passed to LeapC using the LeapSetAllocator. + * @since 4.0.0 + */ +typedef struct _LEAP_IMAGE_EVENT { + /** The information header identifying the images tracking frame. */ + LEAP_FRAME_HEADER info; + + /** The left and right images. */ + LEAP_IMAGE image[2]; + + /** For internal use only. */ + LEAP_CALIBRATION calib; +} LEAP_IMAGE_EVENT; + +/** \ingroup Enum + * The types of event messages resulting from calling LeapPollConnection(). + * @since 3.0.0 + */ +typedef enum _eLeapEventType { + /** + * No event has occurred within the timeout period specified when calling LeapPollConnection(). + * @since 3.0.0 + */ + eLeapEventType_None = 0, + + /** + * A connection to the Ultraleap Tracking Service has been established. + * @since 3.0.0 + */ + eLeapEventType_Connection, + + /** + * The connection to the Ultraleap Tracking Service has been lost. + * @since 3.0.0 + */ + eLeapEventType_ConnectionLost, + + /** + * A device has been detected or plugged-in. + * A device event is dispatched after a connection is established for any + * devices already plugged in. (The system currently only supports one + * streaming device at a time.) + * @since 3.0.0 + */ + eLeapEventType_Device, + + /** + * A device has failed. + * Device failure could be caused by hardware failure, USB controller issues, or + * other system instability. Note that unplugging a device generates an + * eLeapEventType_DeviceLost event message, not a failure message. + * @since 3.0.0 + */ + eLeapEventType_DeviceFailure, + + /** + * A policy change has occurred. + * This can be due to setting a policy with LeapSetPolicyFlags() or due to changing + * or policy-related config settings, including images_mode. + * (A user can also change these policies using the Ultraleap Tracking Control Panel.) + * @since 3.0.0 + */ + eLeapEventType_Policy, + + /** + * A tracking frame. The message contains the tracking data for the frame. + * @since 3.0.0 + */ + eLeapEventType_Tracking = 0x100, + + /** + * The request for an image has failed. + * The message contains information about the failure. The client application + * will not receive the requested image set. + * @since 3.0.0 + */ + eLeapEventType_ImageRequestError, + + /** + * The request for an image is complete. + * The image data has been completely written to the application-provided + * buffer. + * @since 3.0.0 + */ + eLeapEventType_ImageComplete, + + /** + * A system message. @since 3.0.0 + */ + eLeapEventType_LogEvent, + + /** + * The device connection has been lost. + * + * This event is generally asserted when the device has been detached from the system, when the + * connection to the service has been lost, or if the device is closed while streaming. Generally, + * any event where the system can conclude no further frames will be received will result in this + * message. The DeviceEvent field will be filled with the id of the formerly attached device. + * @since 3.0.0 + */ + eLeapEventType_DeviceLost, + + /** + * The asynchronous response to a call to LeapRequestConfigValue(). + * Contains the value of requested configuration item. + * @since 3.0.0 + */ + eLeapEventType_ConfigResponse, + + /** + * The asynchronous response to a call to LeapSaveConfigValue(). + * Reports whether the change succeeded or failed. + * @since 3.0.0 + */ + eLeapEventType_ConfigChange, + + /** + * Notification that a status change has been detected on an attached device + * + * @since 3.1.3 + */ + eLeapEventType_DeviceStatusChange, + eLeapEventType_DroppedFrame, + + /** + * Notification that an unrequested stereo image pair is available + * + * @since 4.0.0 + */ + eLeapEventType_Image, + + /** + * Notification that point mapping has changed + * + * @since 4.0.0 + */ + eLeapEventType_PointMappingChange, + + /** + * A tracking mode change has occurred. + * This can be due to changing the hmd or screentop policy with LeapSetPolicyFlags(). + * or setting the tracking mode using LeapSetTrackingMode(). + * @since 5.0.0 + */ + eLeapEventType_TrackingMode, + + /** + * An array of system messages. @since 4.0.0 + */ + eLeapEventType_LogEvents, + + /** + * A head pose. The message contains the timestamped head position and orientation. + * @since 4.1.0 + */ + eLeapEventType_HeadPose, + + /** + * Tracked eye positions. @since 4.1.0 + */ + eLeapEventType_Eyes, + + /** + * An IMU reading. @since 4.1.0 + */ + eLeapEventType_IMU +} eLeapEventType; +LEAP_STATIC_ASSERT(sizeof(eLeapEventType) == 4, "Incorrect enum size"); + +/** \ingroup Structs + * Defines a basic message from the LeapC message queue. + * Set by calling LeapPollConnection(). + * @since 3.0.0 + */ +typedef struct _LEAP_CONNECTION_MESSAGE { + /** + * The size of this message struct. @since 3.0.0 + */ + uint32_t size; + + /** + * The message type. @since 3.0.0 + */ + eLeapEventType type; + + /** + * A pointer to the event data for the current type of message. @since 3.0.0 + */ + union { + /** An untyped pointer. @since 3.0.0 */ + const void* pointer; + /** A connection message. @since 3.0.0 */ + const LEAP_CONNECTION_EVENT* connection_event; + /** A connection lost. @since 3.0.0 */ + const LEAP_CONNECTION_LOST_EVENT* connection_lost_event; + /** A device detected message. @since 3.0.0 */ + const LEAP_DEVICE_EVENT* device_event; + /** A device's status has changed. @since 3.1.3 */ + const LEAP_DEVICE_STATUS_CHANGE_EVENT* device_status_change_event; + /** A policy message. @since 3.0.0 */ + const LEAP_POLICY_EVENT* policy_event; + /** A device failure message. @since 3.0.0 */ + const LEAP_DEVICE_FAILURE_EVENT* device_failure_event; + /** A tracking message. @since 3.0.0 */ + const LEAP_TRACKING_EVENT* tracking_event; + /** A tracking mode message. @since 5.0.0 */ + const LEAP_TRACKING_MODE_EVENT* tracking_mode_event; + /** A log message. @since 3.0.0 */ + const LEAP_LOG_EVENT* log_event; + /** A log messages. @since 4.0.0 */ + const LEAP_LOG_EVENTS* log_events; + /** A get config value message. @since 3.0.0 */ + const LEAP_CONFIG_RESPONSE_EVENT* config_response_event; + /** A set config value message. @since 3.0.0 */ + const LEAP_CONFIG_CHANGE_EVENT* config_change_event; + const LEAP_DROPPED_FRAME_EVENT* dropped_frame_event; + /** A streaming image message. @since 4.0.0 */ + const LEAP_IMAGE_EVENT* image_event; + /** A point mapping message. @since 4.0.0 */ + const LEAP_POINT_MAPPING_CHANGE_EVENT* point_mapping_change_event; + /** A head pose message. @since 4.1.0 */ + const LEAP_HEAD_POSE_EVENT* head_pose_event; + /** An eye positions message for both the left and right eyes. @since 4.1.0 */ + const LEAP_EYE_EVENT* eye_event; + /** An IMU message. @since 4.1.0 */ + const LEAP_IMU_EVENT* imu_event; + }; + + /** A unique ID for the attached device that sent this message. A value of + * 0 indicates that it was a system-wide message, and not device specific. + * Use this ID to distinguish messages sent from multiple attached devices. + * @since 4.1.0 + */ + uint32_t device_id; +} LEAP_CONNECTION_MESSAGE; + +/** \ingroup Functions + * Polls the connection for a new event. + * + * The specific types of events that may be received are not configurable in this entrypoint. Configure + * the device or connection object directly to change what events will be received. + * + * Pointers in the retrieved event message structure will be valid until the associated connection or device is + * closed, or the next call to LeapPollConnection(). + * + * Calling this method concurrently will return eLeapRS_ConcurrentPoll. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param timeout The maximum amount of time to wait, in milliseconds. If this value is zero, + * the evt pointer references the next queued message, if there is one, and returns immediately. + * @param[out] evt A pointer to a structure that is filled with event information. This structure will be valid + * as long as the LEAP_CONNECTION object is valid. + * + * @returns The operation result code, a member of the eLeapRS enumeration. If the operation + * times out, this method will return eLeapRS_Timeout. The evt pointer will reference a + * message of type eLeapEventType_None. + * @since 3.0.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapPollConnection(LEAP_CONNECTION hConnection, uint32_t timeout, LEAP_CONNECTION_MESSAGE* evt); + +/** \ingroup Functions + * Retrieves the number of bytes required to allocate an interpolated frame at the specified time. + * + * Use this function to determine the size of the buffer to allocate when calling + * LeapInterpolateFrame(). + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param timestamp The timestamp of the frame whose size is to be queried. + * @param[out] pncbEvent A pointer that receives the number of bytes required to store the specified frame. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.1.1 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapGetFrameSize(LEAP_CONNECTION hConnection, int64_t timestamp, uint64_t* pncbEvent); + +/** \ingroup Functions + * Retrieves the number of bytes required to allocate an interpolated frame at the specified time + * for a particular device. + * + * Use this function to determine the size of the buffer to allocate when calling + * LeapInterpolateFrameEx(). + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param hDevice A device handle returned by LeapOpenDevice(). + * @param timestamp The timestamp of the frame whose size is to be queried. + * @param[out] pncbEvent A pointer that receives the number of bytes required to store the specified frame. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 4.1.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapGetFrameSizeEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, int64_t timestamp, uint64_t* pncbEvent); + +/** \ingroup Functions + * Constructs a frame at the specified timestamp by interpolating between measured + * frames. + * + * Caller is responsible for allocating a buffer large enough to hold the data of the frame. + * Use LeapGetFrameSize() to calculate the minimum size of this buffer. + * + * Use LeapCreateClockRebaser(), LeapUpdateRebase(), and LeapRebaseClock() to + * synchronize time measurements in the application with time measurements in + * the Ultraleap Tracking Service. This process is required to achieve accurate, smooth + * interpolation. + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param timestamp The timestamp at which to interpolate the frame data. + * @param[out] pEvent A pointer to a flat buffer which is filled with an interpolated frame. + * @param ncbEvent The number of bytes pointed to by pEvent. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.1.1 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapInterpolateFrame(LEAP_CONNECTION hConnection, int64_t timestamp, LEAP_TRACKING_EVENT* pEvent, uint64_t ncbEvent); + +/** \ingroup Functions + * Constructs a frame at the specified timestamp for a particular device by + * interpolating between measured frames. + * + * Caller is responsible for allocating a buffer large enough to hold the data of the frame. + * Use LeapGetFrameSizeEx() to calculate the minimum size of this buffer. + * + * Use LeapCreateClockRebaser(), LeapUpdateRebase(), and LeapRebaseClock() to + * synchronize time measurements in the application with time measurements in + * the Ultraleap Tracking Service. This process is required to achieve accurate, smooth + * interpolation. + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param hDevice A device handle returned by LeapOpenDevice(). + * @param timestamp The timestamp at which to interpolate the frame data. + * @param[out] pEvent A pointer to a flat buffer which is filled with an interpolated frame. + * @param ncbEvent The number of bytes pointed to by pEvent. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 4.1.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapInterpolateFrameEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, int64_t timestamp, LEAP_TRACKING_EVENT* pEvent, uint64_t ncbEvent); + +/** \ingroup Functions +* Constructs a frame at the specified timestamp by interpolating between a frame near the timestamp +* and a frame near the sourceTimestamp. +* +* Caller is responsible for allocating a buffer large enough to hold the data of the frame. +* Use LeapGetFrameSize() to calculate the minimum size of this buffer. +* +* Use LeapCreateClockRebaser(), LeapUpdateRebase(), and LeapRebaseClock() to +* synchronize time measurements in the application with time measurements in +* the Ultraleap Tracking Service. This process is required to achieve accurate, smooth +* interpolation. +* @param hConnection The connection handle created by LeapCreateConnection(). +* @param timestamp The timestamp to which to interpolate the frame data. +* @param sourceTimestamp The timestamp of the beginning frame from which to interpolate the frame data. +* @param[out] pEvent A pointer to a flat buffer which is filled with an interpolated frame. +* @param ncbEvent The number of bytes pointed to by pEvent. +* @returns The operation result code, a member of the eLeapRS enumeration. +* @since 3.1.1 +*/ +LEAP_EXPORT eLeapRS LEAP_CALL LeapInterpolateFrameFromTime(LEAP_CONNECTION hConnection, int64_t timestamp, int64_t sourceTimestamp, LEAP_TRACKING_EVENT* pEvent, uint64_t ncbEvent); + +/** \ingroup Functions +* Constructs a frame at the specified timestamp for a particular device by +* interpolating between a frame near the timestamp and a frame near the +* sourceTimestamp. +* +* Caller is responsible for allocating a buffer large enough to hold the data of the frame. +* Use LeapGetFrameSizeEx() to calculate the minimum size of this buffer. +* +* Use LeapCreateClockRebaser(), LeapUpdateRebase(), and LeapRebaseClock() to +* synchronize time measurements in the application with time measurements in +* the Ultraleap Tracking Service. This process is required to achieve accurate, smooth +* interpolation. +* @param hConnection The connection handle created by LeapCreateConnection(). +* @param hDevice A device handle returned by LeapOpenDevice(). +* @param timestamp The timestamp to which to interpolate the frame data. +* @param sourceTimestamp The timestamp of the beginning frame from which to interpolate the frame data. +* @param[out] pEvent A pointer to a flat buffer which is filled with an interpolated frame. +* @param ncbEvent The number of bytes pointed to by pEvent. +* @returns The operation result code, a member of the eLeapRS enumeration. +* @since 4.1.0 +*/ +LEAP_EXPORT eLeapRS LEAP_CALL LeapInterpolateFrameFromTimeEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, int64_t timestamp, int64_t sourceTimestamp, LEAP_TRACKING_EVENT* pEvent, uint64_t ncbEvent); + +LEAP_EXPORT eLeapRS LEAP_CALL LeapInterpolateHeadPose(LEAP_CONNECTION hConnection, int64_t timestamp, LEAP_HEAD_POSE_EVENT* pEvent); + +LEAP_EXPORT eLeapRS LEAP_CALL LeapInterpolateHeadPoseEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, int64_t timestamp, LEAP_HEAD_POSE_EVENT* pEvent); + +LEAP_EXPORT eLeapRS LEAP_CALL LeapInterpolateEyePositions(LEAP_CONNECTION hConnection, int64_t timestamp, LEAP_EYE_EVENT* pEvent); + +/** \ingroup Functions + * Closes a device handle previously opened with LeapOpenDevice. + * + * @param hDevice The device handle to close. + * @since 3.0.0 + */ +LEAP_EXPORT void LEAP_CALL LeapCloseDevice(LEAP_DEVICE hDevice); + +/** \ingroup Functions + * Closes a previously opened connection. + * + * This method closes the specified connection object if it is opened + * + * This method never fails. + * + * @param hConnection A handle to the connection object to be closed. + * @since 4.0.0 + */ +LEAP_EXPORT void LEAP_CALL LeapCloseConnection(LEAP_CONNECTION hConnection); + +/** \ingroup Functions + * Destroys a previously opened connection. + * + * This method closes the specified connection object if it is opened, destroys the underlying + * object, and releases all resources associated with it. + * + * This method never fails. + * + * Be sure that no other functions are accessing the connection when this function is called. + * + * @param hConnection A handle to the connection object to be destroyed. + * @since 3.0.0 + */ +LEAP_EXPORT void LEAP_CALL LeapDestroyConnection(LEAP_CONNECTION hConnection); + +/** \ingroup Structs + * \struct LEAP_CLOCK_REBASER + * An opaque clock rebase state structure. @since 3.1.2 + */ +typedef struct _LEAP_CLOCK_REBASER *LEAP_CLOCK_REBASER; + +/** \ingroup Functions + * Initializes a new Leap clock-rebaser handle object. + * + * Pass the filled-in LEAP_CLOCK_REBASER object to calls to LeapUpdateRebase(), + * LeapRebaseClock(), and LeapDestroyClockRebaser(). + * + * @param[out] phClockRebaser The pointer to the clock-rebaser object to be initialized. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.1.2 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapCreateClockRebaser(LEAP_CLOCK_REBASER* phClockRebaser); + +/** \ingroup Functions + * Updates the relationship between the Ultraleap Tracking Service clock and the user clock. + * + * When using LeapInterpolateFrame(), call this function for every graphics frame + * rendered by your application. The function should be called as close to the + * actual point of rendering as possible. + * + * The relationship between the application clock and the Ultraleap Tracking Service clock is + * neither fixed nor stable. Simulation restarts can cause user clock values to change + * instantaneously. Certain systems simulate slow motion, or respond to heavy load, by reducing the tick rate + * of the user clock. As a result, the LeapUpdateRebase() function must be called for every rendered frame. + * + * @param hClockRebaser The handle to a rebaser object created by LeapCreateClockRebaser(). + * @param userClock A clock value supplied by the application, sampled at about the same time as LeapGetNow() was sampled. + * @param leapClock The Ultraleap Tracking Service clock value sampled by a call to LeapGetNow(). + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.1.2 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapUpdateRebase(LEAP_CLOCK_REBASER hClockRebaser, int64_t userClock, int64_t leapClock); + +/** \ingroup Functions + * Computes the Ultraleap Tracking Service clock corresponding to a specified application clock value. + * + * Use this function to translate your application clock to the Ultraleap Tracking Service clock + * when interpolating frames. LeapUpdateRebase() must be called for every rendered + * frame for the relationship between the two clocks to remain synchronized. + * + * @param hClockRebaser The handle to a rebaser object created by LeapCreateClockRebaser(). + * @param userClock The clock in microseconds referenced to the application clock. + * @param[out] pLeapClock The corresponding Ultraleap Tracking Service clock value. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.1.2 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapRebaseClock(LEAP_CLOCK_REBASER hClockRebaser, int64_t userClock, int64_t* pLeapClock); + +/** \ingroup Functions + * Destroys a previously created clock-rebaser object. + * + * This method destroys the specified clock-rebaser object, and releases all resources associated with it. + * + * @param hClockRebaser A handle to the clock-rebaser object to be destroyed. + * @since 3.1.2 + */ +LEAP_EXPORT void LEAP_CALL LeapDestroyClockRebaser(LEAP_CLOCK_REBASER hClockRebaser); + +/** \ingroup Functions + * Provides the corrected camera ray intercepting the specified point on the image. + * + * Given a point on the image, ``LeapPixelToRectilinear()`` corrects for camera distortion + * and returns the true direction from the camera to the source of that image point + * within the Ultraleap Tracking camera field of view. + * + * This direction vector has an x and y component [x, y, 1], with the third element + * always 1. Note that this vector uses the 2D camera coordinate system + * where the x-axis parallels the longer (typically horizontal) dimension and + * the y-axis parallels the shorter (vertical) dimension. The camera coordinate + * system does not correlate to the 3D Ultraleap Tracking coordinate system. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param pixel A Vector containing the position of a pixel in the image. + * @returns A Vector containing the ray direction (the z-component of the vector is always 1). + * @since 3.1.3 + */ +LEAP_EXPORT LEAP_VECTOR LEAP_CALL LeapPixelToRectilinear(LEAP_CONNECTION hConnection, eLeapPerspectiveType camera, LEAP_VECTOR pixel); + +/** \ingroup Functions + * Provides the corrected camera ray intercepting the specified point + * on the image for a particular device. + * + * Given a point on the image, ``LeapPixelToRectilinearEx()`` corrects for camera distortion + * and returns the true direction from the camera to the source of that image point + * within the Devices field of view. + * + * This direction vector has an x and y component [x, y, 1], with the third element + * always 1. Note that this vector uses the 2D camera coordinate system + * where the x-axis parallels the longer (typically horizontal) dimension and + * the y-axis parallels the shorter (vertical) dimension. The camera coordinate + * system does not correlate to the 3D Ultraleap coordinate system. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param hDevice A device handle returned by LeapOpenDevice(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param calibrationType The type of camera calibration to use + * @param pixel A Vector containing the position of a pixel in the image. + * @returns A Vector containing the ray direction (the z-component of the vector is always 1). + * @since 4.1.0 + */ +LEAP_EXPORT LEAP_VECTOR LEAP_CALL LeapPixelToRectilinearEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, eLeapPerspectiveType camera, eLeapCameraCalibrationType calibrationType, LEAP_VECTOR pixel); + +/** \ingroup Functions + * Provides the point in the image corresponding to a ray projecting + * from the camera. + * + * Given a ray projected from the camera in the specified direction, ``LeapRectilinearToPixel()`` + * corrects for camera distortion and returns the corresponding pixel + * coordinates in the image. + * + * The ray direction is specified in relationship to the camera. The first + * vector element is the tangent of the "horizontal" view angle; the second + * element is the tangent of the "vertical" view angle. + * + * The ``LeapRectilinearToPixel()`` function returns pixel coordinates outside of the image bounds + * if you project a ray toward a point for which there is no recorded data. + * + * ``LeapRectilinearToPixel()`` is typically not fast enough for realtime distortion correction. + * For better performance, use a shader program executed on a GPU. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param rectilinear A Vector containing the ray direction. + * @returns A Vector containing the pixel coordinates [x, y, 1] (with z always 1). + * @since 3.1.3 + */ +LEAP_EXPORT LEAP_VECTOR LEAP_CALL LeapRectilinearToPixel(LEAP_CONNECTION hConnection, eLeapPerspectiveType camera, LEAP_VECTOR rectilinear); + +/** \ingroup Functions + * Provides the point in the image corresponding to a ray projecting + * from the camera for a particular device. + * + * Given a ray projected from the camera in the specified direction, ``LeapRectilinearToPixelEx()`` + * corrects for camera distortion and returns the corresponding pixel + * coordinates in the image. + * + * The ray direction is specified in relationship to the camera. The first + * vector element is the tangent of the "horizontal" view angle; the second + * element is the tangent of the "vertical" view angle. + * + * The ``LeapRectilinearToPixelEx()`` function returns pixel coordinates outside of the image bounds + * if you project a ray toward a point for which there is no recorded data. + * + * ``LeapRectilinearToPixelEx()`` is typically not fast enough for realtime distortion correction. + * For better performance, use a shader program executed on a GPU. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param hDevice A device handle returned by LeapOpenDevice(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param calibrationType The type of camera calibration to use + * @param rectilinear A Vector containing the ray direction. + * @returns A Vector containing the pixel coordinates [x, y, 1] (with z always 1). + * @since 4.1.0 + */ +LEAP_EXPORT LEAP_VECTOR LEAP_CALL LeapRectilinearToPixelEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, eLeapPerspectiveType camera, eLeapCameraCalibrationType calibrationType, LEAP_VECTOR rectilinear); + +/** \ingroup Functions + * Returns an OpenCV-compatible camera matrix. + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param[out] dest A pointer to a single-precision float array of size 9 + * @since 3.2.1 + */ +LEAP_EXPORT void LEAP_CALL LeapCameraMatrix(LEAP_CONNECTION hConnection, eLeapPerspectiveType camera, float* dest); + +/** \ingroup Functions + * Returns an OpenCV-compatible camera matrix for a particular device. + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param hDevice A device handle returned by LeapOpenDevice(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param[out] dest A pointer to a single-precision float array of size 9 + * @since 4.1.0 + */ +LEAP_EXPORT void LEAP_CALL LeapCameraMatrixEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, eLeapPerspectiveType camera, float* dest); + +/** \ingroup Functions + * This finds the default device and returns the result LeapExtrinsicCameraMatrixEx() + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param[out] dest A pointer to a single-precision float array of size 16, containing + * the coefficients of the 4x4 matrix in Column Major order + * @since 5.1.0 + */ +LEAP_EXPORT void LEAP_CALL LeapExtrinsicCameraMatrix(LEAP_CONNECTION hConnection, eLeapPerspectiveType camera, float* dest); + +/** \ingroup Functions + * + * Returns a transformation matrix from 3D Leap coordinate space to the coordinate system of the requested camera + * This is composed of a 4 x 4 matrix of the form: + * + * R, t
+ * 0, 1 + * + * R is a 3 x 3 rotation matrix
+ * t is a 3 x 1 translation vector + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param hDevice A device handle returned by LeapOpenDevice(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param[out] dest A pointer to a single-precision float array of size 16, containing + * the coefficients of the 4x4 matrix in Column Major order + * @since 5.1.0 + */ +LEAP_EXPORT void LEAP_CALL LeapExtrinsicCameraMatrixEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, eLeapPerspectiveType camera, float* dest); + +/** \ingroup Functions + * Returns an OpenCV-compatible lens distortion using the 8-parameter rational + * model. + * + * The order of the returned array is: [k1, k2, p1, p2, k3, k4, k5, k6] + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param[out] dest A pointer to a single-precision float array of size 8. + * @since 3.2.1 + */ +LEAP_EXPORT void LEAP_CALL LeapDistortionCoeffs(LEAP_CONNECTION hConnection, eLeapPerspectiveType camera, float* dest); + +/** \ingroup Functions + * Returns an OpenCV-compatible lens distortion for a particular device, using + * the 8-parameter rational model. + * + * The order of the returned array is: [k1, k2, p1, p2, k3, k4, k5, k6] + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param hDevice A device handle returned by LeapOpenDevice(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param[out] dest A pointer to a single-precision float array of size 8. + * @since 4.1.0 + */ +LEAP_EXPORT void LEAP_CALL LeapDistortionCoeffsEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, eLeapPerspectiveType camera, float* dest); + +/** \ingroup Functions + * Provides the human-readable canonical name of the specified device model. + * + * This method is guaranteed to never return null for the LEAP_DEVICE_INFO.pid field + * returned by a successful call to LeapGetDeviceInfo + * + * @param pid The pid of the device + * @returns The string name of the device model, or null if the device type string is invalid. + * + */ +LEAP_EXPORT const char* LEAP_CALL LeapDevicePIDToString(eLeapDevicePID pid); + +LEAP_EXPORT eLeapRS LEAP_CALL LeapGetPointMappingSize(LEAP_CONNECTION hConnection, uint64_t* pSize); +LEAP_EXPORT eLeapRS LEAP_CALL LeapGetPointMapping(LEAP_CONNECTION hConnection, LEAP_POINT_MAPPING* pointMapping, uint64_t* pSize); + +/** \ingroup Enum + * Defines the recording mode provided to the LeapRecordingOpen() + * function. Also used in members of LEAP_RECORDING_PARAMETERS and LEAP_RECORDING_STATUS. + * @since 3.2.0 + */ +typedef enum _eLeapRecordingFlags { + eLeapRecordingFlags_Error = 0x00000000, + eLeapRecordingFlags_Reading = 0x00000001, + eLeapRecordingFlags_Writing = 0x00000002, + eLeapRecordingFlags_Flushing = 0x00000004, + eLeapRecordingFlags_Compressed = 0x00000008 +} eLeapRecordingFlags; +LEAP_STATIC_ASSERT(sizeof(eLeapRecordingFlags) == 4, "Incorrect enum size"); + + +/** \ingroup Structs + * A Leap recording. + * @since 3.2.0 + */ +typedef struct _LEAP_RECORDING *LEAP_RECORDING; + +/** \ingroup Structs + * Read/Write mode for opening a LEAP_RECORDING. + * since 3.2.0 + */ +typedef struct _LEAP_RECORDING_PARAMETERS { + /** A combination of eLeapRecordingFlags indicating the desired operations. @since 3.2.0 */ + uint32_t mode; +} LEAP_RECORDING_PARAMETERS; + +/** \ingroup Structs + * Information about a current LEAP_RECORDING. + * Filled in by a call to LeapRecordingGetStatus(). + * @since 3.2.0 + */ +typedef struct _LEAP_RECORDING_STATUS { + /** Some combination of eLeapRecordingFlags indicating the status of the recording. @since 3.2.0 */ + uint32_t mode; +} LEAP_RECORDING_STATUS; + +/** \ingroup Functions + * Opens or creates a LEAP_RECORDING. + * + * Pass the LEAP_RECORDING pointer to LeapRecordingOpen() to initiate reading from + * or writing to a recording. The recording path is relative to the "user path" + * which is the SD card on Android. + * + * @param ppRecording The recording being opened. + * @param filePath The file path. This will be passed directly to the OS without modification. An ".lmt" suffix is suggested. + * @param params The LEAP_RECORDING_PARAMETERS describing what operations are requested. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.2.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapRecordingOpen(LEAP_RECORDING* ppRecording, const char* filePath, LEAP_RECORDING_PARAMETERS params); + +/** \ingroup Functions + * Closes a LEAP_RECORDING. + * + * @param[out] ppRecording The recording being closed. Will modify *ppRecording to be null. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.2.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapRecordingClose(LEAP_RECORDING* ppRecording); + +/** \ingroup Functions + * Fills in a LEAP_RECORDING_STATUS struct for an open recording. + * This struct provides the applicable eLeapRecordingFlags. + * + * @param pRecording The open recording. + * @param[out] pstatus A LEAP_RECORDING_STATUS struct to receive the recording status. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.2.0 + */ + +LEAP_EXPORT eLeapRS LEAP_CALL LeapRecordingGetStatus(LEAP_RECORDING pRecording, LEAP_RECORDING_STATUS* pstatus); + +/** \ingroup Functions + * Retrieves the number of bytes required to allocate the next frame in a recording. + * + * Use this function to determine the size of the buffer to allocate before calling + * LeapRecordingRead(). + * + * @param pRecording The recording being read from. + * @param[out] pncbEvent A pointer that receives the number of bytes required to store the next frame. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.2.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapRecordingReadSize(LEAP_RECORDING pRecording, uint64_t* pncbEvent); + +/** \ingroup Functions + * Reads a tracking frame from a LEAP_RECORDING file. + * + * Caller is responsible for allocating a buffer large enough to hold the data of the frame. + * Use LeapGetFrameSize() to calculate the minimum size of this buffer. + * + * @param pRecording The recording being read from. + * @param[out] pEvent A pointer to a flat buffer which is filled with the next recorded frame. + * @param ncbEvent The number of bytes pointed to by pEvent. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.2.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapRecordingRead(LEAP_RECORDING pRecording, LEAP_TRACKING_EVENT* pEvent, uint64_t ncbEvent); + +/** \ingroup Functions + * Writes a tracking frame to a LEAP_RECORDING file. + * + * @param pRecording The recording being written to. + * @param[out] pEvent A pointer to a flat buffer which is filled with an interpolated frame. + * @param pnBytesWritten If non-null the number of bytes written. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 3.2.0 + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapRecordingWrite(LEAP_RECORDING pRecording, LEAP_TRACKING_EVENT* pEvent, uint64_t* pnBytesWritten); + +typedef struct _LEAP_TELEMETRY_DATA { + uint32_t thread_id; + uint64_t start_time; + uint64_t end_time; + uint32_t zone_depth; + const char* file_name; + uint32_t line_number; + const char* zone_name; +} LEAP_TELEMETRY_DATA; + +LEAP_EXPORT eLeapRS LEAP_CALL LeapTelemetryProfiling(LEAP_CONNECTION hConnection, const LEAP_TELEMETRY_DATA* telemetryData); + +LEAP_EXPORT uint64_t LEAP_CALL LeapTelemetryGetNow(); + + +/** \ingroup Functions + * This finds the default device and returns the result of LeapScaleOffsetMatrixEx() + * @sa LeapScaleOffsetMatrixEx for additional information + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param[out] dest A pointer to a single-precision float array of size 16, containing + * the coefficients of the 4x4 matrix in Column Major order + * @since 5.x.x + */ +LEAP_EXPORT void LEAP_CALL LeapScaleOffsetMatrix(LEAP_CONNECTION hConnection, eLeapPerspectiveType camera, float* dest); + +/** \ingroup Functions + * + * Returns the appropriate scale and offset coefficients required to project + * normalised Rectilinear coordinates to image-scale coordinates. + * + * This is composed of a 4 x 4 matrix of the form: + * + * scale_x, 0, 0, offset_x, + * 0, 1, 0, 0, + * 0, 0, scale_z, offset_z + * 0, 0, 0, 1 + * + * This matrix is specific to the size of the current image as contained within LEAP_IMAGE. + * + * In practical terms, use this matrix in combination with normalised rays + * to project 3D points into a rectilinear image space (i.e. to visualise hands on an undistorted image). + * + * The pipeline would be: + * 1) Take 3D points from hand tracking. + * 2) Apply an extrinsic transformation to a specific camera's coordinate system (@sa LeapExtrinsicCameraMatrixEx) + * 3) Apply a perspective division to transform 3D points to rays. + * 4) Apply the ScaleOffset matrix to these points. + * + * These points will now be in the correct coordinate system consistent with the undistorted rectilinear image + * provided by LEAP_IMAGE::distortion_matrix. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param hDevice A device handle returned by LeapOpenDevice(). + * @param camera The camera to use, a member of the eLeapPerspectiveType enumeration + * @param[out] dest A pointer to a single-precision float array of size 16, containing + * the coefficients of the 4x4 matrix in Column Major order + * @since 5.x.x + */ +LEAP_EXPORT void LEAP_CALL LeapScaleOffsetMatrixEx(LEAP_CONNECTION hConnection, LEAP_DEVICE hDevice, eLeapPerspectiveType camera, float* dest); + +/** \ingroup Enum + * Defines the parameters used to access version information. + * @since 5.2.x + */ +typedef enum _eLeapVersionPart { + /** + * The parameter for requesting the version of the client. + * @since 5.2.x + */ + eLeapVersionPart_ClientLibrary = 0, + + /** + * The parameter for requesting the protocol version of the client. + * @since 5.2.x + */ + eLeapVersionPart_ClientProtocol = 1, + + /** + * The parameter for requesting the version of the server. + * @since 5.2.x + */ + eLeapVersionPart_ServerLibrary = 2, + + /** + * The parameter for requesting the protocol version of the server. + * @since 5.2.x + */ + eLeapVersionPart_ServerProtocol = 3, +} eLeapVersionPart; +LEAP_STATIC_ASSERT(sizeof(eLeapVersionPart) == 4, "Incorrect enum size"); + + +/** \ingroup Structs + * Version information. + * + * The members can be converted to a version string using the format: + * + * major.minor.patch.build + * + * @since 5.2.0 + */ +typedef struct _LEAP_VERSION { + /** + * The major version. + * @since 5.2.0 + */ + int32_t major; + + /** + * The minor version. + * @since 5.2.0 + */ + int32_t minor; + + /** + * The patch version. + * @since 5.2.0 + */ + int32_t patch; + +} LEAP_VERSION; + +/** \ingroup Functions + * + * Returns the version of a specified part of the system. + * + * If an invalid connection handle is provided only the version details of the client will be available. + * + * @param hConnection The connection handle created by LeapCreateConnection(). + * @param versionPart The version part to return, this will reference one part of the system. + * @param[out] pVersion A pointer to a struct used to store the version number. + * @returns The operation result code, a member of the eLeapRS enumeration. + * @since 5.2.x + */ +LEAP_EXPORT eLeapRS LEAP_CALL LeapGetVersion(LEAP_CONNECTION hConnection, eLeapVersionPart versionPart, LEAP_VERSION* pVersion); + +#ifdef __cplusplus +} +#endif + +#pragma pack() + +#endif diff --git a/vendor/LeapSDK/lib/cmake/LeapSDK/leapsdk-config.cmake b/vendor/LeapSDK/lib/cmake/LeapSDK/leapsdk-config.cmake new file mode 100644 index 00000000..ab21c1f2 --- /dev/null +++ b/vendor/LeapSDK/lib/cmake/LeapSDK/leapsdk-config.cmake @@ -0,0 +1,15 @@ + +####### Expanded from @PACKAGE_INIT@ by configure_package_config_file() ####### +####### Any changes to this file will be overwritten by the next CMake run #### +####### The input file was leapsdk-config.cmake.in ######## + +get_filename_component(PACKAGE_PREFIX_DIR "${CMAKE_CURRENT_LIST_DIR}/../../../" ABSOLUTE) + +#################################################################################### + +if(IS_DIRECTORY ${PACKAGE_PREFIX_DIR}/lib/x64 OR + IS_DIRECTORY ${PACKAGE_PREFIX_DIR}/lib/x86) + set(_arch_folder x64) +endif() + +include(${PACKAGE_PREFIX_DIR}/lib/${_arch_folder}/cmake/LeapCTargets.cmake) diff --git a/vendor/LeapSDK/lib/cmake/LeapSDK/leapsdk-configVersion.cmake b/vendor/LeapSDK/lib/cmake/LeapSDK/leapsdk-configVersion.cmake new file mode 100644 index 00000000..cbdfd651 --- /dev/null +++ b/vendor/LeapSDK/lib/cmake/LeapSDK/leapsdk-configVersion.cmake @@ -0,0 +1,41 @@ +# This is a basic version file for the Config-mode of find_package(). + +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version, +# but only if the requested major version is the same as the current one. + +set(PACKAGE_VERSION "5.3.1") + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + + if("5.3.1" MATCHES "^([0-9]+)\\.") + set(LEAP_VERSION_MAJOR "${CMAKE_MATCH_1}") + else() + set(LEAP_VERSION_MAJOR "5.3.1") + endif() + + if(PACKAGE_FIND_VERSION_MAJOR STREQUAL LEAP_VERSION_MAJOR) + set(PACKAGE_VERSION_COMPATIBLE TRUE) + else() + set(PACKAGE_VERSION_COMPATIBLE FALSE) + endif() + + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() + +# if the project doesn't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching if not on a platform where we package both: +if(NOT WIN32 AND NOT CMAKE_SIZEOF_VOID_P STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/vendor/LeapSDK/lib/x64/LICENSE.protobuf b/vendor/LeapSDK/lib/x64/LICENSE.protobuf new file mode 100644 index 00000000..19b305b0 --- /dev/null +++ b/vendor/LeapSDK/lib/x64/LICENSE.protobuf @@ -0,0 +1,32 @@ +Copyright 2008 Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. diff --git a/vendor/LeapSDK/lib/x64/LeapC.dll b/vendor/LeapSDK/lib/x64/LeapC.dll new file mode 100644 index 00000000..7e559999 Binary files /dev/null and b/vendor/LeapSDK/lib/x64/LeapC.dll differ diff --git a/vendor/LeapSDK/lib/x64/LeapC.lib b/vendor/LeapSDK/lib/x64/LeapC.lib new file mode 100644 index 00000000..dbc2088e Binary files /dev/null and b/vendor/LeapSDK/lib/x64/LeapC.lib differ diff --git a/vendor/LeapSDK/lib/x64/cmake/LeapCTargets-relwithdebinfo.cmake b/vendor/LeapSDK/lib/x64/cmake/LeapCTargets-relwithdebinfo.cmake new file mode 100644 index 00000000..94215969 --- /dev/null +++ b/vendor/LeapSDK/lib/x64/cmake/LeapCTargets-relwithdebinfo.cmake @@ -0,0 +1,19 @@ +#---------------------------------------------------------------- +# Generated CMake target import file for configuration "RelWithDebInfo". +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Import target "LeapSDK::LeapC" for configuration "RelWithDebInfo" +set_property(TARGET LeapSDK::LeapC APPEND PROPERTY IMPORTED_CONFIGURATIONS RELWITHDEBINFO) +set_target_properties(LeapSDK::LeapC PROPERTIES + IMPORTED_IMPLIB_RELWITHDEBINFO "${_IMPORT_PREFIX}/LeapSDK/lib/x64/LeapC.lib" + IMPORTED_LOCATION_RELWITHDEBINFO "${_IMPORT_PREFIX}/LeapSDK/lib/x64/LeapC.dll" + ) + +list(APPEND _IMPORT_CHECK_TARGETS LeapSDK::LeapC ) +list(APPEND _IMPORT_CHECK_FILES_FOR_LeapSDK::LeapC "${_IMPORT_PREFIX}/LeapSDK/lib/x64/LeapC.lib" "${_IMPORT_PREFIX}/LeapSDK/lib/x64/LeapC.dll" ) + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) diff --git a/vendor/LeapSDK/lib/x64/cmake/LeapCTargets.cmake b/vendor/LeapSDK/lib/x64/cmake/LeapCTargets.cmake new file mode 100644 index 00000000..a379a73d --- /dev/null +++ b/vendor/LeapSDK/lib/x64/cmake/LeapCTargets.cmake @@ -0,0 +1,95 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) + message(FATAL_ERROR "CMake >= 2.6.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.6...3.17) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_targetsDefined) +set(_targetsNotDefined) +set(_expectedTargets) +foreach(_expectedTarget LeapSDK::LeapC) + list(APPEND _expectedTargets ${_expectedTarget}) + if(NOT TARGET ${_expectedTarget}) + list(APPEND _targetsNotDefined ${_expectedTarget}) + endif() + if(TARGET ${_expectedTarget}) + list(APPEND _targetsDefined ${_expectedTarget}) + endif() +endforeach() +if("${_targetsDefined}" STREQUAL "${_expectedTargets}") + unset(_targetsDefined) + unset(_targetsNotDefined) + unset(_expectedTargets) + set(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT "${_targetsDefined}" STREQUAL "") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") +endif() +unset(_targetsDefined) +unset(_targetsNotDefined) +unset(_expectedTargets) + + +# Compute the installation prefix relative to this file. +get_filename_component(_IMPORT_PREFIX "${CMAKE_CURRENT_LIST_FILE}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +get_filename_component(_IMPORT_PREFIX "${_IMPORT_PREFIX}" PATH) +if(_IMPORT_PREFIX STREQUAL "/") + set(_IMPORT_PREFIX "") +endif() + +# Create imported target LeapSDK::LeapC +add_library(LeapSDK::LeapC SHARED IMPORTED) + +set_target_properties(LeapSDK::LeapC PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${_IMPORT_PREFIX}/LeapSDK/include" +) + +# Load information for each installed configuration. +get_filename_component(_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +file(GLOB CONFIG_FILES "${_DIR}/LeapCTargets-*.cmake") +foreach(f ${CONFIG_FILES}) + include(${f}) +endforeach() + +# Cleanup temporary variables. +set(_IMPORT_PREFIX) + +# Loop over all imported files and verify that they actually exist +foreach(target ${_IMPORT_CHECK_TARGETS} ) + foreach(file ${_IMPORT_CHECK_FILES_FOR_${target}} ) + if(NOT EXISTS "${file}" ) + message(FATAL_ERROR "The imported target \"${target}\" references the file + \"${file}\" +but this file does not exist. Possible reasons include: +* The file was deleted, renamed, or moved to another location. +* An install or uninstall procedure did not complete successfully. +* The installation package was faulty and contained + \"${CMAKE_CURRENT_LIST_FILE}\" +but not all the files it references. +") + endif() + endforeach() + unset(_IMPORT_CHECK_FILES_FOR_${target}) +endforeach() +unset(_IMPORT_CHECK_TARGETS) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/vendor/LeapSDK/samples/CMakeLists.txt b/vendor/LeapSDK/samples/CMakeLists.txt new file mode 100644 index 00000000..3e094b05 --- /dev/null +++ b/vendor/LeapSDK/samples/CMakeLists.txt @@ -0,0 +1,71 @@ +cmake_minimum_required(VERSION 3.16.3) + +project(leapc_example VERSION "1.0.0" LANGUAGES C) + +set(ULTRALEAP_PATH_ROOT "$ENV{ProgramFiles}/Ultraleap") + +find_package(LeapSDK + 5 + REQUIRED + PATHS + "${ULTRALEAP_PATH_ROOT}") + +add_executable( + leapc_example + "leapc_main.c") + +target_link_libraries( + leapc_example + PRIVATE + LeapSDK::LeapC) + +get_target_property( + LEAPC_IMPORTED_CONFIG + LeapSDK::LeapC + IMPORTED_CONFIGURATIONS +) + +get_target_property( + LEAPC_SHARED_LIB_PATH + LeapSDK::LeapC + IMPORTED_LOCATION_${LEAPC_IMPORTED_CONFIG} +) + +add_custom_command( + TARGET + leapc_example + POST_BUILD + COMMAND + ${CMAKE_COMMAND} -E copy + ${LEAPC_SHARED_LIB_PATH} + $) + +add_library( + libExampleConnection + OBJECT + "ExampleConnection.c") + +target_link_libraries( + libExampleConnection + PUBLIC + LeapSDK::LeapC) + +target_include_directories( + libExampleConnection + PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR}) + +# Add targets for each sample file. +function(add_sample sample_name sample_source_file) + + add_executable(${sample_name} ${sample_source_file}) + set_property(TARGET ${sample_name} PROPERTY FOLDER "Samples") + target_link_libraries(${sample_name} PUBLIC libExampleConnection) + +endfunction() + + +add_sample("CallbackSample" "CallbackSample.c") +add_sample("ImageSample" "ImageSample.c") +add_sample("PollingSample" "PollingSample.c") +add_sample("InterpolationSample" "InterpolationSample.c") diff --git a/vendor/LeapSDK/samples/CallbackSample.c b/vendor/LeapSDK/samples/CallbackSample.c new file mode 100644 index 00000000..bad31102 --- /dev/null +++ b/vendor/LeapSDK/samples/CallbackSample.c @@ -0,0 +1,146 @@ +/* Copyright (C) 2012-2017 Ultraleap Limited. All rights reserved. + * + * Use of this code is subject to the terms of the Ultraleap SDK agreement + * available at https://central.leapmotion.com/agreements/SdkAgreement unless + * Ultraleap has signed a separate license agreement with you or your + * organisation. + * + */ + +#include +#include +#include "LeapC.h" +#include "ExampleConnection.h" + +static LEAP_CONNECTION* connectionHandle; + +/** Callback for when the connection opens. */ +static void OnConnect(){ + printf("Connected.\n"); +} + +/** Callback for when a device is found. */ +static void OnDevice(const LEAP_DEVICE_INFO *props){ + printf("Found device %s.\n", props->serial); +} + +/** Callback for when a frame of tracking data is available. */ +static void OnFrame(const LEAP_TRACKING_EVENT *frame){ + if (frame->info.frame_id % 60 == 0) + printf("Frame %lli with %i hands.\n", (long long int)frame->info.frame_id, frame->nHands); + + for(uint32_t h = 0; h < frame->nHands; h++){ + LEAP_HAND* hand = &frame->pHands[h]; + printf(" Hand id %i is a %s hand with position (%f, %f, %f).\n", + hand->id, + (hand->type == eLeapHandType_Left ? "left" : "right"), + hand->palm.position.x, + hand->palm.position.y, + hand->palm.position.z); + } +} + +static void OnImage(const LEAP_IMAGE_EVENT *image){ + printf("Image %lli => Left: %d x %d (bpp=%d), Right: %d x %d (bpp=%d)\n", + (long long int)image->info.frame_id, + image->image[0].properties.width,image->image[0].properties.height,image->image[0].properties.bpp*8, + image->image[1].properties.width,image->image[1].properties.height,image->image[1].properties.bpp*8); +} + +static void OnLogMessage(const eLeapLogSeverity severity, const int64_t timestamp, + const char* message) { + const char* severity_str; + switch(severity) { + case eLeapLogSeverity_Critical: + severity_str = "Critical"; + break; + case eLeapLogSeverity_Warning: + severity_str = "Warning"; + break; + case eLeapLogSeverity_Information: + severity_str = "Info"; + break; + default: + severity_str = ""; + break; + } + printf("[%s][%lli] %s\n", severity_str, (long long int)timestamp, message); +} + +static void* allocate(uint32_t size, eLeapAllocatorType typeHint, void* state) { + void* ptr = malloc(size); + return ptr; +} + +static void deallocate(void* ptr, void* state) { + if (!ptr) + return; + free(ptr); +} + +void OnPointMappingChange(const LEAP_POINT_MAPPING_CHANGE_EVENT *change){ + if (!connectionHandle) + return; + + uint64_t size = 0; + if (LeapGetPointMappingSize(*connectionHandle, &size) != eLeapRS_Success || !size) + return; + + LEAP_POINT_MAPPING* pointMapping = (LEAP_POINT_MAPPING*)malloc((size_t)size); + if (!pointMapping) + return; + + if (LeapGetPointMapping(*connectionHandle, pointMapping, &size) == eLeapRS_Success && + pointMapping->nPoints > 0) { + printf("Managing %u points as of frame %lld at %lld\n", pointMapping->nPoints, (long long int)pointMapping->frame_id, (long long int)pointMapping->timestamp); + } + free(pointMapping); +} + +void OnHeadPose(const LEAP_HEAD_POSE_EVENT *event) { + printf("Head pose:\n"); + printf(" Head position (%f, %f, %f).\n", + event->head_position.x, + event->head_position.y, + event->head_position.z); + printf(" Head orientation (%f, %f, %f, %f).\n", + event->head_orientation.w, + event->head_orientation.x, + event->head_orientation.y, + event->head_orientation.z); + printf(" Head linear velocity (%f, %f, %f).\n", + event->head_linear_velocity.x, + event->head_linear_velocity.y, + event->head_linear_velocity.z); + printf(" Head angular velocity (%f, %f, %f).\n", + event->head_angular_velocity.x, + event->head_angular_velocity.y, + event->head_angular_velocity.z); + } + +int main(int argc, char** argv) { + //Set callback function pointers + ConnectionCallbacks.on_connection = &OnConnect; + ConnectionCallbacks.on_device_found = &OnDevice; + ConnectionCallbacks.on_frame = &OnFrame; + ConnectionCallbacks.on_image = &OnImage; + ConnectionCallbacks.on_point_mapping_change = &OnPointMappingChange; + ConnectionCallbacks.on_log_message = &OnLogMessage; + ConnectionCallbacks.on_head_pose = &OnHeadPose; + + connectionHandle = OpenConnection(); + { + LEAP_ALLOCATOR allocator = { allocate, deallocate, NULL }; + LeapSetAllocator(*connectionHandle, &allocator); + } + LeapSetPolicyFlags(*connectionHandle, eLeapPolicyFlag_Images | eLeapPolicyFlag_MapPoints, 0); + + printf("Press Enter to exit program.\n"); + getchar(); + + CloseConnection(); + DestroyConnection(); + + return 0; +} +//End-of-Sample diff --git a/vendor/LeapSDK/samples/ExampleConnection.c b/vendor/LeapSDK/samples/ExampleConnection.c new file mode 100644 index 00000000..714b42fc --- /dev/null +++ b/vendor/LeapSDK/samples/ExampleConnection.c @@ -0,0 +1,411 @@ +/* Copyright (C) 2012-2017 Ultraleap Limited. All rights reserved. + * + * Use of this code is subject to the terms of the Ultraleap SDK agreement + * available at https://central.leapmotion.com/agreements/SdkAgreement unless + * Ultraleap has signed a separate license agreement with you or your + * organisation. + * + */ + +#include "ExampleConnection.h" +#include +#include +#include +#if defined(_MSC_VER) + #include + #include + #define LockMutex EnterCriticalSection + #define UnlockMutex LeaveCriticalSection +#else + #include + #include + #define LockMutex pthread_mutex_lock + #define UnlockMutex pthread_mutex_unlock +#endif + + +//Forward declarations +#if defined(_MSC_VER) +static void serviceMessageLoop(void * unused); +#else +static void* serviceMessageLoop(void * unused); +#endif +static void setFrame(const LEAP_TRACKING_EVENT *frame); +static void setDevice(const LEAP_DEVICE_INFO *deviceProps); + +//External state +bool IsConnected = false; + +//Internal state +static volatile bool _isRunning = false; +static LEAP_CONNECTION connectionHandle = NULL; +static LEAP_TRACKING_EVENT *lastFrame = NULL; +static LEAP_DEVICE_INFO *lastDevice = NULL; + +//Callback function pointers +struct Callbacks ConnectionCallbacks; + +//Threading variables +#if defined(_MSC_VER) +static HANDLE pollingThread; +static CRITICAL_SECTION dataLock; +#else +static pthread_t pollingThread; +static pthread_mutex_t dataLock; +#endif + +/** + * Creates the connection handle and opens a connection to the Leap Motion + * service. On success, creates a thread to service the LeapC message pump. + */ +LEAP_CONNECTION* OpenConnection(){ + if(_isRunning){ + return &connectionHandle; + } + if(connectionHandle || LeapCreateConnection(NULL, &connectionHandle) == eLeapRS_Success){ + eLeapRS result = LeapOpenConnection(connectionHandle); + if(result == eLeapRS_Success){ + _isRunning = true; +#if defined(_MSC_VER) + InitializeCriticalSection(&dataLock); + pollingThread = (HANDLE)_beginthread(serviceMessageLoop, 0, NULL); +#else + pthread_mutex_init(&dataLock, NULL); + pthread_create(&pollingThread, NULL, serviceMessageLoop, NULL); +#endif + } + } + return &connectionHandle; +} + +void CloseConnection(){ + if(!_isRunning){ + return; + } + _isRunning = false; + LeapCloseConnection(connectionHandle); +#if defined(_MSC_VER) + WaitForSingleObject(pollingThread, INFINITE); + CloseHandle(pollingThread); +#else + pthread_join(pollingThread, NULL); + pthread_mutex_destroy(&dataLock); +#endif +} + +void DestroyConnection(){ + CloseConnection(); + LeapDestroyConnection(connectionHandle); +} + + +/** Close the connection and let message thread function end. */ +void CloseConnectionHandle(LEAP_CONNECTION* connectionHandle){ + LeapDestroyConnection(*connectionHandle); + _isRunning = false; +} + +/** Called by serviceMessageLoop() when a connection event is returned by LeapPollConnection(). */ +static void handleConnectionEvent(const LEAP_CONNECTION_EVENT *connection_event){ + IsConnected = true; + if(ConnectionCallbacks.on_connection){ + ConnectionCallbacks.on_connection(); + } +} + +/** Called by serviceMessageLoop() when a connection lost event is returned by LeapPollConnection(). */ +static void handleConnectionLostEvent(const LEAP_CONNECTION_LOST_EVENT *connection_lost_event){ + IsConnected = false; + if(ConnectionCallbacks.on_connection_lost){ + ConnectionCallbacks.on_connection_lost(); + } +} + +/** + * Called by serviceMessageLoop() when a device event is returned by LeapPollConnection() + * Demonstrates how to access device properties. + */ +static void handleDeviceEvent(const LEAP_DEVICE_EVENT *device_event){ + LEAP_DEVICE deviceHandle; + //Open device using LEAP_DEVICE_REF from event struct. + eLeapRS result = LeapOpenDevice(device_event->device, &deviceHandle); + if(result != eLeapRS_Success){ + printf("Could not open device %s.\n", ResultString(result)); + return; + } + + //Create a struct to hold the device properties, we have to provide a buffer for the serial string + LEAP_DEVICE_INFO deviceProperties = { sizeof(deviceProperties) }; + // Start with a length of 1 (pretending we don't know a priori what the length is). + // Currently device serial numbers are all the same length, but that could change in the future + deviceProperties.serial_length = 1; + deviceProperties.serial = malloc(deviceProperties.serial_length); + //This will fail since the serial buffer is only 1 character long + // But deviceProperties is updated to contain the required buffer length + result = LeapGetDeviceInfo(deviceHandle, &deviceProperties); + if(result == eLeapRS_InsufficientBuffer){ + //try again with correct buffer size + deviceProperties.serial = realloc(deviceProperties.serial, deviceProperties.serial_length); + result = LeapGetDeviceInfo(deviceHandle, &deviceProperties); + if(result != eLeapRS_Success){ + printf("Failed to get device info %s.\n", ResultString(result)); + free(deviceProperties.serial); + return; + } + } + setDevice(&deviceProperties); + if(ConnectionCallbacks.on_device_found){ + ConnectionCallbacks.on_device_found(&deviceProperties); + } + + free(deviceProperties.serial); + LeapCloseDevice(deviceHandle); +} + +/** Called by serviceMessageLoop() when a device lost event is returned by LeapPollConnection(). */ +static void handleDeviceLostEvent(const LEAP_DEVICE_EVENT *device_event){ + if(ConnectionCallbacks.on_device_lost){ + ConnectionCallbacks.on_device_lost(); + } +} + +/** Called by serviceMessageLoop() when a device failure event is returned by LeapPollConnection(). */ +static void handleDeviceFailureEvent(const LEAP_DEVICE_FAILURE_EVENT *device_failure_event){ + if(ConnectionCallbacks.on_device_failure){ + ConnectionCallbacks.on_device_failure(device_failure_event->status, device_failure_event->hDevice); + } +} + +/** Called by serviceMessageLoop() when a tracking event is returned by LeapPollConnection(). */ +static void handleTrackingEvent(const LEAP_TRACKING_EVENT *tracking_event){ + setFrame(tracking_event); //support polling tracking data from different thread + if(ConnectionCallbacks.on_frame){ + ConnectionCallbacks.on_frame(tracking_event); + } +} + +/** Called by serviceMessageLoop() when a log event is returned by LeapPollConnection(). */ +static void handleLogEvent(const LEAP_LOG_EVENT *log_event){ + if(ConnectionCallbacks.on_log_message){ + ConnectionCallbacks.on_log_message(log_event->severity, log_event->timestamp, log_event->message); + } +} + +/** Called by serviceMessageLoop() when a log event is returned by LeapPollConnection(). */ +static void handleLogEvents(const LEAP_LOG_EVENTS *log_events){ + if(ConnectionCallbacks.on_log_message){ + for (int i = 0; i < (int)(log_events->nEvents); i++) { + const LEAP_LOG_EVENT* log_event = &log_events->events[i]; + ConnectionCallbacks.on_log_message(log_event->severity, log_event->timestamp, log_event->message); + } + } +} + +/** Called by serviceMessageLoop() when a policy event is returned by LeapPollConnection(). */ +static void handlePolicyEvent(const LEAP_POLICY_EVENT *policy_event){ + if(ConnectionCallbacks.on_policy){ + ConnectionCallbacks.on_policy(policy_event->current_policy); + } +} + +/** Called by serviceMessageLoop() when a config change event is returned by LeapPollConnection(). */ +static void handleConfigChangeEvent(const LEAP_CONFIG_CHANGE_EVENT *config_change_event){ + if(ConnectionCallbacks.on_config_change){ + ConnectionCallbacks.on_config_change(config_change_event->requestID, config_change_event->status); + } +} + +/** Called by serviceMessageLoop() when a config response event is returned by LeapPollConnection(). */ +static void handleConfigResponseEvent(const LEAP_CONFIG_RESPONSE_EVENT *config_response_event){ + if(ConnectionCallbacks.on_config_response){ + ConnectionCallbacks.on_config_response(config_response_event->requestID, config_response_event->value); + } +} + +/** Called by serviceMessageLoop() when a point mapping change event is returned by LeapPollConnection(). */ +static void handleImageEvent(const LEAP_IMAGE_EVENT *image_event) { + if(ConnectionCallbacks.on_image){ + ConnectionCallbacks.on_image(image_event); + } +} + +/** Called by serviceMessageLoop() when a point mapping change event is returned by LeapPollConnection(). */ +static void handlePointMappingChangeEvent(const LEAP_POINT_MAPPING_CHANGE_EVENT *point_mapping_change_event) { + if(ConnectionCallbacks.on_point_mapping_change){ + ConnectionCallbacks.on_point_mapping_change(point_mapping_change_event); + } +} + +/** Called by serviceMessageLoop() when a point mapping change event is returned by LeapPollConnection(). */ +static void handleHeadPoseEvent(const LEAP_HEAD_POSE_EVENT *head_pose_event) { + if(ConnectionCallbacks.on_head_pose){ + ConnectionCallbacks.on_head_pose(head_pose_event); + } +} + +/** + * Services the LeapC message pump by calling LeapPollConnection(). + * The average polling time is determined by the framerate of the Ultraleap Tracking service. + */ +#if defined(_MSC_VER) +static void serviceMessageLoop(void * unused){ +#else +static void* serviceMessageLoop(void * unused){ +#endif + eLeapRS result; + LEAP_CONNECTION_MESSAGE msg; + while(_isRunning){ + unsigned int timeout = 1000; + result = LeapPollConnection(connectionHandle, timeout, &msg); + + if(result != eLeapRS_Success){ + printf("LeapC PollConnection call was %s.\n", ResultString(result)); + continue; + } + + switch (msg.type){ + case eLeapEventType_Connection: + handleConnectionEvent(msg.connection_event); + break; + case eLeapEventType_ConnectionLost: + handleConnectionLostEvent(msg.connection_lost_event); + break; + case eLeapEventType_Device: + handleDeviceEvent(msg.device_event); + break; + case eLeapEventType_DeviceLost: + handleDeviceLostEvent(msg.device_event); + break; + case eLeapEventType_DeviceFailure: + handleDeviceFailureEvent(msg.device_failure_event); + break; + case eLeapEventType_Tracking: + handleTrackingEvent(msg.tracking_event); + break; + case eLeapEventType_ImageComplete: + // Ignore + break; + case eLeapEventType_ImageRequestError: + // Ignore + break; + case eLeapEventType_LogEvent: + handleLogEvent(msg.log_event); + break; + case eLeapEventType_Policy: + handlePolicyEvent(msg.policy_event); + break; + case eLeapEventType_ConfigChange: + handleConfigChangeEvent(msg.config_change_event); + break; + case eLeapEventType_ConfigResponse: + handleConfigResponseEvent(msg.config_response_event); + break; + case eLeapEventType_Image: + handleImageEvent(msg.image_event); + break; + case eLeapEventType_PointMappingChange: + handlePointMappingChangeEvent(msg.point_mapping_change_event); + break; + case eLeapEventType_LogEvents: + handleLogEvents(msg.log_events); + break; + case eLeapEventType_HeadPose: + handleHeadPoseEvent(msg.head_pose_event); + break; + default: + //discard unknown message types + printf("Unhandled message type %i.\n", msg.type); + } //switch on msg.type + } +#if !defined(_MSC_VER) + return NULL; +#endif +} + +/* Used in Polling Example: */ + +/** + * Caches the newest frame by copying the tracking event struct returned by + * LeapC. + */ +void setFrame(const LEAP_TRACKING_EVENT *frame){ + LockMutex(&dataLock); + if(!lastFrame) lastFrame = malloc(sizeof(*frame)); + *lastFrame = *frame; + UnlockMutex(&dataLock); +} + +/** Returns a pointer to the cached tracking frame. */ +LEAP_TRACKING_EVENT* GetFrame(){ + LEAP_TRACKING_EVENT *currentFrame; + + LockMutex(&dataLock); + currentFrame = lastFrame; + UnlockMutex(&dataLock); + + return currentFrame; +} + +/** + * Caches the last device found by copying the device info struct returned by + * LeapC. + */ +static void setDevice(const LEAP_DEVICE_INFO *deviceProps){ + LockMutex(&dataLock); + if(lastDevice){ + free(lastDevice->serial); + } else { + lastDevice = malloc(sizeof(*deviceProps)); + } + *lastDevice = *deviceProps; + lastDevice->serial = malloc(deviceProps->serial_length); + memcpy(lastDevice->serial, deviceProps->serial, deviceProps->serial_length); + UnlockMutex(&dataLock); +} + +/** Returns a pointer to the cached device info. */ +LEAP_DEVICE_INFO* GetDeviceProperties(){ + LEAP_DEVICE_INFO *currentDevice; + LockMutex(&dataLock); + currentDevice = lastDevice; + UnlockMutex(&dataLock); + return currentDevice; +} + +//End of polling example-specific code + +/** Translates eLeapRS result codes into a human-readable string. */ +const char* ResultString(eLeapRS r) { + switch(r){ + case eLeapRS_Success: return "eLeapRS_Success"; + case eLeapRS_UnknownError: return "eLeapRS_UnknownError"; + case eLeapRS_InvalidArgument: return "eLeapRS_InvalidArgument"; + case eLeapRS_InsufficientResources: return "eLeapRS_InsufficientResources"; + case eLeapRS_InsufficientBuffer: return "eLeapRS_InsufficientBuffer"; + case eLeapRS_Timeout: return "eLeapRS_Timeout"; + case eLeapRS_NotConnected: return "eLeapRS_NotConnected"; + case eLeapRS_HandshakeIncomplete: return "eLeapRS_HandshakeIncomplete"; + case eLeapRS_BufferSizeOverflow: return "eLeapRS_BufferSizeOverflow"; + case eLeapRS_ProtocolError: return "eLeapRS_ProtocolError"; + case eLeapRS_InvalidClientID: return "eLeapRS_InvalidClientID"; + case eLeapRS_UnexpectedClosed: return "eLeapRS_UnexpectedClosed"; + case eLeapRS_UnknownImageFrameRequest: return "eLeapRS_UnknownImageFrameRequest"; + case eLeapRS_UnknownTrackingFrameID: return "eLeapRS_UnknownTrackingFrameID"; + case eLeapRS_RoutineIsNotSeer: return "eLeapRS_RoutineIsNotSeer"; + case eLeapRS_TimestampTooEarly: return "eLeapRS_TimestampTooEarly"; + case eLeapRS_ConcurrentPoll: return "eLeapRS_ConcurrentPoll"; + case eLeapRS_NotAvailable: return "eLeapRS_NotAvailable"; + case eLeapRS_NotStreaming: return "eLeapRS_NotStreaming"; + case eLeapRS_CannotOpenDevice: return "eLeapRS_CannotOpenDevice"; + default: return "unknown result type."; + } +} +/** Cross-platform sleep function */ +void millisleep(int milliseconds){ +#ifdef _WIN32 + Sleep(milliseconds); +#else + usleep(milliseconds*1000); +#endif + } +//End-of-ExampleConnection.c diff --git a/vendor/LeapSDK/samples/ExampleConnection.h b/vendor/LeapSDK/samples/ExampleConnection.h new file mode 100644 index 00000000..ca1f99c8 --- /dev/null +++ b/vendor/LeapSDK/samples/ExampleConnection.h @@ -0,0 +1,60 @@ +/* Copyright (C) 2012-2017 Ultraleap Limited. All rights reserved. + * + * Use of this code is subject to the terms of the Ultraleap SDK agreement + * available at https://central.leapmotion.com/agreements/SdkAgreement unless + * Ultraleap has signed a separate license agreement with you or your + * organisation. + * + */ + +#ifndef ExampleConnection_h +#define ExampleConnection_h + +#include "LeapC.h" + +/* Client functions */ +LEAP_CONNECTION* OpenConnection(); +void CloseConnection(); +void DestroyConnection(); +LEAP_TRACKING_EVENT* GetFrame(); //Used in polling example +LEAP_DEVICE_INFO* GetDeviceProperties(); //Used in polling example +const char* ResultString(eLeapRS r); + +/* State */ +extern bool IsConnected; + +/* Callback function pointers */ +typedef void (*connection_callback) (); +typedef void (*device_callback) (const LEAP_DEVICE_INFO *device); +typedef void (*device_lost_callback) (); +typedef void (*device_failure_callback) (const eLeapDeviceStatus failure_code, + const LEAP_DEVICE failed_device); +typedef void (*policy_callback) (const uint32_t current_policies); +typedef void (*tracking_callback) (const LEAP_TRACKING_EVENT *tracking_event); +typedef void (*log_callback) (const eLeapLogSeverity severity, + const int64_t timestamp, + const char* message); +typedef void (*config_change_callback) (const uint32_t requestID, const bool success); +typedef void (*config_response_callback)(const uint32_t requestID, LEAP_VARIANT value); +typedef void (*image_callback) (const LEAP_IMAGE_EVENT *image_event); +typedef void (*point_mapping_change_callback)(const LEAP_POINT_MAPPING_CHANGE_EVENT *point_mapping_change_event); +typedef void (*head_pose_callback)(const LEAP_HEAD_POSE_EVENT *head_pose_event); + +struct Callbacks{ + connection_callback on_connection; + connection_callback on_connection_lost; + device_callback on_device_found; + device_lost_callback on_device_lost; + device_failure_callback on_device_failure; + policy_callback on_policy; + tracking_callback on_frame; + log_callback on_log_message; + config_change_callback on_config_change; + config_response_callback on_config_response; + image_callback on_image; + point_mapping_change_callback on_point_mapping_change; + head_pose_callback on_head_pose; +}; +extern struct Callbacks ConnectionCallbacks; +extern void millisleep(int milliseconds); +#endif /* ExampleConnection_h */ diff --git a/vendor/LeapSDK/samples/ImageSample.c b/vendor/LeapSDK/samples/ImageSample.c new file mode 100644 index 00000000..47910adc --- /dev/null +++ b/vendor/LeapSDK/samples/ImageSample.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2012-2017 Ultraleap Limited. All rights reserved. + * + * Use of this code is subject to the terms of the Ultraleap SDK agreement + * available at https://central.leapmotion.com/agreements/SdkAgreement unless + * Ultraleap has signed a separate license agreement with you or your + * organisation. + * + */ + +#include +#include +#include "LeapC.h" +#include "ExampleConnection.h" + +/** Callback for when the connection opens. */ +static void OnConnect(){ + printf("Connected.\n"); +} + +/** Callback for when a device is found. */ +static void OnDevice(const LEAP_DEVICE_INFO *props){ + printf("Found device %s.\n", props->serial); +} + +/** Callback for when a frame of tracking data is available. */ +static void OnFrame(const LEAP_TRACKING_EVENT *frame){ + printf("Frame %lli with %i hands.\n", (long long int)frame->info.frame_id, frame->nHands); + for(uint32_t h = 0; h < frame->nHands; h++){ + LEAP_HAND* hand = &frame->pHands[h]; + printf(" Hand id %i is a %s hand with position (%f, %f, %f).\n", + hand->id, + (hand->type == eLeapHandType_Left ? "left" : "right"), + hand->palm.position.x, + hand->palm.position.y, + hand->palm.position.z); + } +} + +/** Callback for when an image is available. */ +static void OnImage(const LEAP_IMAGE_EVENT *imageEvent){ + printf("Received image set for frame %lli with size %lli.\n", + (long long int)imageEvent->info.frame_id, + (long long int)imageEvent->image[0].properties.width* + (long long int)imageEvent->image[0].properties.height*2); +} + +int main(int argc, char** argv) { + //Set callback function pointers + ConnectionCallbacks.on_connection = &OnConnect; + ConnectionCallbacks.on_device_found = &OnDevice; + ConnectionCallbacks.on_frame = &OnFrame; + ConnectionCallbacks.on_image = &OnImage; + + LEAP_CONNECTION *connection = OpenConnection(); + LeapSetPolicyFlags(*connection, eLeapPolicyFlag_Images, 0); + + printf("Press Enter to exit program.\n"); + getchar(); + return 0; +} +//End-of-Sample diff --git a/vendor/LeapSDK/samples/InterpolationSample.c b/vendor/LeapSDK/samples/InterpolationSample.c new file mode 100644 index 00000000..d7f36b18 --- /dev/null +++ b/vendor/LeapSDK/samples/InterpolationSample.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2012-2017 Ultraleap Limited. All rights reserved. + * + * Use of this code is subject to the terms of the Ultraleap SDK agreement + * available at https://central.leapmotion.com/agreements/SdkAgreement unless + * Ultraleap has signed a separate license agreement with you or your + * organisation. + * + */ + +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include +#include "LeapC.h" +#include "ExampleConnection.h" + +LEAP_CLOCK_REBASER clockSynchronizer; + +int main(int argc, char** argv) { + LEAP_CONNECTION* connHandle = OpenConnection(); + + while(!IsConnected){ + millisleep(250); + } + + printf("Connected.\n"); + //Create the clock synchronizer + LeapCreateClockRebaser(&clockSynchronizer); + clock_t cpuTime; + int64_t targetFrameTime = 0; + uint64_t targetFrameSize = 0; + eLeapRS result; + for(;;){ + //Calculate the application time + cpuTime = (clock_t).000001 * clock()/CLOCKS_PER_SEC;//microseconds + //Synchronize the clocks + LeapUpdateRebase(clockSynchronizer, cpuTime, LeapGetNow()); + + //Simulate delay (i.e. processing load, v-sync, etc) + millisleep(10); + + //Now get the updated application time + cpuTime = (clock_t) .000001 * clock()/CLOCKS_PER_SEC; + + //Translate application time to Leap time + LeapRebaseClock(clockSynchronizer, cpuTime, &targetFrameTime); + + //Get the buffer size needed to hold the tracking data + result = LeapGetFrameSize(*connHandle, targetFrameTime, &targetFrameSize); + if(result == eLeapRS_Success){ + //Allocate enough memory + LEAP_TRACKING_EVENT* interpolatedFrame = malloc((size_t)targetFrameSize); + //Get the frame + result = LeapInterpolateFrame(*connHandle, targetFrameTime, interpolatedFrame, targetFrameSize); + if(result == eLeapRS_Success){ + //Use the data... + printf("Frame %lli with %i hands with delay of %lli microseconds.\n", + (long long int)interpolatedFrame->tracking_frame_id, + interpolatedFrame->nHands, + (long long int)LeapGetNow() - interpolatedFrame->info.timestamp); + for(uint32_t h = 0; h < interpolatedFrame->nHands; h++){ + LEAP_HAND* hand = &interpolatedFrame->pHands[h]; + printf(" Hand id %i is a %s hand with position (%f, %f, %f).\n", + hand->id, + (hand->type == eLeapHandType_Left ? "left" : "right"), + hand->palm.position.x, + hand->palm.position.y, + hand->palm.position.z); + } + //Free the allocated buffer when done. + free(interpolatedFrame); + } + else { + printf("LeapInterpolateFrame() result was %s.\n", ResultString(result)); + } + } + else { + printf("LeapGetFrameSize() result was %s.\n", ResultString(result)); + } + } //ctrl-c to exit + return 0; +} +//End-of-Sample diff --git a/vendor/LeapSDK/samples/PollingSample.c b/vendor/LeapSDK/samples/PollingSample.c new file mode 100644 index 00000000..3d739069 --- /dev/null +++ b/vendor/LeapSDK/samples/PollingSample.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2012-2017 Ultraleap Limited. All rights reserved. + * + * Use of this code is subject to the terms of the Ultraleap SDK agreement + * available at https://central.leapmotion.com/agreements/SdkAgreement unless + * Ultraleap has signed a separate license agreement with you or your + * organisation. + * + */ + +#include +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "LeapC.h" +#include "ExampleConnection.h" + +int64_t lastFrameID = 0; //The last frame received + +int main(int argc, char** argv) { + OpenConnection(); + while(!IsConnected) + millisleep(100); //wait a bit to let the connection complete + + printf("Connected."); + LEAP_DEVICE_INFO* deviceProps = GetDeviceProperties(); + if(deviceProps) + printf("Using device %s.\n", deviceProps->serial); + + for(;;){ + LEAP_TRACKING_EVENT *frame = GetFrame(); + if(frame && (frame->tracking_frame_id > lastFrameID)){ + lastFrameID = frame->tracking_frame_id; + printf("Frame %lli with %i hands.\n", (long long int)frame->tracking_frame_id, frame->nHands); + for(uint32_t h = 0; h < frame->nHands; h++){ + LEAP_HAND* hand = &frame->pHands[h]; + printf(" Hand id %i is a %s hand with position (%f, %f, %f).\n", + hand->id, + (hand->type == eLeapHandType_Left ? "left" : "right"), + hand->palm.position.x, + hand->palm.position.y, + hand->palm.position.z); + } + } + } //ctrl-c to exit + return 0; +} +//End-of-Sample diff --git a/vendor/LeapSDK/samples/RecordPlaybackSample.c b/vendor/LeapSDK/samples/RecordPlaybackSample.c new file mode 100644 index 00000000..5f038e4b --- /dev/null +++ b/vendor/LeapSDK/samples/RecordPlaybackSample.c @@ -0,0 +1,89 @@ +/* Copyright (C) 2012-2017 Ultraleap Limited. All rights reserved. + * + * Use of this code is subject to the terms of the Ultraleap SDK agreement + * available at https://central.leapmotion.com/agreements/SdkAgreement unless + * Ultraleap has signed a separate license agreement with you or your + * organisation. + * + */ + +#include +#include +#define __STDC_FORMAT_MACROS +#include + +#ifdef _WIN32 +#include +#else +#include +#endif + +#include "LeapC.h" +#include "ExampleConnection.h" + +int64_t lastFrameID = 0; //The last frame received + +int main(int argc, char** argv) { + OpenConnection(); + while(!IsConnected) + millisleep(100); //wait a bit to let the connection complete + + printf("Connected.\n"); + LEAP_DEVICE_INFO* deviceProps = GetDeviceProperties(); + if(deviceProps) + printf("Using device %s.\n", deviceProps->serial); + + LEAP_RECORDING recordingHandle; + LEAP_RECORDING_PARAMETERS params; + + //Open the recording for writing + params.mode = eLeapRecordingFlags_Writing; + eLeapRS result = LeapRecordingOpen(&recordingHandle, "leapRecording.lmt", params); + if(LEAP_SUCCEEDED(result)){ + int frameCount = 0; + while(frameCount < 10){ + LEAP_TRACKING_EVENT *frame = GetFrame(); + if(frame && (frame->tracking_frame_id > lastFrameID)){ + lastFrameID = frame->tracking_frame_id; + frameCount++; + uint64_t dataWritten = 0; + result = LeapRecordingWrite(recordingHandle, frame, &dataWritten); + printf("Recorded %"PRIu64" bytes for frame %"PRIu64" with %i hands.\n", dataWritten, frame->tracking_frame_id, frame->nHands); + } + } + result = LeapRecordingClose(&recordingHandle); + if(!LEAP_SUCCEEDED(result)) + printf("Failed to close recording: %s\n", ResultString(result)); + + //Reopen the recording for reading + params.mode = eLeapRecordingFlags_Reading; + result = LeapRecordingOpen(&recordingHandle, "leapRecording.lmt", params); + if(LEAP_SUCCEEDED(result)){ + LEAP_TRACKING_EVENT *frame = 0; + while(frameCount-- > 0){ + uint64_t nextFrameSize = 0; + result = LeapRecordingReadSize(recordingHandle, &nextFrameSize); + if(!LEAP_SUCCEEDED(result)) + printf("Couldn't get next frame size: %s\n", ResultString(result)); + if(nextFrameSize > 0){ + frame = (LEAP_TRACKING_EVENT *)malloc((size_t)nextFrameSize); + result = LeapRecordingRead(recordingHandle, frame, nextFrameSize); + if(LEAP_SUCCEEDED(result)){ + printf("Read frame %"PRIu64" with %i hands.\n", frame->tracking_frame_id, frame->nHands); + } else { + printf("Could not read frame: %s\n", ResultString(result)); + } + } + } + result = LeapRecordingClose(&recordingHandle); + if(!LEAP_SUCCEEDED(result)) + printf("Failed to close recording: %s\n", ResultString(result)); + } else { + printf("Failed to open recording for reading: %s\n", ResultString(result)); + } + } else { + printf("Failed to open recording for writing: %s\n", ResultString(result)); + } + return 0; +} +//End-of-Sample diff --git a/vendor/LeapSDK/samples/leapc_main.c b/vendor/LeapSDK/samples/leapc_main.c new file mode 100644 index 00000000..e5890559 --- /dev/null +++ b/vendor/LeapSDK/samples/leapc_main.c @@ -0,0 +1,78 @@ +/* Copyright (C) 2021 Ultraleap Limited. All rights reserved. + * + * Use of this code is subject to the terms of the Ultraleap SDK agreement + * available at https://central.leapmotion.com/agreements/SdkAgreement unless + * Ultraleap has signed a separate license agreement with you or your + * organisation. + * + */ + +#include "LeapC.h" + +#include +#include +#include + +static void assert_impl(bool success, const char* instruction_line) +{ + if (!success) + { + fprintf(stderr, "ERROR: %s\n", instruction_line); + abort(); + } +} + +#define str_i(s) #s +#define str(s) str_i(s) + +#define assert_i(test, msg) assert_impl(test, __FILE__ ":" str(__LINE__) " -- " msg) +#define assert(test) assert_i((test), #test) + +int main(int argc, const char** argv) +{ + LEAP_CONNECTION connection; + + assert(LeapCreateConnection(NULL, &connection) == eLeapRS_Success); + assert(LeapOpenConnection(connection) == eLeapRS_Success); + + const uint32_t timeout = 1000U; + + uint32_t computed_array_size = 0U; + + for (uint32_t retry_limit = 7U; retry_limit > 0; --retry_limit) + { + LEAP_CONNECTION_MESSAGE msg; + + LeapPollConnection(connection, timeout, &msg); + + eLeapRS return_code = LeapGetDeviceList(connection, NULL, &computed_array_size); + if (return_code == eLeapRS_NotConnected) + { + continue; + } + assert(return_code == eLeapRS_Success); + printf("Number of devices available: %u\n", computed_array_size); + + if (computed_array_size > 0U) + { + break; + } + } + + if (computed_array_size > 0U) + { + LEAP_DEVICE_REF* leap_device_list = + (LEAP_DEVICE_REF*)malloc(sizeof(LEAP_DEVICE_REF) * computed_array_size); + assert( + LeapGetDeviceList(connection, leap_device_list, &computed_array_size) == eLeapRS_Success); + + /* Make use of leap_device_list here */ + + free(leap_device_list); + } + + LeapCloseConnection(connection); + LeapDestroyConnection(connection); + + return eLeapRS_Success; +} diff --git a/vendor/glm b/vendor/glm new file mode 160000 index 00000000..bf71a834 --- /dev/null +++ b/vendor/glm @@ -0,0 +1 @@ +Subproject commit bf71a834948186f4097caa076cd2663c69a10e1e diff --git a/vendor/openvr b/vendor/openvr new file mode 160000 index 00000000..4c85abcb --- /dev/null +++ b/vendor/openvr @@ -0,0 +1 @@ +Subproject commit 4c85abcb7f7f1f02adaf3812018c99fc593bc341 diff --git a/vendor/pugixml b/vendor/pugixml new file mode 160000 index 00000000..3c59df55 --- /dev/null +++ b/vendor/pugixml @@ -0,0 +1 @@ +Subproject commit 3c59df555b93a7650ae0056da34bacde93f4ef8f