diff --git a/CMakeLists.txt b/CMakeLists.txt
index 007ffc13..6e1c3a70 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -24,6 +24,19 @@ elseif(APPLE)
set(PLATFORM_NAME "osx")
endif()
+execute_process(
+ COMMAND git rev-parse --abbrev-ref HEAD
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_BRANCH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+# Get the latest commit hash
+execute_process(
+ COMMAND git rev-parse HEAD
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ OUTPUT_VARIABLE GIT_COMMIT_HASH
+ OUTPUT_STRIP_TRAILING_WHITESPACE)
+
find_library(OPENVR_LIB openvr_api HINTS "${CMAKE_CURRENT_SOURCE_DIR}/libraries/openvr/lib/${PLATFORM_NAME}${PROCESSOR_ARCH}/" NO_DEFAULT_PATH )
add_subdirectory("overlay")
@@ -41,6 +54,9 @@ target_include_directories("${OPENGLOVE_PROJECT}" PUBLIC "${OPENVR_INCLUDE_DIR}"
target_include_directories("${OPENGLOVE_PROJECT}" PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/include/")
target_link_libraries("${OPENGLOVE_PROJECT}" PUBLIC "${OPENVR_LIB}" setupapi wsock32 ws2_32 bthprops)
+target_compile_definitions("${OPENGLOVE_PROJECT}" PRIVATE
+ "-DGIT_COMMIT_HASH=\"${GIT_COMMIT_HASH}\"")
+
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/include" PREFIX "Header Files" FILES ${HEADERS})
source_group(TREE "${CMAKE_CURRENT_SOURCE_DIR}/src" PREFIX "Source Files" FILES ${SOURCES})
set_property(TARGET "${OPENGLOVE_PROJECT}" PROPERTY CXX_STANDARD 17)
diff --git a/README.md b/README.md
index a4a09028..c1051904 100644
--- a/README.md
+++ b/README.md
@@ -1,62 +1,84 @@
-# OpenGloves Driver
+# OpenGloves Driver [![Steam Badge]][Steam] [![Discord Badge]][Discord]
-OpenGloves is an OpenVR driver for DIY Virtual Reality Gloves. Using OpenVR's driver interface we are able to provide support for many SteamVR/OpenVR games.
+A general purpose **SteamVR** driver with an **[Open Interface]**
+for anyone to connect their **DIY** **VR** *( Glove )* hardware.
-## Installation and Usage
+---
+**⸢ [Installation] ⸥ ⸢ [Limitations] ⸥ ⸢ [Compatibility] ⸥**
-### Download on Steam:
-[![Steam Release](https://cdn.discordapp.com/attachments/790676300552994826/845412304219537439/openglovessteam.png)](https://store.steampowered.com/app/1574050/OpenGloves)
- * We strongly recommend downloading the driver from Steam, to recieve automatic updates and UI settings.
+---
-*Or download the latest on GitHub:*
- * https://github.com/LucidVR/opengloves-driver/releases
+## Features
-**Follow the wiki guide for configuring the driver**
-* https://github.com/LucidVR/opengloves-driver/wiki/Configuring-the-Driver
-* The driver will not work correctly unless you configure it properly.
+- **Haptic Force Feedback**
-**Problems?**
-* Check [Troubleshooting](https://github.com/LucidVR/opengloves-driver/wiki/Troubleshooting)
- * Didn't help? Contact us on the [Community Discord Server](https://discord.gg/lucidvr)
-## Building
-If you want to use the driver as-is, refer to [Installation and Usage](#Installation-and-Usage).
-If you are planning on modifying source files, refer to [BUILDING.md](https://github.com/LucidVR/opengloves-driver/blob/develop/BUILDING.md).
+- **Full Finger Tracking**
+ *‹ Beta › Splay Support*
+ *‹ Beta › Individual Joint Support*
-## Compatibility
-### Compatible Hardware
-* [LucidGloves](https://github.com/LucidVR/lucidgloves) - Lucas VRTech
-* [Fngrs](https://github.com/danwillm/Fngrs/) - danwillm
-* Have your own hardware you want to feature here? Let us know!
+- **Tracker / Controller Positioning**
+ *Automatic relative calibration*
+ *Controller ⟷ Glove*
-### Compatible Games
-* Refer to [Game Compatibility List](https://github.com/LucidVR/opengloves-driver/wiki/Game-Compatibility-List)
-* As this is an OpenVR driver, it is strictly compatible with games that take input from the OpenVR API. Only the games in the list above have been tested to work properly.
+- **Button / Joystick Inputs**
+ *➜ Trigger | A | B*
+ *➜ Joystick | X | Y | Click*
-### Current features included in the driver
-* Finger flexion tracking
-* Force feedback haptics
-* Positioning from controllers + trackers
- * Automatic Calibration
-* Button/Joystick inputs
- * A/B/Menu buttons, Joystick X/Y/Click
-* Communication Protocols:
- * Serial USB
- * Serial over Bluetooth
+- **Multiple Communication Protocols**
+ *- Bluetooth Serial*
+ *- Named Pipes*
+ *- Serial USB*
-### Planned features
-* BLE Communication
-* Finger splay tracking
-* Vibration haptics
+
+### Steam UI
+
+The **[Steam]** version of **OpenGloves** also comes
+with a **[UI]** for configuring driver related features.
+
+##### UI Supported Features
+- Force Feedback Testing
+- Editable Driver Settings
+- Automatic Calibration
+ *Controller ⟷ Glove*
+
+---
## Contributing
-Pull requests are very welcome. For major changes, please open an issue first to discuss what you would like to change.
-## Authors
+**Pull requests are very welcome.**
+
+*For major changes, please open an*
+***[Issue]*** *or contact us first to discuss*
+*what you would like to change.*
+
+---
+
+## Credits
+
+| Author | Discord |
+|:------:|:-------:|
+| **[Danwillm]** | `danwillm#8254` |
+| **[Lucas VRTech]** | `LucidVR#0001` |
+
+
+
+
+[Steam Badge]: https://img.shields.io/badge/Steam-000000?style=for-the-badge&logo=steam&logoColor=white
+[Discord Badge]: https://img.shields.io/badge/Discord-7289DA?style=for-the-badge&logo=discord&logoColor=white
+
+[Discord]: https://discord.gg/lucidvr
+[Steam]: https://store.steampowered.com/app/1574050/OpenGloves
+
+[Installation]: docs/Installation.md
+[Limitations]: docs/Limitations.md
+[Compatibility]: docs/Compatibility.md
+
+[UI]: https://github.com/lucidVR/opengloves-ui
+[Open Interface]: https://github.com/LucidVR/opengloves-driver/wiki/Driver-Input
-* Danwillm (`danwillm#8254`)
-* Lucas VRTech (`LucidVR#0001`)
+[Issue]: https://github.com/LucidVR/opengloves-driver/issues
-## Discord
-https://discord.gg/lucidvr
+[Danwillm]: https://github.com/danwillm
+[Lucas VRTech]: https://github.com/lucas-vrtech
diff --git a/BUILDING.md b/docs/Building.md
similarity index 100%
rename from BUILDING.md
rename to docs/Building.md
diff --git a/docs/Compatibility.md b/docs/Compatibility.md
new file mode 100644
index 00000000..456dbce6
--- /dev/null
+++ b/docs/Compatibility.md
@@ -0,0 +1,81 @@
+
+# Compatibility
+
+
+
+## Officially Hardware
+
+The following projects are known to be compatible with **OpenGloves**.
+
+- **[LucidGloves]**
+ *by [Lucas VRTech]*
+
+- **[Fngrs]**
+ *by [danwillm]*
+
+
+
+**Made your own hardware? Let us know!**
+
+---
+
+## Your Hardware
+
+While **OpenGloves** is capable of handling
+inputs from a variety of VR controllers,
+it is primarily designed for VR Gloves.
+
+
+
+#### Custom Hardware
+
+To make your own hardware compatible with **OpenGloves**,
+please refer to the **[Driver Input]** page, which provides relevant
+information like `Encoding Schemes` & `Communication Methods`.
+
+
+
+#### LucidVR
+
+This is our own **[Firmware]** that is compatible with
+**OpenGloves** and runs on `Arduino` / `ESP32` devices.
+
+---
+
+## Games
+
+**OpenGloves** is strictly compatible with **OpenVR** compatible games.
+
+
+
+##### Finger Curling
+
+Is supported in games that work with the **Index** controllers.
+
+
+
+##### Force Feedback
+
+Unfortunately, game compatibility
+with this feature is **[More Limited][Game Compatibility]**.
+
+If you'd like to make your **Game** / **Mod** compatible
+with `Force Feedback`, please refer to the **[Wiki][Integration]**.
+
+
+
+
+
+[LucidGloves]: https://github.com/LucidVR/lucidgloves
+[Lucas VRTech]: https://github.com/lucas-vrtech
+
+[Fngrs]: https://github.com/danwillm/Fngrs/
+[danwillm]: https://github.com/danwillm
+
+[Driver Input]: https://github.com/LucidVR/opengloves-driver/wiki/Driver-Input
+
+[Firmware]: https://github.com/LucidVR/lucidgloves/tree/main/firmware/lucidgloves-firmware
+
+[Game Compatibility]: https://github.com/LucidVR/opengloves-driver/wiki/Game-Compatibility-List
+
+[Integration]: https://github.com/LucidVR/opengloves-driver/wiki/Integrating-Force-Feedback
diff --git a/docs/Installation.md b/docs/Installation.md
new file mode 100644
index 00000000..87e98f3e
--- /dev/null
+++ b/docs/Installation.md
@@ -0,0 +1,23 @@
+
+# Installation & Usage
+
+It is strongly recommended to use the **[Steam]** version
+to receive `Automatic Updates` as well as a `Builtin UI`.
+
+[![Steam Preview]][Steam]
+
+---
+
+## GitHub
+
+While ***not recommended***, it is possible to install **OpenGloves**
+manually by downloading a **[Release]** and **[Building]** it yourself.
+
+
+
+
+[Steam]: https://store.steampowered.com/app/1574050/OpenGloves
+[Steam Preview]: https://cdn.discordapp.com/attachments/790676300552994826/845412304219537439/openglovessteam.png
+
+[Release]: https://github.com/LucidVR/opengloves-driver/releases
+[Building]: Building.md
diff --git a/docs/Limitations.md b/docs/Limitations.md
new file mode 100644
index 00000000..228c9e27
--- /dev/null
+++ b/docs/Limitations.md
@@ -0,0 +1,50 @@
+
+# Limitations
+
+
+
+#### Missing Custom Controller Support
+
+Many VR titles do not support finger tracking from **custom**
+controllers, requiring the need to emulate controller types.
+
+
+We emulate the index controller to achieve this
+compatibility, which means that we are limited
+to the inputs that the index controller exposes.
+
+It is possible to emulate an index controller while
+providing your own input profiles and bindings,
+but we have chosen not to include that by default
+in the driver, as to preserve compatibility with
+default index controller bindings.
+
+##### Custom Implementation
+
+If you want to implement your own device and use the utilities
+that **OpenGloves** provides, such as `Bone Calculations` and
+`Communication`, you will have to implement a custom driver.
+
+To do this, you have to create your own class derived from [`DeviceDriver`], that
implement `StartingDevice`, `SetupProps`, `HandleInput` & `StoppingDevice`.
+
+**➔** An example of a fully custom controller is **[LucidGloveDriver]**
+ *which you are free to adapt to your needs.*
+
+
+
+#### Dynamic Inputs
+
+Due to how **OpenVR** works, inputs cannot be set ***dynamically***.
+
+Our inputs for `Index Controller Emulated Devices` are ***fixed***
+to that of the index controller, and cannot have custom inputs.
+
+**➔** *However, you can define your own inputs in a*
+ *custom device with a different input profile.*
+
+
+
+
+[`DeviceDriver`]: ../src/DeviceDriver/DeviceDriver.cpp
+
+[LucidGloveDriver]: https://github.com/LucidVR/opengloves-driver/blob/develop/src/DeviceDriver/LucidGloveDriver.cpp
diff --git a/include/Bones.h b/include/Bones.h
index a898c475..922a86bd 100644
--- a/include/Bones.h
+++ b/include/Bones.h
@@ -3,79 +3,23 @@
#include
#include
+#include "Encode/EncodingManager.h"
#include "openvr_driver.h"
-
-enum class HandSkeletonBone : vr::BoneIndex_t {
- Root = 0,
- Wrist,
- Thumb0,
- Thumb1,
- Thumb2,
- Thumb3,
- IndexFinger0,
- IndexFinger1,
- IndexFinger2,
- IndexFinger3,
- IndexFinger4,
- MiddleFinger0,
- MiddleFinger1,
- MiddleFinger2,
- MiddleFinger3,
- MiddleFinger4,
- RingFinger0,
- RingFinger1,
- RingFinger2,
- RingFinger3,
- RingFinger4,
- PinkyFinger0,
- PinkyFinger1,
- PinkyFinger2,
- PinkyFinger3,
- PinkyFinger4,
- AuxThumb,
- AuxIndexFinger,
- AuxMiddleFinger,
- AuxRingFinger,
- AuxPinkyFinger,
- _Count
-};
+#include "Util/AnimLoader.h"
const short NUM_BONES = static_cast(HandSkeletonBone::_Count);
-extern vr::VRBoneTransform_t rightOpenPose[NUM_BONES];
-extern vr::VRBoneTransform_t leftOpenPose[NUM_BONES];
-
-struct Transform {
- Transform();
- std::array rotation;
- std::array translation;
-};
-
-struct AnimationData {
- AnimationData();
- Transform startTransform;
- float startTime;
- Transform endTransform;
- float endTime;
- float fScaled;
-};
-
-class IModelManager {
- public:
- virtual bool Load() = 0;
-
- virtual AnimationData GetAnimationDataByBoneIndex(const HandSkeletonBone& boneIndex, float f) const = 0;
- virtual Transform GetTransformByBoneIndex(const HandSkeletonBone& boneIndex) const = 0;
-};
-
class BoneAnimator {
public:
explicit BoneAnimator(const std::string& fileName);
- void ComputeSkeletonTransforms(vr::VRBoneTransform_t* skeleton, const std::array& flexion, const bool rightHand);
+ void ComputeSkeletonTransforms(vr::VRBoneTransform_t* skeleton, const VRInputData& inputData, const bool rightHand);
static void TransformLeftBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex);
+ static float GetAverageCurlValue(const std::array& joints);
+ void LoadDefaultSkeletonByHand(vr::VRBoneTransform_t* skeleton, const bool rightHand);
private:
- void SetTransformForBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex, const float f, const bool rightHand) const;
+ void SetTransformForBone(
+ vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex, const float curl, const float splay, const bool rightHand) const;
std::string fileName_;
std::unique_ptr modelManager_;
diff --git a/include/Communication/SerialCommunicationManager.h b/include/Communication/SerialCommunicationManager.h
index a07a5f5c..687528b9 100644
--- a/include/Communication/SerialCommunicationManager.h
+++ b/include/Communication/SerialCommunicationManager.h
@@ -27,6 +27,12 @@ class SerialCommunicationManager : public CommunicationManager {
private:
bool PurgeBuffer() const;
+ bool SetCommunicationTimeout(
+ unsigned long ReadIntervalTimeout,
+ unsigned long ReadTotalTimeoutMultiplier,
+ unsigned long ReadTotalTimeoutConstant,
+ unsigned long WriteTotalTimeoutMultiplier,
+ unsigned long WriteTotalTimeoutConstant);
VRSerialConfiguration serialConfiguration_;
diff --git a/include/DeviceDriver/DeviceDriver.h b/include/DeviceDriver/DeviceDriver.h
index 02416f17..74ee67db 100644
--- a/include/DeviceDriver/DeviceDriver.h
+++ b/include/DeviceDriver/DeviceDriver.h
@@ -35,6 +35,7 @@ class DeviceDriver : public vr::ITrackedDeviceServerDriver {
virtual void SetupProps(vr::PropertyContainerHandle_t& props) = 0;
virtual void StartingDevice() = 0;
virtual void StoppingDevice() = 0;
+ void PoseUpdateThread();
std::unique_ptr communicationManager_;
std::shared_ptr boneAnimator_;
@@ -45,6 +46,8 @@ class DeviceDriver : public vr::ITrackedDeviceServerDriver {
vr::VRInputComponentHandle_t skeletalComponentHandle_;
vr::VRBoneTransform_t handTransforms_[NUM_BONES];
- bool hasActivated_;
+ std::thread poseUpdateThread_;
+
+ std::atomic hasActivated_;
uint32_t driverId_;
};
\ No newline at end of file
diff --git a/include/Encode/AlphaEncodingManager.h b/include/Encode/AlphaEncodingManager.h
index 043df5ef..7adef598 100644
--- a/include/Encode/AlphaEncodingManager.h
+++ b/include/Encode/AlphaEncodingManager.h
@@ -4,8 +4,8 @@
class AlphaEncodingManager : public EncodingManager {
public:
- explicit AlphaEncodingManager(float maxAnalogValue);
+ explicit AlphaEncodingManager(float maxAnalogValue) : EncodingManager(maxAnalogValue){};
- VRInputData Decode(std::string input) override;
+ VRInputData Decode(const std::string& input) override;
std::string Encode(const VRFFBData& input) override;
};
\ No newline at end of file
diff --git a/include/Encode/EncodingManager.h b/include/Encode/EncodingManager.h
index c8f19160..2e1937ea 100644
--- a/include/Encode/EncodingManager.h
+++ b/include/Encode/EncodingManager.h
@@ -7,8 +7,9 @@
#include "DriverLog.h"
struct VRFFBData {
- VRFFBData();
- VRFFBData(short thumbCurl, short indexCurl, short middleCurl, short ringCurl, short pinkyCurl);
+ VRFFBData() : VRFFBData(0, 0, 0, 0, 0){};
+ VRFFBData(short thumbCurl, short indexCurl, short middleCurl, short ringCurl, short pinkyCurl)
+ : thumbCurl(thumbCurl), indexCurl(indexCurl), middleCurl(middleCurl), ringCurl(ringCurl), pinkyCurl(pinkyCurl){};
const short thumbCurl;
const short indexCurl;
@@ -18,7 +19,10 @@ struct VRFFBData {
};
struct VRInputData {
- VRInputData();
+ VRInputData()
+ : VRInputData(
+ {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, {0.0f, 0.0f, 0.0f, 0.0f, 0.0f}, 0.0f, 0.0f, false, false, false, false, false, false, false, false){};
+
VRInputData(
std::array flexion,
float joyX,
@@ -30,9 +34,68 @@ struct VRInputData {
bool grab,
bool pinch,
bool menu,
- bool calibrate);
+ bool calibrate)
+ : flexion({
+ flexion[0],
+ flexion[0],
+ flexion[0],
+ flexion[0],
+ flexion[1],
+ flexion[1],
+ flexion[1],
+ flexion[1],
+ flexion[2],
+ flexion[2],
+ flexion[2],
+ flexion[2],
+ flexion[3],
+ flexion[3],
+ flexion[3],
+ flexion[3],
+ flexion[4],
+ flexion[4],
+ flexion[4],
+ flexion[4],
+ }),
+ joyX(joyX),
+ joyY(joyY),
+ joyButton(joyButton),
+ trgButton(trgButton),
+ aButton(aButton),
+ bButton(bButton),
+ grab(grab),
+ pinch(pinch),
+ menu(menu),
+ calibrate(calibrate) {}
+
+ VRInputData(
+ std::array, 5> flexion,
+ std::array splay,
+ float joyX,
+ float joyY,
+ bool joyButton,
+ bool trgButton,
+ bool aButton,
+ bool bButton,
+ bool grab,
+ bool pinch,
+ bool menu,
+ bool calibrate)
+ : flexion(flexion),
+ splay(splay),
+ joyX(joyX),
+ joyY(joyY),
+ joyButton(joyButton),
+ trgButton(trgButton),
+ aButton(aButton),
+ bButton(bButton),
+ grab(grab),
+ pinch(pinch),
+ menu(menu),
+ calibrate(calibrate) {}
- const std::array flexion;
+ const std::array, 5> flexion;
+ const std::array splay = {-2.0f, -2.0f, -2.0f, -2.0f, -2.0f};
const float joyX;
const float joyY;
const bool joyButton;
@@ -47,8 +110,8 @@ struct VRInputData {
class EncodingManager {
public:
- explicit EncodingManager(float maxAnalogValue);
- virtual VRInputData Decode(std::string input) = 0;
+ explicit EncodingManager(float maxAnalogValue) : maxAnalogValue_(maxAnalogValue){};
+ virtual VRInputData Decode(const std::string& input) = 0;
virtual std::string Encode(const VRFFBData& data) = 0;
protected:
diff --git a/include/Encode/LegacyEncodingManager.h b/include/Encode/LegacyEncodingManager.h
index 672d806b..7f92ae64 100644
--- a/include/Encode/LegacyEncodingManager.h
+++ b/include/Encode/LegacyEncodingManager.h
@@ -6,6 +6,6 @@ class LegacyEncodingManager : public EncodingManager {
public:
explicit LegacyEncodingManager(float maxAnalogValue);
- VRInputData Decode(std::string input) override;
+ VRInputData Decode(const std::string& input) override;
std::string Encode(const VRFFBData& input) override;
};
\ No newline at end of file
diff --git a/include/Util/AnimLoader.h b/include/Util/AnimLoader.h
new file mode 100644
index 00000000..1cd9de3e
--- /dev/null
+++ b/include/Util/AnimLoader.h
@@ -0,0 +1,97 @@
+#pragma once
+
+#include
+
+#include "openvr_driver.h"
+
+#define TINYGLTF_NO_STB_IMAGE
+#define TINYGLTF_NO_STB_IMAGE_WRITE
+#include "tiny_gltf.h"
+
+enum class HandSkeletonBone : vr::BoneIndex_t {
+ Root = 0,
+ Wrist,
+ Thumb0,
+ Thumb1,
+ Thumb2,
+ Thumb3,
+ IndexFinger0,
+ IndexFinger1,
+ IndexFinger2,
+ IndexFinger3,
+ IndexFinger4,
+ MiddleFinger0,
+ MiddleFinger1,
+ MiddleFinger2,
+ MiddleFinger3,
+ MiddleFinger4,
+ RingFinger0,
+ RingFinger1,
+ RingFinger2,
+ RingFinger3,
+ RingFinger4,
+ PinkyFinger0,
+ PinkyFinger1,
+ PinkyFinger2,
+ PinkyFinger3,
+ PinkyFinger4,
+ AuxThumb,
+ AuxIndexFinger,
+ AuxMiddleFinger,
+ AuxRingFinger,
+ AuxPinkyFinger,
+ _Count
+};
+
+struct Transform {
+ Transform();
+ std::array rotation;
+ std::array translation;
+};
+
+struct AnimationData {
+ AnimationData();
+ Transform startTransform;
+ float startTime;
+ Transform endTransform;
+ float endTime;
+};
+
+class IModelManager {
+ public:
+ virtual bool Load() = 0;
+
+ virtual AnimationData GetAnimationDataByBoneIndex(const HandSkeletonBone& boneIndex, float f) const = 0;
+ virtual Transform GetTransformByBoneIndex(const HandSkeletonBone& boneIndex) const = 0;
+};
+
+class GLTFModelManager : public IModelManager {
+ public:
+ GLTFModelManager(std::string fileName) : fileName_(std::move(fileName)) {}
+
+ bool Load() override;
+
+ AnimationData GetAnimationDataByBoneIndex(const HandSkeletonBone& boneIndex, const float f) const override;
+ Transform GetTransformByBoneIndex(const HandSkeletonBone& boneIndex) const;
+
+ private:
+ void LoadInitialTransforms();
+ void LoadKeyframeTimes();
+
+ template
+ std::vector> GetVecN(const tinygltf::Accessor& accessor) const {
+ const tinygltf::BufferView bufferView = model_.bufferViews[accessor.bufferView];
+ const std::vector& bufData = model_.buffers[0].data;
+
+ std::vector> res(accessor.count);
+ memcpy(&res[0], bufData.data() + bufferView.byteOffset + accessor.byteOffset, accessor.count * sizeof(float) * N);
+
+ return res;
+ }
+
+ tinygltf::Model model_;
+ std::string fileName_;
+ std::vector initialTransforms_;
+ std::vector keyframeTimes_;
+ std::vector> keyframeTransforms_;
+};
\ No newline at end of file
diff --git a/include/Util/Quaternion.h b/include/Util/Quaternion.h
index 237d9f31..3b07951d 100644
--- a/include/Util/Quaternion.h
+++ b/include/Util/Quaternion.h
@@ -12,10 +12,15 @@ vr::HmdVector3_t CombinePosition(const vr::HmdMatrix34_t& matrix, const vr::HmdV
// returns the result of multiplying two quaternions, effectively applying a rotation on a quaternion
vr::HmdQuaternion_t MultiplyQuaternion(const vr::HmdQuaternion_t& q, const vr::HmdQuaternion_t& r);
+vr::HmdQuaternionf_t MultiplyQuaternion(const vr::HmdQuaternionf_t& q, const vr::HmdQuaternionf_t& r);
+vr::HmdQuaternionf_t EulerToQuaternion(const float& yaw, const float& pitch, const float& roll);
vr::HmdQuaternion_t EulerToQuaternion(const double& yaw, const double& pitch, const double& roll);
+
vr::HmdMatrix33_t GetRotationMatrix(const vr::HmdMatrix34_t& matrix);
+
vr::HmdVector3_t MultiplyMatrix(const vr::HmdMatrix33_t& matrix, const vr::HmdVector3_t& vector);
+
vr::HmdMatrix33_t QuaternionToMatrix(const vr::HmdQuaternion_t& q);
vr::HmdQuaternion_t QuatConjugate(const vr::HmdQuaternion_t& q);
diff --git a/src/Bones.cpp b/src/Bones.cpp
index 8355e95a..9c1ee58a 100644
--- a/src/Bones.cpp
+++ b/src/Bones.cpp
@@ -1,65 +1,32 @@
#include "Bones.h"
+#include
#include
#include "DriverLog.h"
+#include "Util/Quaternion.h"
-#define TINYGLTF_IMPLEMENTATION
-#define TINYGLTF_NO_STB_IMAGE
-#define TINYGLTF_NO_STB_IMAGE_WRITE
-#include "tiny_gltf.h"
+static const float c_maxSplayAngle = 10.0f;
static const std::array emptyRotation = {0.0f, 0.0f, 0.0f, 0.0f};
static const std::array emptyTranslation = {0.0f, 0.0f, 0.0f};
-Transform::Transform() : rotation(emptyRotation), translation(emptyTranslation) {}
-AnimationData::AnimationData() : startTime(0.0f), endTime(0.0f) {}
-
static float Lerp(const float& a, const float& b, const float& f) {
return a + f * (b - a);
}
enum class FingerIndex : int { Thumb = 0, IndexFinger, MiddleFinger, RingFinger, PinkyFinger, Unknown = -1 };
-static std::map GLTFNodeBoneMap{
- {"REF:Root", HandSkeletonBone::Root},
- {"REF:wrist_r", HandSkeletonBone::Wrist},
- {"REF:finger_thumb_0_r", HandSkeletonBone::Thumb0},
- {"REF:finger_thumb_1_r", HandSkeletonBone::Thumb1},
- {"REF:finger_thumb_2_r", HandSkeletonBone::Thumb2},
- {"REF:finger_thumb_r_end", HandSkeletonBone::Thumb3},
- {"REF:finger_index_meta_r", HandSkeletonBone::IndexFinger0},
- {"REF:finger_index_0_r", HandSkeletonBone::IndexFinger1},
- {"REF:finger_index_1_r", HandSkeletonBone::IndexFinger2},
- {"REF:finger_index_2_r", HandSkeletonBone::IndexFinger3},
- {"REF:finger_index_r_end", HandSkeletonBone::IndexFinger4},
- {"REF:finger_middle_meta_r", HandSkeletonBone::MiddleFinger0},
- {"REF:finger_middle_0_r", HandSkeletonBone::MiddleFinger1},
- {"REF:finger_middle_1_r", HandSkeletonBone::MiddleFinger2},
- {"REF:finger_middle_2_r", HandSkeletonBone::MiddleFinger3},
- {"REF:finger_middle_r_end", HandSkeletonBone::MiddleFinger4},
- {"REF:finger_ring_meta_r", HandSkeletonBone::RingFinger0},
- {"REF:finger_ring_0_r", HandSkeletonBone::RingFinger1},
- {"REF:finger_ring_1_r", HandSkeletonBone::RingFinger2},
- {"REF:finger_ring_2_r", HandSkeletonBone::RingFinger3},
- {"REF:finger_ring_r_end", HandSkeletonBone::RingFinger4},
- {"REF:finger_pinky_meta_r", HandSkeletonBone::PinkyFinger0},
- {"REF:finger_pinky_0_r", HandSkeletonBone::PinkyFinger1},
- {"REF:finger_pinky_1_r", HandSkeletonBone::PinkyFinger2},
- {"REF:finger_pinky_2_r", HandSkeletonBone::PinkyFinger3},
- {"REF:finger_pinky_r_end", HandSkeletonBone::PinkyFinger4},
- {"REF:finger_thumb_r_aux", HandSkeletonBone::AuxThumb},
- {"REF:finger_index_r_aux", HandSkeletonBone::AuxIndexFinger},
- {"REF:finger_middle_r_aux", HandSkeletonBone::AuxMiddleFinger},
- {"REF:finger_ring_r_aux", HandSkeletonBone::AuxRingFinger},
- {"REF:finger_pinky_r_aux", HandSkeletonBone::AuxPinkyFinger}};
-
-static FingerIndex GetFingerFromBoneIndex(const HandSkeletonBone bone) {
+static bool IsBoneSplayableBone(const HandSkeletonBone& bone) {
+ return bone == HandSkeletonBone::Thumb0 || bone == HandSkeletonBone::IndexFinger1 || bone == HandSkeletonBone::MiddleFinger1 ||
+ bone == HandSkeletonBone::RingFinger1 || bone == HandSkeletonBone::PinkyFinger1;
+}
+
+static FingerIndex GetFingerFromBoneIndex(const HandSkeletonBone& bone) {
switch (bone) {
case HandSkeletonBone::Thumb0:
case HandSkeletonBone::Thumb1:
case HandSkeletonBone::Thumb2:
- case HandSkeletonBone::Thumb3:
case HandSkeletonBone::AuxThumb:
return FingerIndex::Thumb;
@@ -67,7 +34,6 @@ static FingerIndex GetFingerFromBoneIndex(const HandSkeletonBone bone) {
case HandSkeletonBone::IndexFinger1:
case HandSkeletonBone::IndexFinger2:
case HandSkeletonBone::IndexFinger3:
- case HandSkeletonBone::IndexFinger4:
case HandSkeletonBone::AuxIndexFinger:
return FingerIndex::IndexFinger;
@@ -75,7 +41,6 @@ static FingerIndex GetFingerFromBoneIndex(const HandSkeletonBone bone) {
case HandSkeletonBone::MiddleFinger1:
case HandSkeletonBone::MiddleFinger2:
case HandSkeletonBone::MiddleFinger3:
- case HandSkeletonBone::MiddleFinger4:
case HandSkeletonBone::AuxMiddleFinger:
return FingerIndex::MiddleFinger;
@@ -83,7 +48,6 @@ static FingerIndex GetFingerFromBoneIndex(const HandSkeletonBone bone) {
case HandSkeletonBone::RingFinger1:
case HandSkeletonBone::RingFinger2:
case HandSkeletonBone::RingFinger3:
- case HandSkeletonBone::RingFinger4:
case HandSkeletonBone::AuxRingFinger:
return FingerIndex::RingFinger;
@@ -91,7 +55,6 @@ static FingerIndex GetFingerFromBoneIndex(const HandSkeletonBone bone) {
case HandSkeletonBone::PinkyFinger1:
case HandSkeletonBone::PinkyFinger2:
case HandSkeletonBone::PinkyFinger3:
- case HandSkeletonBone::PinkyFinger4:
case HandSkeletonBone::AuxPinkyFinger:
return FingerIndex::PinkyFinger;
@@ -100,164 +63,93 @@ static FingerIndex GetFingerFromBoneIndex(const HandSkeletonBone bone) {
}
}
-class GLTFModelManager : public IModelManager {
- tinygltf::Model model_;
- std::string fileName_;
- std::vector initialTransforms_;
- std::vector keyframeTimes_;
- std::vector> keyframeTransforms_;
-
- public:
- GLTFModelManager(std::string fileName) : fileName_(std::move(fileName)) {}
-
- bool Load() override {
- tinygltf::TinyGLTF loader;
- std::string err;
- std::string warn;
-
- const bool ret = loader.LoadBinaryFromFile(&model_, &err, &warn, fileName_);
+static HandSkeletonBone GetRootFingerBoneFromFingerIndex(const FingerIndex& finger) {
+ switch (finger) {
+ case FingerIndex::Thumb:
+ return HandSkeletonBone::Thumb0;
+ case FingerIndex::IndexFinger:
+ return HandSkeletonBone::IndexFinger0;
+ case FingerIndex::MiddleFinger:
+ return HandSkeletonBone::MiddleFinger0;
+ case FingerIndex::RingFinger:
+ return HandSkeletonBone::RingFinger0;
+ case FingerIndex::PinkyFinger:
+ return HandSkeletonBone::PinkyFinger0;
+ }
+}
- if (!warn.empty()) {
- DriverLog("Warning parsing gltf file: %s", warn.c_str());
- return false;
+void BoneAnimator::TransformLeftBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex) {
+ switch (boneIndex) {
+ case HandSkeletonBone::Root: {
+ return;
}
-
- if (!err.empty()) {
- DriverLog("Error parsing gltf file: %s", err.c_str());
- return false;
+ case HandSkeletonBone::Thumb0:
+ case HandSkeletonBone::IndexFinger0:
+ case HandSkeletonBone::MiddleFinger0:
+ case HandSkeletonBone::RingFinger0:
+ case HandSkeletonBone::PinkyFinger0: {
+ const vr::HmdQuaternionf_t quat = bone.orientation;
+ bone.orientation.w = -quat.x;
+ bone.orientation.x = quat.w;
+ bone.orientation.y = -quat.z;
+ bone.orientation.z = quat.y;
+ break;
}
-
- if (!ret) {
- DriverLog("Failed to parse gltf");
- return false;
+ case HandSkeletonBone::Wrist:
+ case HandSkeletonBone::AuxIndexFinger:
+ case HandSkeletonBone::AuxThumb:
+ case HandSkeletonBone::AuxMiddleFinger:
+ case HandSkeletonBone::AuxRingFinger:
+ case HandSkeletonBone::AuxPinkyFinger: {
+ bone.orientation.y *= -1;
+ bone.orientation.z *= -1;
+ break;
}
-
- initialTransforms_ = std::vector(GLTFNodeBoneMap.size());
- keyframeTransforms_ = std::vector>(GLTFNodeBoneMap.size());
-
- LoadKeyframeTimes();
- LoadInitialTransforms();
-
- return true;
- }
-
- AnimationData GetAnimationDataByBoneIndex(const HandSkeletonBone& boneIndex, const float f) const override {
- const float smallest = keyframeTimes_.at(0);
- const float largest = keyframeTimes_.at(keyframeTimes_.size() - 1);
- const float fScaled = Lerp(smallest, largest, f);
-
- const size_t lowerKeyframeIndex = std::upper_bound(keyframeTimes_.begin(), keyframeTimes_.end(), fScaled) - keyframeTimes_.begin() - 1;
- const size_t upperKeyframeIndex = lowerKeyframeIndex < keyframeTimes_.size() - 1 ? lowerKeyframeIndex + 1 : lowerKeyframeIndex;
-
- AnimationData result;
- result.startTransform = keyframeTransforms_[static_cast(boneIndex)][lowerKeyframeIndex];
- result.startTime = keyframeTimes_[lowerKeyframeIndex];
- result.endTransform = keyframeTransforms_[static_cast(boneIndex)][upperKeyframeIndex];
- result.endTime = keyframeTimes_[upperKeyframeIndex];
- result.fScaled = fScaled;
-
- return result;
- }
-
- Transform GetTransformByBoneIndex(const HandSkeletonBone& boneIndex) const override {
- return initialTransforms_[static_cast(boneIndex)];
- }
-
- private:
- void LoadInitialTransforms() {
- for (size_t nodeIndex = 0; nodeIndex < model_.nodes.size(); nodeIndex++) {
- const tinygltf::Node& node = model_.nodes[nodeIndex];
-
- try {
- const int boneIndex = static_cast(GLTFNodeBoneMap.at(node.name));
-
- Transform transform;
- if (node.rotation.size() >= 4) {
- transform.rotation[0] = static_cast(node.rotation[0]);
- transform.rotation[1] = static_cast(node.rotation[1]);
- transform.rotation[2] = static_cast(node.rotation[2]);
- transform.rotation[3] = static_cast(node.rotation[3]);
- }
- if (node.translation.size() >= 3) {
- transform.translation[0] = static_cast(node.translation[0]);
- transform.translation[1] = static_cast(node.translation[1]);
- transform.translation[2] = static_cast(node.translation[2]);
- }
-
- initialTransforms_[boneIndex] = transform;
-
- const tinygltf::Animation& animation = model_.animations[0];
- std::vector& transforms = keyframeTransforms_[boneIndex];
-
- transforms.resize(keyframeTimes_.size());
-
- for (auto& channel : animation.channels) {
- if (channel.target_node != nodeIndex) continue;
-
- const tinygltf::Accessor& accessor = model_.accessors[animation.samplers[channel.sampler].output];
- switch (accessor.type) {
- // rotation via quaternion
- case TINYGLTF_TYPE_VEC4: {
- std::vector> keyframes = GetVecN<4>(accessor);
- for (size_t i = 0; i < keyframes.size(); i++) transforms[i].rotation = keyframes[i];
- break;
- }
- // translation
- case TINYGLTF_TYPE_VEC3: {
- std::vector> keyframes = GetVecN<3>(accessor);
- for (size_t i = 0; i < keyframes.size(); i++) transforms[i].translation = keyframes[i];
- break;
- }
- }
- }
-
- } catch (const std::out_of_range&) {
- DriverLog("Not parsing node as it was not defined as a bone: %i", nodeIndex);
- continue;
- }
+ default: {
+ bone.position.v[1] *= -1;
+ bone.position.v[2] *= -1;
}
}
- void LoadKeyframeTimes() {
- const tinygltf::Accessor accessor = model_.accessors[0];
- keyframeTimes_.resize(accessor.count);
-
- const tinygltf::BufferView bufferView = model_.bufferViews[accessor.bufferView];
- const std::vector& bufData = model_.buffers[0].data;
- memcpy(&keyframeTimes_[0], bufData.data() + bufferView.byteOffset + accessor.byteOffset, accessor.count * sizeof(float));
- }
-
- template
- std::vector> GetVecN(const tinygltf::Accessor& accessor) const {
- const tinygltf::BufferView bufferView = model_.bufferViews[accessor.bufferView];
- const std::vector& bufData = model_.buffers[0].data;
-
- std::vector> res(accessor.count);
- memcpy(&res[0], bufData.data() + bufferView.byteOffset + accessor.byteOffset, accessor.count * sizeof(float) * N);
+ bone.position.v[0] *= -1;
+}
- return res;
- }
-};
+static bool IsAuxBone(const HandSkeletonBone& boneIndex) {
+ return boneIndex == HandSkeletonBone::AuxThumb || boneIndex == HandSkeletonBone::AuxIndexFinger || boneIndex == HandSkeletonBone::AuxMiddleFinger ||
+ boneIndex == HandSkeletonBone::AuxRingFinger || boneIndex == HandSkeletonBone::AuxPinkyFinger;
+}
BoneAnimator::BoneAnimator(const std::string& fileName) : fileName_(fileName) {
modelManager_ = std::make_unique(fileName);
loaded_ = modelManager_->Load();
}
-void BoneAnimator::ComputeSkeletonTransforms(vr::VRBoneTransform_t* skeleton, const std::array& flexion, const bool rightHand) {
+void BoneAnimator::ComputeSkeletonTransforms(vr::VRBoneTransform_t* skeleton, const VRInputData& inputData, const bool rightHand) {
if (!loaded_) return;
- for (size_t i = 0; i < NUM_BONES; i++) {
+ for (size_t i = 1; i < NUM_BONES; i++) {
const FingerIndex finger = GetFingerFromBoneIndex(static_cast(i));
- if (finger != FingerIndex::Unknown) {
- const float f = flexion[static_cast(finger)];
- SetTransformForBone(skeleton[i], static_cast(i), f, rightHand);
- }
+ const int iFinger = static_cast(finger);
+
+ if (finger == FingerIndex::Unknown) continue;
+
+ float curl;
+ if (IsAuxBone(static_cast(i)))
+ curl = GetAverageCurlValue(inputData.flexion[iFinger]);
+ else
+ curl = inputData.flexion[iFinger][i - static_cast(GetRootFingerBoneFromFingerIndex(finger))];
+
+ const float splay = inputData.splay[iFinger];
+
+ SetTransformForBone(skeleton[i], static_cast(i), curl, splay, rightHand);
}
}
-void BoneAnimator::SetTransformForBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex, const float f, const bool rightHand) const {
- if (f < 0.0f || f > 1.0f) return; // skip if the value is invalid
+// splay asssumesthat there is a valid curl value for the finger
+void BoneAnimator::SetTransformForBone(
+ vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex, const float curl, const float splay, const bool rightHand) const {
+ // We don't clamp this, as chances are if it's invalid we don't really want to use it anyway.
+ if (curl < 0.0f || curl > 1.0f) return;
const Transform nodeTransform = modelManager_->GetTransformByBoneIndex(boneIndex);
bone.orientation.x = nodeTransform.rotation[0];
@@ -268,17 +160,15 @@ void BoneAnimator::SetTransformForBone(vr::VRBoneTransform_t& bone, const HandSk
bone.position.v[1] = nodeTransform.translation[1];
bone.position.v[2] = nodeTransform.translation[2];
- const AnimationData animationData = modelManager_->GetAnimationDataByBoneIndex(boneIndex, f);
+ const AnimationData animationData = modelManager_->GetAnimationDataByBoneIndex(boneIndex, curl);
- // start and end time can be the same (if we've reached the max keyframe), so make sure we only do the lerp if not
- const float diff = animationData.endTime - animationData.startTime;
- const float interp = diff != 0.0f ? (animationData.fScaled - animationData.startTime) / diff : 1.0f;
+ const float interp = std::clamp((curl - animationData.startTime) / (animationData.endTime - animationData.startTime), 0.0f, 1.0f);
if (animationData.startTransform.rotation != emptyRotation) {
- bone.orientation.x = Lerp(animationData.startTransform.rotation[0], animationData.endTransform.rotation[0], interp);
- bone.orientation.y = Lerp(animationData.startTransform.rotation[1], animationData.endTransform.rotation[1], interp);
- bone.orientation.z = Lerp(animationData.startTransform.rotation[2], animationData.endTransform.rotation[2], interp);
- bone.orientation.w = Lerp(animationData.startTransform.rotation[3], animationData.endTransform.rotation[3], interp);
+ bone.orientation.w = Lerp(animationData.startTransform.rotation[0], animationData.endTransform.rotation[0], interp);
+ bone.orientation.x = Lerp(animationData.startTransform.rotation[1], animationData.endTransform.rotation[1], interp);
+ bone.orientation.y = Lerp(animationData.startTransform.rotation[2], animationData.endTransform.rotation[2], interp);
+ bone.orientation.z = Lerp(animationData.startTransform.rotation[3], animationData.endTransform.rotation[3], interp);
}
if (animationData.startTransform.translation != emptyTranslation) {
@@ -288,110 +178,38 @@ void BoneAnimator::SetTransformForBone(vr::VRBoneTransform_t& bone, const HandSk
}
bone.position.v[3] = 1.0f;
+ if (splay >= -1.0f && splay <= 1.0f) {
+ // only splay one bone (all the rest are done relative to this one)
+ if (IsBoneSplayableBone(boneIndex))
+ bone.orientation = MultiplyQuaternion(bone.orientation, EulerToQuaternion(0.0f, static_cast(DegToRad(splay * c_maxSplayAngle)), 0.0f));
+ }
+
+ // we're guaranteed to have updated the bone, so we can safely apply a transformation
if (!rightHand) TransformLeftBone(bone, boneIndex);
};
-void BoneAnimator::TransformLeftBone(vr::VRBoneTransform_t& bone, const HandSkeletonBone& boneIndex) {
- switch (boneIndex) {
- case HandSkeletonBone::Root: {
- return;
- }
- case HandSkeletonBone::Thumb0:
- case HandSkeletonBone::IndexFinger0:
- case HandSkeletonBone::MiddleFinger0:
- case HandSkeletonBone::RingFinger0:
- case HandSkeletonBone::PinkyFinger0: {
- const vr::HmdQuaternionf_t quat = bone.orientation;
- bone.orientation.w = -quat.x;
- bone.orientation.x = quat.w;
- bone.orientation.y = -quat.z;
- bone.orientation.z = quat.y;
- break;
- }
- case HandSkeletonBone::Wrist:
- case HandSkeletonBone::AuxIndexFinger:
- case HandSkeletonBone::AuxThumb:
- case HandSkeletonBone::AuxMiddleFinger:
- case HandSkeletonBone::AuxRingFinger:
- case HandSkeletonBone::AuxPinkyFinger: {
- bone.orientation.y *= -1;
- bone.orientation.z *= -1;
- break;
- }
- default: {
- bone.position.v[1] *= -1;
- bone.position.v[2] *= -1;
- }
+float BoneAnimator::GetAverageCurlValue(const std::array& joints) {
+ float acc = 0;
+ for (int i = 0; i < joints.size(); i++) {
+ acc += joints[i];
}
- bone.position.v[0] *= -1;
+ return acc / static_cast(joints.size());
}
-// Initial values for the right/left poses
-vr::VRBoneTransform_t rightOpenPose[NUM_BONES] = {
- {{0.000000f, 0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}},
- {{0.034038f, 0.036503f, 0.164722f, 1.000000f}, {-0.055147f, -0.078608f, 0.920279f, -0.379296f}},
- {{0.012083f, 0.028070f, 0.025050f, 1.000000f}, {0.567418f, -0.464112f, 0.623374f, -0.272106f}},
- {{-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.421979f, -0.644251f, 0.422133f, 0.478202f}},
- {{-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.541276f, -0.546723f, 0.460749f, 0.442520f}},
- {{-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.550143f, -0.516692f, 0.429888f, 0.495548f}},
- {{-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.523940f, -0.526918f, 0.326740f, 0.584025f}},
- {{-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}},
-};
+void BoneAnimator::LoadDefaultSkeletonByHand(vr::VRBoneTransform_t* skeleton, const bool rightHand) {
+ for (int i = 0; i < 31; i++) {
+ Transform transform = modelManager_->GetTransformByBoneIndex((HandSkeletonBone)i);
+ skeleton[i].orientation.w = transform.rotation[0];
+ skeleton[i].orientation.x = transform.rotation[1];
+ skeleton[i].orientation.y = transform.rotation[2];
+ skeleton[i].orientation.z = transform.rotation[3];
+
+ skeleton[i].position.v[0] = transform.translation[0];
+ skeleton[i].position.v[1] = transform.translation[1];
+ skeleton[i].position.v[2] = transform.translation[2];
+ skeleton[i].position.v[3] = 1.0f;
-vr::VRBoneTransform_t leftOpenPose[NUM_BONES] = {
- {{0.000000f, 0.000000f, 0.000000f, 1.000000f}, {1.000000f, -0.000000f, -0.000000f, 0.000000f}},
- {{-0.034038f, 0.036503f, 0.164722f, 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}},
-};
\ No newline at end of file
+ if (!rightHand) TransformLeftBone(skeleton[i], (HandSkeletonBone)i);
+ }
+}
\ No newline at end of file
diff --git a/src/Communication/SerialCommunicationManager.cpp b/src/Communication/SerialCommunicationManager.cpp
index 68b4bd26..090fad04 100644
--- a/src/Communication/SerialCommunicationManager.cpp
+++ b/src/Communication/SerialCommunicationManager.cpp
@@ -16,6 +16,25 @@ bool SerialCommunicationManager::IsConnected() {
return isConnected_;
};
+bool SerialCommunicationManager::SetCommunicationTimeout(
+ unsigned long ReadIntervalTimeout,
+ unsigned long ReadTotalTimeoutMultiplier,
+ unsigned long ReadTotalTimeoutConstant,
+ unsigned long WriteTotalTimeoutMultiplier,
+ unsigned long WriteTotalTimeoutConstant) {
+ COMMTIMEOUTS timeout;
+
+ timeout.ReadIntervalTimeout = ReadIntervalTimeout;
+ timeout.ReadTotalTimeoutConstant = ReadTotalTimeoutConstant;
+ timeout.ReadTotalTimeoutMultiplier = ReadTotalTimeoutMultiplier;
+ timeout.WriteTotalTimeoutConstant = WriteTotalTimeoutConstant;
+ timeout.WriteTotalTimeoutMultiplier = WriteTotalTimeoutMultiplier;
+
+ if (!SetCommTimeouts(hSerial_, &timeout)) return false;
+
+ return true;
+}
+
bool SerialCommunicationManager::Connect() {
LogMessage("Attempting connection to device");
// We're not yet connected
@@ -48,6 +67,16 @@ bool SerialCommunicationManager::Connect() {
return false;
}
+ if (!SetCommunicationTimeout(50, 0, 0, 50, 0)) {
+ LogError("Failed to set communication timeout");
+ return false;
+ }
+
+ if (!SetupComm(hSerial_, 200, 200)) {
+ LogError("Failed to setup comm");
+ return false;
+ }
+
// If everything went fine we're connected
isConnected_ = true;
@@ -101,7 +130,9 @@ bool SerialCommunicationManager::ReceiveNextPacket(std::string& buff) {
// will become saturated and block future reads. We've got the data we need so purge
// anything else left in the buffer. There should be more data ready for us in the
// buffer by the next time we poll for it.
- PurgeBuffer();
+ // TODO: This is currently causing lag on ESP32's so purging has been removed for now.
+ // Things to try in the future are purging on a time increment, or shrinking the buffer size.
+ // PurgeBuffer();
return true;
}
diff --git a/src/ControllerPose.cpp b/src/ControllerPose.cpp
index 3d58ff84..2595424f 100644
--- a/src/ControllerPose.cpp
+++ b/src/ControllerPose.cpp
@@ -79,7 +79,7 @@ vr::DriverPose_t ControllerPose::UpdatePose() const {
angularVelocityWorld.v[1] /= 100.0;
angularVelocityWorld.v[2] /= 100.0;
- vr::HmdQuaternion_t qAngularVelocityWorld = EulerToQuaternion(angularVelocityWorld.v[2], angularVelocityWorld.v[1], angularVelocityWorld.v[0]);
+ vr::HmdQuaternion_t qAngularVelocityWorld = EulerToQuaternion(static_cast(angularVelocityWorld.v[2]), static_cast(angularVelocityWorld.v[1]), static_cast(angularVelocityWorld.v[0]));
vr::HmdQuaternion_t qAngularVelocityObject =
MultiplyQuaternion(MultiplyQuaternion(QuatConjugate(newPose.qRotation), qAngularVelocityWorld), newPose.qRotation);
diff --git a/src/DeviceDriver/DeviceDriver.cpp b/src/DeviceDriver/DeviceDriver.cpp
index 39a2e478..798264db 100644
--- a/src/DeviceDriver/DeviceDriver.cpp
+++ b/src/DeviceDriver/DeviceDriver.cpp
@@ -17,9 +17,8 @@ DeviceDriver::DeviceDriver(
handTransforms_(),
hasActivated_(false),
driverId_(vr::k_unTrackedDeviceIndexInvalid) {
- // copy a default bone transform to our hand transform for use in finger positioning later
- std::copy(
- std::begin(IsRightHand() ? rightOpenPose : leftOpenPose), std::end(IsRightHand() ? rightOpenPose : leftOpenPose), std::begin(handTransforms_));
+ // Load in a default skeleton
+ boneAnimator_->LoadDefaultSkeletonByHand(handTransforms_, configuration_.role == vr::ETrackedControllerRole::TrackedControllerRole_RightHand);
}
vr::EVRInitError DeviceDriver::Activate(uint32_t unObjectId) {
@@ -36,7 +35,7 @@ vr::EVRInitError DeviceDriver::Activate(uint32_t unObjectId) {
IsRightHand() ? "/input/skeleton/right" : "/input/skeleton/left",
IsRightHand() ? "/skeleton/hand/right" : "/skeleton/hand/left",
"/pose/raw",
- vr::VRSkeletalTracking_Partial,
+ vr::EVRSkeletalTrackingLevel::VRSkeletalTracking_Full,
handTransforms_,
NUM_BONES,
&skeletalComponentHandle_);
@@ -52,11 +51,13 @@ vr::EVRInitError DeviceDriver::Activate(uint32_t unObjectId) {
}
void DeviceDriver::Deactivate() {
- if (hasActivated_) {
+ if (hasActivated_.exchange(false)) {
StoppingDevice();
communicationManager_->Disconnect();
driverId_ = vr::k_unTrackedDeviceIndexInvalid;
hasActivated_ = false;
+
+ poseUpdateThread_.join();
}
}
@@ -84,12 +85,19 @@ bool DeviceDriver::IsActive() {
return hasActivated_;
}
-void DeviceDriver::RunFrame() {
- if (hasActivated_) {
- vr::VRServerDriverHost()->TrackedDevicePoseUpdated(driverId_, controllerPose_->UpdatePose(), sizeof(vr::DriverPose_t));
+void DeviceDriver::PoseUpdateThread() {
+ while (hasActivated_) {
+ vr::DriverPose_t pose = controllerPose_->UpdatePose();
+ vr::VRServerDriverHost()->TrackedDevicePoseUpdated(driverId_, pose, sizeof(vr::DriverPose_t));
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(2));
}
+
+ DriverLog("Closing pose thread...");
}
+void DeviceDriver::RunFrame() {}
+
bool DeviceDriver::IsRightHand() const {
return configuration_.role == vr::TrackedControllerRole_RightHand;
}
@@ -97,14 +105,12 @@ bool DeviceDriver::IsRightHand() const {
void DeviceDriver::StartDevice() {
StartingDevice();
- vr::VRDriverInput()->UpdateSkeletonComponent(
- skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithoutController, IsRightHand() ? rightOpenPose : leftOpenPose, NUM_BONES);
- vr::VRDriverInput()->UpdateSkeletonComponent(
- skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithController, IsRightHand() ? rightOpenPose : leftOpenPose, NUM_BONES);
+ vr::VRDriverInput()->UpdateSkeletonComponent(skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithoutController, handTransforms_, NUM_BONES);
+ vr::VRDriverInput()->UpdateSkeletonComponent(skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithController, handTransforms_, NUM_BONES);
communicationManager_->BeginListener([&](VRInputData data) {
try {
- boneAnimator_->ComputeSkeletonTransforms(handTransforms_, data.flexion, IsRightHand());
+ boneAnimator_->ComputeSkeletonTransforms(handTransforms_, data, IsRightHand());
vr::VRDriverInput()->UpdateSkeletonComponent(skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithoutController, handTransforms_, NUM_BONES);
vr::VRDriverInput()->UpdateSkeletonComponent(skeletalComponentHandle_, vr::VRSkeletalMotionRange_WithController, handTransforms_, NUM_BONES);
@@ -122,4 +128,6 @@ void DeviceDriver::StartDevice() {
DebugDriverLog("Exception caught while parsing comm data");
}
});
+
+ poseUpdateThread_ = std::thread(&DeviceDriver::PoseUpdateThread, this);
}
diff --git a/src/DeviceDriver/KnuckleDriver.cpp b/src/DeviceDriver/KnuckleDriver.cpp
index 4c637e8b..d657b7c8 100644
--- a/src/DeviceDriver/KnuckleDriver.cpp
+++ b/src/DeviceDriver/KnuckleDriver.cpp
@@ -10,7 +10,8 @@ KnuckleDeviceDriver::KnuckleDeviceDriver(
const VRDeviceConfiguration configuration)
: DeviceDriver(std::move(communicationManager), std::move(boneAnimator), std::move(serialNumber), configuration),
inputComponentHandles_(),
- haptic_(), approximateThumb_(approximateThumb){}
+ haptic_(),
+ approximateThumb_(approximateThumb) {}
void KnuckleDeviceDriver::HandleInput(const VRInputData data) {
// clang-format off
@@ -21,10 +22,10 @@ void KnuckleDeviceDriver::HandleInput(const VRInputData data) {
vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ThumbstickTouch)], data.joyButton, 0);
vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TriggerClick)], data.trgButton, 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TriggerValue)], data.flexion[1], 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::TriggerValue)], boneAnimator_->GetAverageCurlValue(data.flexion[1]), 0);
vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::AClick)], data.aButton, 0);
- vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ATouch)], data.aButton || (approximateThumb_ && data.flexion[0] > 0.6), 0); //Thumb approximation
+ vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::ATouch)], data.aButton || (approximateThumb_ && boneAnimator_->GetAverageCurlValue(data.flexion[0]) > 0.6), 0); //Thumb approximation
vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::BClick)], data.bButton, 0);
vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::BTouch)], data.bButton, 0);
@@ -37,10 +38,10 @@ void KnuckleDeviceDriver::HandleInput(const VRInputData data) {
// We don't have a thumb on the index
// vr::VRDriverInput()->UpdateScalarComponent(_inputComponentHandles[(int)KnuckleDeviceComponentIndex::THUMB], data.flexion[0], 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerIndex)], data.flexion[1], 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerMiddle)], data.flexion[2], 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerRing)], data.flexion[3], 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerPinky)], data.flexion[4], 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerIndex)], boneAnimator_->GetAverageCurlValue(data.flexion[1]), 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerMiddle)], boneAnimator_->GetAverageCurlValue(data.flexion[2]), 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerRing)], boneAnimator_->GetAverageCurlValue(data.flexion[3]), 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(KnuckleDeviceComponentIndex::FingerPinky)], boneAnimator_->GetAverageCurlValue(data.flexion[4]), 0);
// clang-format on
}
diff --git a/src/DeviceDriver/LucidGloveDriver.cpp b/src/DeviceDriver/LucidGloveDriver.cpp
index fb77d97e..657a8155 100644
--- a/src/DeviceDriver/LucidGloveDriver.cpp
+++ b/src/DeviceDriver/LucidGloveDriver.cpp
@@ -25,11 +25,11 @@ void LucidGloveDeviceDriver::HandleInput(const VRInputData data) {
vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::GesGrab)], data.grab, 0);
vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::GesPinch)], data.pinch, 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgThumb)], data.flexion[0], 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgIndex)], data.flexion[1], 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgMiddle)], data.flexion[2], 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgRing)], data.flexion[3], 0);
- vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgPinky)], data.flexion[4], 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgThumb)], boneAnimator_->GetAverageCurlValue(data.flexion[0]), 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgIndex)], boneAnimator_->GetAverageCurlValue(data.flexion[1]), 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgMiddle)], boneAnimator_->GetAverageCurlValue(data.flexion[2]), 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgRing)], boneAnimator_->GetAverageCurlValue(data.flexion[3]), 0);
+ vr::VRDriverInput()->UpdateScalarComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::TrgPinky)], boneAnimator_->GetAverageCurlValue(data.flexion[4]), 0);
vr::VRDriverInput()->UpdateBooleanComponent(inputComponentHandles_[static_cast(LucidGloveDeviceComponentIndex::BtnMenu)], data.menu, 0);
// clang-format on
diff --git a/src/DeviceProvider.cpp b/src/DeviceProvider.cpp
index 4084d62f..76dfc12d 100644
--- a/src/DeviceProvider.cpp
+++ b/src/DeviceProvider.cpp
@@ -15,6 +15,11 @@
#include "Util/Quaternion.h"
#include "Util/Windows.h"
+#ifndef GIT_COMMIT_HASH
+#define GIT_COMMIT_HASH "?"
+#endif
+
+
vr::EVRInitError DeviceProvider::Init(vr::IVRDriverContext* pDriverContext) {
if (const vr::EVRInitError initError = InitServerDriverContext(pDriverContext); initError != vr::EVRInitError::VRInitError_None) return initError;
@@ -22,11 +27,14 @@ vr::EVRInitError DeviceProvider::Init(vr::IVRDriverContext* pDriverContext) {
InitDriverLog(vr::VRDriverLog());
//this won't print if running in release
- DebugDriverLog("OpenGlove is running in DEBUG mode");
+ DebugDriverLog("OpenGloves is running in DEBUG mode");
const std::string driverPath = GetDriverPath();
DriverLog("Path to DLL: %s", driverPath.c_str());
+ const std::string commitHash = GIT_COMMIT_HASH;
+ DriverLog("Built from: %s", commitHash.substr(0,10).c_str());
+
// Create background process for the overlay (used for finding controllers to bind to for tracking)
if (!CreateBackgroundProcess(driverPath + R"(\bin\win64\openglove_overlay.exe)")) {
DriverLog("Could not create background process: %c", GetLastErrorAsString().c_str());
@@ -77,7 +85,7 @@ std::unique_ptr DeviceProvider::InstantiateDeviceDriver(
switch (configuration.communicationProtocol) {
case VRCommunicationProtocol::NamedPipe: {
DriverLog("Communication set to Named Pipe");
- const std::string path = R"(\\.\pipe\vrapplication\input\)" + std::string(isRightHand ? "right" : "left");
+ const std::string path = R"(\\.\pipe\vrapplication\input\glove\v1\)" + std::string(isRightHand ? "right" : "left");
VRNamedPipeInputConfiguration namedPipeConfiguration(path);
communicationManager = std::make_unique(namedPipeConfiguration, configuration);
break;
diff --git a/src/Encode/AlphaEncodingManager.cpp b/src/Encode/AlphaEncodingManager.cpp
index d6c5b945..f00d730d 100644
--- a/src/Encode/AlphaEncodingManager.cpp
+++ b/src/Encode/AlphaEncodingManager.cpp
@@ -1,111 +1,238 @@
#include
+#include
+#include