Compare commits

...
44 Commits
Author SHA1 Message Date
Mamadou Babaei bb7e777ae6 bump the plugin version to v2.7.3 2026-02-17 13:54:51 +01:00
Mamadou Babaei b4e526996c bump mdBook to v0.5.2 2026-02-17 13:40:10 +01:00
Mamadou Babaei 114e7dfcf9 bump the plugin version to v2.7.2 2026-02-17 13:21:43 +01:00
Mamadou Babaei 944a7da804 fix incorrect toolchain linkage for ue 5.7 linux arm64 builds 2026-02-17 13:20:54 +01:00
Mamadou Babaei a2cee0762d bump the plugin version to v2.7.1 2025-12-09 13:56:11 +01:00
Mamadou Babaei 0d7c37a5fb work around a panick during handbook's pdf generation 2025-12-09 13:56:10 +01:00
Mamadou Babaei fd495d00e8 work around a ue 5.5 regression (UE-212224) while sensecom is running and gloves are connected 2025-12-09 13:25:22 +01:00
Mamadou Babaei d7e61f63e1 bump the plugin version to v2.7.0 2025-11-18 04:09:38 +01:00
Mamadou Babaei eb56601297 fix a runuat build issues on ue 5.4 2025-11-18 04:09:38 +01:00
Mamadou Babaei f639bf6957 add a new android deployment third-party tutorial for ue 5.7 2025-11-18 03:23:25 +01:00
Mamadou Babaei 810d5a7477 list ue 5.7 in the sgum-packager configuration file and update ndk paths for ue 5.6.1 2025-11-18 03:23:25 +01:00
Mamadou Babaei 94d910bc34 update the platform support matrix to refelect the latest support status 2025-11-18 03:23:25 +01:00
Mamadou Babaei b82bae52c6 add htc standalone mode deprecation warnings to the upcoming v2.7.x changelog and the relevant htc standalone mode sections in the docs 2025-11-18 03:23:25 +01:00
Mamadou Babaei fbd732b043 keep removed 5.7 changes inside SGXRTracker implementation file conditionally, in order to reduce maintenance burden 2025-11-18 03:23:25 +01:00
Mamadou Babaei fa0ff6704c revert offloading senseglove glove data retrieval api calls to timers and restore calls from tickcomponent functions 2025-11-18 03:23:25 +01:00
Mamadou Babaei 88cc8411c0 Revert "get rid of SGPawn::Tick, introduce SGPawn::HandVelocitySamplerFramerate, and make hand velocity sampler timer-based instead of tick-based"
This reverts commit 8dea65ed40.
2025-11-18 03:23:24 +01:00
Mamadou Babaei 93e8e7878b remove support for FXRMotionControllerData on UE 5.7 as it has been obliterated by the upstream and apply necessary changes to make XR_EXT_hand_tracking work again on 5.7 2025-11-18 03:23:24 +01:00
Mamadou Babaei 2a51d58f05 bump senseglove libraries to v2.305.3-17a820b6e with support for Android NDK r27c and Epic Native/Cross Toolchains v26 2025-11-18 03:23:24 +01:00
Mamadou Babaei a2f1ce5eed set default VibrotactileFrequency to 180 for optimal vibrotactile feedback 2025-11-18 03:23:22 +01:00
Mamadou Babaei 3e11112405 bump senseglove libraries to v2.304.1-fb2a464d6 2025-11-18 03:23:21 +01:00
Mamadou Babaei 9ab8f380d0 bump senseglove libraries to v2.304.0-ebcb93fc1 2025-11-18 03:23:20 +01:00
Mamadou Babaei 7eebf3eded replace QueueVibroLevels with SendCustomWaveform 2025-11-18 03:23:20 +01:00
Mamadou Babaei 9340fa293c whitespace fix 2025-11-18 03:23:20 +01:00
Mamadou Babaei 5b4139878c avoid calling senseglove glove data retrieval api from tickcomponent functions and instead offload those to background timers 2025-11-18 03:23:20 +01:00
Mamadou Babaei bbb1699fe2 return when ensure statements fail 2025-11-18 03:23:20 +01:00
Mamadou Babaei 7d44a4b373 get rid of SGPawn::Tick, introduce SGPawn::HandVelocitySamplerFramerate, and make hand velocity sampler timer-based instead of tick-based 2025-11-18 03:23:20 +01:00
Mamadou Babaei 49a5bbc8e7 rename FSGGloveTrackingSettings::GloveConnectivityCheckInterval to FSGGloveTrackingSettings::DataRetrievalRefreshRate 2025-11-18 03:23:20 +01:00
Mamadou Babaei 3056314579 apply third-party modules fixes 2025-11-18 03:23:20 +01:00
Mamadou Babaei 83a20f038d bump senseglove libraries to v2.303.0-4a2a57376 2025-11-18 03:23:19 +01:00
Mamadou Babaei 4d8a5df225 integrate sensglove libraries v2.301.0-c70bce637 and the required refactor to make it build/work 2025-11-18 03:23:17 +01:00
Mamadou Babaei a99ae9badd drop ue 5.3 and msvc 2019 support and bump the senseglove libraries to v2.205.1-cb26979ed 2025-11-18 03:23:15 +01:00
Mamadou Babaei 6b05868cbc remove remnants of the long-removed Unreal Engine 5.2 from various *.Build.cs files 2025-11-18 03:23:14 +01:00
Mamadou Babaei 5c903fe0dd remove remnants of the long-removed Unreal Engine 5.2 from SenseGloveTracking module 2025-11-18 03:23:14 +01:00
Mamadou Babaei 90805084ec remove remnants of long removed unreal 5.2 from third-party modules *.Build.cs files 2025-11-18 03:23:03 +01:00
Mamadou Babaei f6094122de re-add Source/ThirdParty/**/*.Build.cs to get tracked under git rather than lfs 2025-11-18 03:21:28 +01:00
Mamadou Babaei 892398050f delete Source/ThirdParty/**/*.Build.cs from lfs 2025-11-18 03:21:28 +01:00
Mamadou Babaei 524aa1cd4e bump the plugin version to v2.6.3 2025-06-27 18:34:23 +02:00
Mamadou Babaei 602f8b4470 add third-party openxr integration documentation section 2025-06-27 18:34:23 +02:00
Mamadou Babaei 519e00755c bump the plugin version to v2.6.2 2025-06-10 09:13:47 +02:00
Mamadou Babaei b32491811d add a vr optimization third-party tutorial 2025-06-10 09:13:47 +02:00
Mamadou Babaei 516d246793 bump the plugin version to v2.6.1 2025-06-05 13:20:13 +02:00
Mamadou Babaei 7fb4c7b5eb changelog fixes 2025-06-05 12:38:32 +02:00
Mamadou Babaei 4009892861 bump senseglove libraries to v2.204.0-3a37b1977 2025-06-05 12:38:31 +02:00
Mamadou Babaei f540872fa3 fix a changelog typo 2025-06-05 12:38:29 +02:00
3956 changed files with 4125 additions and 11431 deletions
+3 -1
View File
@@ -38,6 +38,8 @@ Resources/**/* filter=lfs diff=lfs merge=lfs -text
# LFS: everything under Source/ThirdParty/
Source/ThirdParty/**/* filter=lfs diff=lfs merge=lfs -text
# Except
Source/ThirdParty/**/*.Build.cs filter= diff= merge= text
# LFS: everything under Handbook/dist/
Handbook/dist/**/* filter=lfs diff=lfs merge=lfs -text
@@ -47,4 +49,4 @@ Handbook/dist/**/* filter=lfs diff=lfs merge=lfs -text
# LFS: sgum-packager Linux and Windows binaries
Packager/sgum-packager filter=lfs diff=lfs merge=lfs -text
Packager/sgum-packager.exe filter=lfs diff=lfs merge=lfs -text
Packager/sgum-packager.exe filter=lfs diff=lfs merge=lfs -text
+3 -4
View File
@@ -365,17 +365,16 @@ clean:
.PHONY: install-build-deps
install-build-deps:
@echo "Installing build dependencies if they have not already been installed..."
@cargo install mdbook --version "0.4.49" --locked
@cargo install mdbook --version "0.5.2" --locked
@cargo install xq --vers "^0.4" --locked
@cargo install mdbook-alerts --vers "^0.7" --locked
@cargo install mdbook-pdf --vers "^0.1" --locked
@cargo install mdbook-pdf --vers "0.1.13" --locked
ifeq ($(SG_BUILD_PLATFORM),$(SG_BUILD_PLATFORM_LINUX))
@echo "Installing mdbook-pdf-outline..."
@python -m venv $(VIRTUAL_ENV) \
&& . $(SG_LINUX_PYTHON_VENV_BIN_DIR)/activate \
&& pip install mdbook-pdf-outline 2>/dev/null
endif # ($(SG_BUILD_PLATFORM),$(SG_BUILD_PLATFORM_LINUX))
@cargo install --git https://github.com/Michael-F-Bryan/mdbook-epub --rev cac03b7f4b151f106f7f05b13da4c33fc098dd2c --locked
@cargo install --git https://github.com/Michael-F-Bryan/mdbook-epub --rev 21a1c8134134201a2d555313447c96e56e2a8996 --locked
################################################################################
# Make Targets - mdBook
+5 -5
View File
@@ -33,8 +33,8 @@ fi
readonly JSON_INPUT=$(cat)
readonly CONTEXT=$(echo "${JSON_INPUT}" | xq '.[0]')
readonly BOOK=$(echo "${JSON_INPUT}" | xq '.[1]')
readonly CONTEXT=$(printf '%s' "${JSON_INPUT}" | xq '.[0]')
readonly BOOK=$(printf '%s' "${JSON_INPUT}" | xq '.[1]')
escape_string() {
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'
@@ -63,8 +63,8 @@ SG_PLUGIN_VERSION_PATCH_ESCAPED=$(escape_string "${SG_PLUGIN_VERSION_PATCH}")
SG_BUILD_HOST_ESCAPED=$(escape_string "${SG_BUILD_HOST}")
SG_BUILD_TIME_ESCAPED=$(escape_string "${SG_BUILD_TIME}")
PARSED_BOOK=$(echo "${BOOK}" | xq "
.sections[] |= (
PARSED_BOOK=$(printf '%s' "${BOOK}" | xq "
.items[] |= (
if has(\"Chapter\") then
.Chapter.content |=
walk(if type == \"string\" then
@@ -103,4 +103,4 @@ PARSED_BOOK=$(echo "${BOOK}" | xq "
#echo "BOOK: ${BOOK}" >&2
#echo "PARSED_BOOK: ${PARSED_BOOK}" >&2
echo "${PARSED_BOOK}" | xq '.'
printf '%s' "${PARSED_BOOK}"
+1 -5
View File
@@ -28,7 +28,6 @@
authors = ["Mamadou Babaei"]
description = "Welcome to the SenseGlove Unreal Engine documentation!"
language = "en"
multilingual = false
src = "src"
text-direction = "ltr"
title = "The SenseGlove Unreal Engine Handbook"
@@ -43,8 +42,6 @@ use-default-preprocessors = true
[preprocessor.links]
[preprocessor.alerts]
[preprocessor.senseglove]
after = [ "index", "links" ]
command = "sh ./bin/sg-preprocessor.sh"
@@ -59,10 +56,9 @@ footnote-backrefs = true
additional-css = ["styles/custom.css"]
additional-js = []
cname = "unreal.docs.senseglove.com"
copy-fonts = true
default-theme = "navy"
git-repository-url = "https://dev.azure.com/SenseGlove/_git/SenseGlove-Unreal"
git-repository-icon = "fa-git"
git-repository-icon = "fab-git"
input-404 = "404.md"
mathjax-support = false
no-section-label = false
+4
View File
@@ -68,6 +68,7 @@ Welcom to the SenseGlove Unreal Engine Handbook!
- [Third-Party Tutorials](misc/android-standalone-deployment/third-party-tutorials/README.md)
- [Upgrade Guide](misc/upgrade-guide/README.md)
- [Optimizing for Higher FPS](misc/optimize-higher-fps/README.md)
- [Third-Party Tutorials](misc/optimize-higher-fps/third-party-tutorials/README.md)
# 🛠️ Advanced Topics
@@ -79,6 +80,7 @@ Welcom to the SenseGlove Unreal Engine Handbook!
- [Consuming FXRMotionControllerData](advanced-topics/openxr/consuming-fxrmotioncontrollerdata/README.md)
- [Blueprint](advanced-topics/openxr/consuming-fxrmotioncontrollerdata/blueprint.md)
- [C++](advanced-topics/openxr/consuming-fxrmotioncontrollerdata/cpp.md)
- [Third-Party Integrations](advanced-topics/openxr/third-party-integrations/README.md)
- [Third-Party Tutorials](advanced-topics/openxr/third-party-tutorials/README.md)
# 🔌 Low-Level API
@@ -102,6 +104,8 @@ Welcom to the SenseGlove Unreal Engine Handbook!
- [SenseGlove SDK License](license/senseglove-sdk.md)
- [SGBLE and SGBLExx Rust Dependencies Licenses](license/sgble-sgblexx-rust-dependencies.md)
- [Boost C++ Libraries License](license/boost-cpp-libraries.md)
- [{fmt} Formatting Library License](license/fmt-formatting-library.md)
- [Loguru Logging Library License](license/loguru-loggin-library.md)
- [Serial Communication Library License](license/serial-communication-library.md)
-----------
@@ -0,0 +1,265 @@
# Third-Party OpenXR Integrations
The **SenseGlove Unreal Engine Plugin** registers itself as an `OpenXRHandTracking` provider, making it a fully compatible, drop-in replacement for Epics own **OpenXRHandTracking** plugin in Unreal Engine. This allows it to integrate seamlessly with any third-party system or plugin that can consume OpenXR hand-tracking data.
One notable example is the open-source, MIT-licensed [VR Expansion Plugin (VRE)](#vr-expansion-plugin).
> [!IMPORTANT]
> As explained in the
> [Third-Party Tutorials: Consuming OpenXR Hand-Tracking Data](../third-party-tutorials/)
> section, its entirely possible to build your own custom hand interaction
> system without relying on
> [SGPawn](../../../getting-started/setup-senseglove-default-classes/sgpawn.html)
> or any third-party OpenXR-compatible interaction plugin altogether.
>
> If your project requires finer-grained control than what these solutions
> offer, the tutorials in that section will guide you through understanding the
> OpenXR hand-tracking data format in Unreal Engine and help you implement a
> fully tailored interaction system from the ground up in a few hours.
As the SenseGlove Unreal Engine Plugin is fully OpenXR-compliant, it provides OpenXR hand-tracking data in the expected format and takes over as the active provider within Unreal. If your existing interaction system (e.g. VRE plugin) already uses OpenXR hand-tracking, SenseGlove will function as a direct tracking source instead of a real hand.
> [!NOTE]
> Since most hand-tracking systems are not capable of haptics feedback,
> integrating SenseGlove's haptic feedback requires a small amount of additional
> effort.
>
> The SenseGlove API is fully exposed to Unreal Engine via C++ and Blueprint,
> so triggering haptic feedback is as simple as calling a function.
> For more information, refer to the [Blueprint Changes](#blueprint-changes)
> section below.
> [!IMPORTANT]
> If you're using a third-party OpenXR hand interaction system, configuring the
> [Wrist-Tracker Hardware Settings](../../../getting-started/setup-wrist-tracking-hardware/)
> will likely have no effect, and your hand offsets may appear at the incorrect
> location in the scene.
>
> This is because those settings are only recognized by SenseGloves native
> actors and components such as `SGPawn`, `SGWristTrackerComponent`, etc.
> Most third-party plugins are unaware of these settings. As a result, you'll
> need to figure out how to manually apply the appropriate offsets within your
> chosen OpenXR hand interaction system.
>
> For example, the VRE plugin provide similar configurations in their plugin's
> settings section. For more information refer to the
> [Changing Wrist-Tracker Offsets](#changing-wrist-tracker-offsets) section
> below.
## Comparison of Supported OpenXR Hand-Interaction Systems
| | **Built-in?** | **Works out of the box?** | **Beginner-friendly?** | **Learning Curve** | **Featureful** | **Customizable?** | **Supports Custom Gestures?** |
|-------------------------------------|---------------|------------------------------------|--------------------------------------------------|-----------------------------|--------------------------------------------------------------------------|-----------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------|
| **SGPawn** | ✅ Yes | ✅ Yes | ✅ Most beginer-friendly | ✅ Very easy | ⚠️ Very basic | ⚠️ Very limited | ❌ Not yet, maybe added in the future |
| **SenseGlove OpenXR** | ✅ Yes | ❌ Requires Blueprint or C++ coding | ✅ Requires a few hours of watching tutotrials | ✅ Moderate | ❌ You need to develop your own features and functionalities from scratch | ✅ Your imagination, creativity, and skill level are your limits | ✅ You have to implement your own recognition logic; example pinch detection algorithm is taught in the tutorial series |
| **VR Expansion Plugin** | ❌ No | ⚠️ Partially requires setup | ❌ Best suited for intermediate or advanced users | ⚠️ Steep | ✅ Diverse features and functionalities | ✅ Highly customizable | ✅ Via custom logic |
| **Other OpenXR-compatible Plugins** | ❌ No | ❓ Check their documentation | ❓ Check their documentation | ❓ Check their documentation | ❓ Check their documentation | ❓ Check their documentation | ❓ Check their documentation |
## VR Expansion Plugin
The [**VR Expansion Plugin (VRE)**](https://vreue4.com/) is a robust, community-driven plugin for Unreal Engine that focuses on advanced VR interaction and gameplay mechanics. It is open-source (MIT licensed), actively maintained, and has received support from Epic via the [MegaGrants program](https://www.unrealengine.com/en-US/megagrants).
Designed to extend Unreals capabilities for virtual reality, VRE offers a modular set of tools covering:
- Multiplayer and networking
- Locomotion systems
- Object gripping and interaction
- Custom movement and physics handling
The plugin is particularly useful for teams building sophisticated VR experiences. While it's beginner-friendly to an extent, its depth and flexibility are **best suited for intermediate to advanced Unreal Engine developers**. Whether you're prototyping with built-in features or extracting specific systems for your own framework, VRE offers a rich foundation for VR development.
> [!NOTE]
> For support and assistance with the VRE plugin, you can join
> [its active and welcoming Discord community](https://discord.gg/P4V7TY8BQy),
> known for being responsive and supportive.
### SGVRETemplate Demo Scene
To showcase how SenseGlove can be integrated with OpenXR-compatible third-party interaction systems, SenseGlove provides a ready-to-use [VR Expansion Plugin Integration Demo for Unreal Engine 5.4](https://dev.azure.com/SenseGlove/_git/SGVRETemplate).
This repository includes UE `5.4`compatible versions of both the **SenseGlove** and **VR Expansion** plugins, with all necessary setup and configuration already in place. Simply download the project and it should run out of the box, allowing you to explore the integration without additional setup.
> [!NOTE]
> SenseGlove provides this demo to demonstrate the potential for integrating
> with third-party OpenXR-based hand interaction systems.
> Please note that the **VR Expansion Plugin** is a third-party solution, and as
> such, **we do not offer official support for it**.
>
> For help with the VRE plugin, refer to its documentation at
> [**vreue4.com**](https://vreue4.com/) and consider joining the
> [**official VRE Discord community**](https://discord.gg/P4V7TY8BQy),
> which is active, supportive, and very responsive.
### SGVRETemplate Modifications
The [**SGVRETemplate**](https://dev.azure.com/SenseGlove/_git/SGVRETemplate) is built on top of the [VR Expansion Plugin Example Template](https://github.com/mordentral/VRExpPluginExample). However, since the original template is not directly compatible with SenseGlove, several adjustments were necessary.
In addition, a few known issues with OpenXR support in the VR Expansion Plugin for Unreal Engine `5.4` required us to modify the plugin itself to ensure smooth integration.
Below is an overview of the key modifications made to both the project template and this version of the VRE plugin.
#### Blueprint Changes
- **Content/VRE/Core/Character/BP_VRCharacter**: Four functions were added: `SendVibration`, `SendFFB`, `SendSqueeze`, and `ResetHaptics`. These functions retrieve the glove instance and send the appropriate haptic command to it. In the `OnPossessed` event, `Load Controller by Name` was added along with a string uproperty `Tracking Offset`, which is used to load the correct tracking offsets based on the selected profile.
> [!NOTE]
> If you'd like to implement your own haptic functions, the most convenient
> approach is to
> [safely acquire a glove instance](../../../advanced-topics/safe-glove-access-blueprint/).
> Once you have the glove instance, applying haptic feedback is as simple as
> calling the appropriate function.
>
> SenseGlove supports three types of haptics: Vibrations, Force-feedback, and
> Wrist-squeeze.
>
> - Using `Send Custom Waveform`, you can send vibrations to the glove instance.
> - Using `Queue Command Force Feedback Levels`, you can send force-feedback.
> - Using `Queue Command Wrist Squeeze`, you can send a wrist-squeeze command to
> the glove.
>
> Each of these functions can be called directly on the glove instance to
> trigger the desired haptic feedback.
- **Content/VRE/Core/GraspingHands/GraspingHandManny**: In the `SetupFingerAnimations` function, replace the hardcoded check for `HandType == Left` with a string comparison: convert the enum to a string and check if it contains `"Left"`. This allows compatibility with alternative tracking sources such as `"Left Foot"`.
#### C++ Changes
- **Plugins/VRExpansionPlugin/Source/VRExpansionPlugin/Public/Grippables/HandSocketComponent.h**: The following line was added as a public `UPROPERTY` in the header file:
```cpp
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Hand Animation")
float HandAnimationProgress = 0.0f;
```
- **Plugins/VRExpansionPlugin/Source/VRExpansionPlugin/Private/Grippables/HandSocketComponent.cpp**: In the function `bool UHandSocketComponent::GetBlendedPoseSnapShot(FPoseSnapshot& PoseSnapShot, USkeletalMeshComponent* TargetMesh, bool bSkipRootBone, bool bFlipHand)`, the `TrackLocation` calculation was modified from:
```cpp
if (TrackIndex != INDEX_NONE && (!bSkipRootBone || TrackIndex != 0))
{
double TrackLocation = 0.0f;
HandTargetAnimation->GetBoneTransform(LocalTransform, FSkeletonPoseBoneIndex(TrackMap[TrackIndex].BoneTreeIndex), TrackLocation, false);
}
else
{
```
To:
```cpp
if (TrackIndex != INDEX_NONE && (!bSkipRootBone || TrackIndex != 0))
{
double TrackLocation = HandTargetAnimation->GetPlayLength() * HandAnimationProgress;
HandTargetAnimation->GetBoneTransform(LocalTransform, FSkeletonPoseBoneIndex(TrackMap[TrackIndex].BoneTreeIndex), TrackLocation, false);
}
else
{
```
- **Plugins/VRExpansionPlugin/Source/VRExpansionPlugin/Private/GripMotionControllerComponent.cpp**: In the function `void UGripMotionControllerComponent::GetCurrentProfileTransform(bool bBindToNoticationDelegate)`, the following logic was updated from:
```cpp
if (HandType == EControllerHand::Left || HandType == EControllerHand::AnyHand || !VRSettings->bUseSeperateHandTransforms)
{
NewControllerProfileTransform = VRSettings->CurrentControllerProfileTransform;
}
else if (HandType == EControllerHand::Right)
{
NewControllerProfileTransform = VRSettings->CurrentControllerProfileTransformRight;
}
```
To:
```cpp
if (UEnum::GetDisplayValueAsText(HandType).ToString().Contains("Left") || HandType == EControllerHand::AnyHand || !VRSettings->bUseSeperateHandTransforms)
{
NewControllerProfileTransform = VRSettings->CurrentControllerProfileTransform;
}
else if (UEnum::GetDisplayValueAsText(HandType).ToString().Contains("Right"))
{
NewControllerProfileTransform = VRSettings->CurrentControllerProfileTransformRight;
}
```
The following function was also updated; from:
```cpp
void UGripMotionControllerComponent::GetHandType(EControllerHand& Hand)
{
if (!IMotionController::GetHandEnumForSourceName(MotionSource, Hand))
{
// Check if the palm motion source extension is being used
// I assume eventually epic will handle this case
if (MotionSource.Compare(FName(TEXT("RightPalm"))) == 0 || MotionSource.Compare(FName(TEXT("RightWrist"))) == 0)
{
Hand = EControllerHand::Right;
}
// Could skip this and default to left now but would rather check
else if (MotionSource.Compare(FName(TEXT("LeftPalm"))) == 0 || MotionSource.Compare(FName(TEXT("LeftWrist"))) == 0)
{
Hand = EControllerHand::Left;
}
else
{
Hand = EControllerHand::Left;
}
}
}
```
To:
```cpp
void UGripMotionControllerComponent::GetHandType(EControllerHand& Hand)
{
if (!IMotionController::GetHandEnumForSourceName(MotionSource, Hand))
{
// Check if the palm motion source extension is being used
// I assume eventually epic will handle this case
if (MotionSource.Compare(FName(TEXT("RightPalm"))) == 0 || MotionSource.Compare(FName(TEXT("RightWrist"))) == 0 || MotionSource.ToString().Contains("Right"))
{
Hand = EControllerHand::Right;
}
// Could skip this and default to left now but would rather check
else if (MotionSource.Compare(FName(TEXT("LeftPalm"))) == 0 || MotionSource.Compare(FName(TEXT("LeftWrist"))) == 0 || MotionSource.ToString().Contains("Left"))
{
Hand = EControllerHand::Left;
}
else
{
Hand = EControllerHand::Left;
}
}
}
```
#### Changing Wrist-Tracker Offsets
If you are using wrist-tracking hardware supported by the SenseGlove plugin, you can change the offsets inside `BP_VRCharacter` using the uproperty `Tracking Offset` typing or copying any of the following, depending on your hardware:
- **SenseGlove_Quest3**: The wrist-tracking controller profile for for Meta Quest3.
- **SenseGlove_ViveWristTrackers**: The wrist-tracking controller profile for HTC VIVE wrist trackers.
#### Changing Motion Source
In `BP_VRCharacter`, you can change the wrist-tracking motion source for each hand. This is required depending on which tracker you are using.
#### Adding More Gestures
In the `GraspingHandManny` Blueprint, weve created a simple function called `SaveHandPose`. If you press the `Space Bar` while the game is running, it will save the current pose of the corresponding hand. The pose is stored in a gestures database located under `Content/SenseGlove` with the default name `NewHandPose`. You should rename the pose to something meaningful when you intend to use it.
Its helpful to add an Event Dispatcher to the `GraspingHandManny` Blueprint, which is triggered in the Event Graph by the `On New Gesture Detected` event from the `OpenXRHandPose` component. This system is index-based rather than name-based, so keep that in mind when adding more dispatchers. By default, weve included examples for `Teleport`, `Grab`, `Release`, and `Use`.
#### Video Summary
This short video provides an overview of some of the key changes and modifications behind the SGVRETemplate demo scene, mentioned above.
<div style="margin: 0 auto; width: 560px;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/6uTu4T10mjU" frameborder="0" allowfullscreen></iframe>
</div>
### SGVRETemplate Demo Calibration Scene
The SGVRETemplate includes a basic Calibration Scene located at `Content/SenseGlove/Maps/Calibration`. Inside this level, youll find a copy of `Content/SenseGlove/Blueprints/Calibration/BP_Calibrator` Blueprint responsible for transitioning to your desired target map after the calibration process is complete. You can configure the target map directly within this Blueprint by adjusting the `Level to Load` uproperty.
+151 -1
View File
@@ -5,9 +5,159 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [2.7.3] - 2026-02-17
This patch release resolves documentation build pipeline failures by updating broken mdBook tooling.
### Documentation
- Bumped [mdBook](https://rust-lang.github.io/mdBook/) to `v0.5.2`
- Bumped the [Michael-F-Bryan/mdbook-epub](https://github.com/Michael-F-Bryan/mdbook-epub) crate to [`21a1c8134134201a2d555313447c96e56e2a8996`](https://github.com/Michael-F-Bryan/mdbook-epub/commit/21a1c8134134201a2d555313447c96e56e2a8996), which addresses issue [#133](https://github.com/Michael-F-Bryan/mdbook-epub/issues/133). This allowed upgrading mdBook from `0.4.49` to `v0.5.2` without breaking images inside the generated ePub version of the handbook.
- Bumped [HollowMan6/mdbook-pdf](https://github.com/HollowMan6/mdbook-pdf) to `v0.1.13`.
- Removed [lambdalisue/rs-mdbook-alerts](https://github.com/lambdalisue/rs-mdbook-alerts) as it's incompatible with mdBook `v0.5.x`. The good news is that mdBook itself is now able to support this feature natively.
## [2.7.2] - 2026-02-17
This patch release resolves build issues affecting Unreal Engine `5.7` on Linux `Arm64` architecture.
### Fixed
- Fixed an issue in UE `5.7` projects where Linux `Arm64` builds were incorrectly linking against third-party libraries compiled with Epic Native/Cross Toolchain `v25` (shipped with UE `5.6`), instead of the required Toolchain `v26` binaries (shipped with UE `5.7`).
## [2.7.1] - 2025-12-09
This patch release addresses a severe regression affecting UE `5.5` projects with specific settings.
### Fixed
- Resolved a critical deadlock between the rendering and game threads in Unreal Engine `5.5` that when `IHeadMountedDisplay::GetHMDMonitorInfo()` is invoked from `FSGXRTracker::GetControllerTransform()` in certain conditions; specifically while SenseCom is running and gloves are present and connected. This issue is [related to critical deadlock issue (UE-212224), occurring during PipelinedFrameState acquisition, which had already been addressed for the plugin versions running on UE `5.6+`](#260---2025-06-04). Because it only gets triggered under specific project settings, we were previously unaware that it also affected IHeadMountedDisplay::GetHMDMonitorInfo() in UE 5.5.
### Documentation
- Locked the [mdbook-pdf](https://github.com/HollowMan6/mdbook-pdf) crate to [`v0.1.11`](https://github.com/HollowMan6/mdbook-pdf/releases/tag/v0.1.11) due to the following `v0.1.12` panick during PDF generation: called `Result::unwrap()` on an `Err` value: Unable to deserialize the `RenderContext`.
## [2.7.0] - 2025-11-18
This minor release focuses on delivering performance improvements, made possible by major optimizations in the underlying proprietary SenseGlove libraries, while also introducing some breaking changes.
### Added
- Added support for UE `5.7`.
- Added support for Android NDK `r27c`, which is the recommend Android SDK since UE `5.6.1` and the default for UE `5.7+` for Android Standalone builds.
- Added support for Epic Cross and Native Toolchains `v26`, which is shipped with the UE `5.7` and GNU/Linux support.
- Added prebuilt binaries for third-party library [{fmt} Formatting Library](https://github.com/fmtlib/fmt) on all supported platforms. This third-party library is a required dependency of SenseGlove libraries >= `v2.300.0`.
- Added prebuilt binaries for third-party library: [Loguru Logging Library](https://github.com/emilk/loguru) on all supported platforms. This third-party library is a required dependency of SenseGlove libraries >= `v2.300.0`.
- Added third-party module `SGCommonThirdPartyLibs`.
- Added third-party module `SGConnectShmThirdPartyLibs`.
- Added third-party module `SGCoreShmThirdPartyLibs`.
- Added third-party module `SGCoreThirdPartyHeaders`.
- Added third-party module `SGFmtThirdPartyLibs`.
- Added third-party module `SGLogThirdPartyLibs`.
- Added third-party module `SGLoguruThirdPartyLibs`.
- Added third-party module `SGWjwwoodSerialThirdPartyLibs` to replace `SGSerialThirdPartyLibs` while retaining `SGSerialThirdPartyLibs` for a different purpose. See the relevant comment in the Changed section below.
- Added UPROPERTY `USGTouchComponent::VibrotactileAmplitude`.
- Added UPROPERTY `USGTouchComponent::VibrotactileFrequency`.
- Added method `USGTouchComponent::GetVibrotactileAmplitude()`.
- Added method `USGTouchComponent::SetVibrotactileAmplitude()`.
- Added method `USGTouchComponent::GetVibrotactileFrequency()`.
- Added method `USGTouchComponent::SetVibrotactileFrequency()`.
- Added Blueprint-accessible method `USGTouchComponentKismetLibrary::GetVibrotactileAmplitude()`.
- Added Blueprint-accessible method `USGTouchComponentKismetLibrary::SetVibrotactileAmplitude()`.
- Added Blueprint-accessible method `USGTouchComponentKismetLibrary::GetVibrotactileFrequency()`.
- Added Blueprint-accessible method `USGTouchComponentKismetLibrary::SetVibrotactileFrequency()`.
### Fixed
- Fix a typo in the function name `SGDeviceList::SenseCommRunning()`. This fix breaks ABI and API compatibility with previous versions of the plugin and affects both C++ and Blueprint code.
### Changed
- `SGDeviceList::SenseCommRunning()` has been renamed to `SGDeviceList::SenseComRunning()` due to a typo. This change breaks ABI and API compatibility with previous versions of the plugin and affects both C++ and Blueprint code.
- Bumped the SenseGlove libraries to `v2.305.3-17a820b6e`. This release of the SenseGlove libraries disables RTTI/Exceptions for the most parts and isolates it to a minor portion of the code base, which yields noticable performance gains. Futhermore, some optiomizations are done in the multi-threaded code, such as replacing Spinlocks with Adaptive Mutexes (a hybrid Mutex/Spinlock).
- As a result of SenseGlove libraries >= `v2.300.0` changing it's directory structure, the `ThirdParty` folder's directory structure has been revamped.
- Renamed third-party module `SGSerialThirdPartyLibs` to `SGWjwwoodSerialThirdPartyLibs` since SenseGlove libraries >= `v2.300.0` ships a new static library named `sgserial`. Thus, to avoid confusion and naming conflicts the third-party `serial` static library is now provided by the `SGWjwwoodSerialThirdPartyLibs` module and `sgserial` is provided by the `SGSerialThirdPartyLibs` module.
- `FSGGloveTrackingSettings::GloveConnectivityCheckInterval` settings have been renamed to `FSGGloveTrackingSettings::DataRetrievalRefreshRate` for adoption other than glove connectivity use cases.
- `USGVirtualHandComponent::GetMotionControllerData()` signature has changed.
- `USGVirtualHandComponent::GetHandTrackingState()` signature has changed.
- `USGWristTrackerComponent::GetMotionControllerData()` signature has changed.
- `USGWristTrackerComponent::GetHandTrackingState()` signature has changed.
- `USGVirtualHandComponentKismetLibrary::GetMotionControllerData()` signature has changed.
- `USGVirtualHandComponentKismetLibrary::GetHandTrackingState()` signature has changed.
- `SGPawn` and `SGTouchComponent` no longer use the legacy `QueueVibroLevels` method for applying vibrotactile feedback. Instead it's been replaced with `SendCustomWaveform`.
- Changed `USGTouchComponent::VibrotactileDuration` UPROPERTY's maximum value to `1.0f`. Previously it was uncapped, and now any value beyond `1.0f` seconds is clamped.
### Removed
- Dropped support for Unreal Engine `5.3`, which was already deprecated in the `v2.6.x` release series.
- Dropped support for MSVC `v142` (Visual Studio 2019), since UE `5.3` was the last supported version relying on it.
- Cleaned up remnants of the long-removed Unreal Engine `5.2` from third-party module `*.Build.cs` files.
- Cleaned up remnants of the long-removed Unreal Engine `5.2` from `SenseGlove.Build.cs`, `SenseGloveKismet.Build.cs`, `SenseGloveTracking.Build.cs`, files.
- Cleaned up remnants of the long-removed Unreal Engine `5.2` from `SenseGloveTracking` module.
- `USGVirtualHandComponent::GetMotionControllerState()` has been removed.
- `USGWristTrackerComponent::GetMotionControllerState()` has been removed.
- `USGVirtualHandComponentKismetLibrary::GetMotionControllerState()` has been removed.
- `USGWristTrackerComponentKismetLibrary::GetMotionControllerState()` has been removed.
- `USGTouchComponent::VibrotactileLevel` UPROPERTY has been removed.
- `USGTouchComponent::GetVibrotactileLevel()` method has been removed.
- `USGTouchComponent::SetVibrotactileLevel()` method has been removed.
- `USGTouchComponentKismetLibrary::GetVibrotactileLevel()` method has been removed and is no longer available to Blueprint.
- `USGTouchComponentKismetLibrary::SetVibrotactileLevel()` method has been removed and is no longer available to Blueprint.
### Deprecated
- **This is the last major/minor release to support Unreal Engine `5.4`**, and its support will be removed in future minor or major releases. This is **important to keep in mind if your target development and deployment platform is [HTC VIVE in Standalone Mode](../getting-started/enabling-xr-ext-hand-tracking-vr-headsets/standalone-mode/index.html#htc-vive)**. Unfortunately, HTC has not released any updates to their HTC ViveOpenXR plugin since December 6, 2024. Their [latest release](https://developer.vive.com/resources/openxr/unreal/unreal-download/latest/) [[1]](https://web.archive.org/web/20251113165658/https://developer.vive.com/resources/openxr/unreal/unreal-download/latest/) [[2]](https://archive.ph/DlrLr), ViveOpenXR Plugin `v2.5.0`, supports only Unreal Engine `5.3` and `5.4`. [HTC VIVE PCVR Mode](../getting-started/enabling-xr-ext-hand-tracking-vr-headsets/pcvr-mode/index.html#htc-vive) is unaffected and will remain fully functional because, on Microsoft Windows, it is supported via the [OpenXRViveTracker Plugin](../getting-started/enabling-xr-ext-hand-tracking-vr-headsets/pcvr-mode/index.html#openxrvivetracker-plugin), which is bundled with Unreal Engine and officially maintained by Epic Games. If you still intend to target HTC in Standalone Mode, you are welcome to continue using the latest SenseGlove Unreal Engine Plugin `v2.7.x`, which will retain HTC Standalone Mode support. However, please keep in mind that once newer versions of the SenseGlove Unreal Engine Plugin are released and UE `5.4` is no longer supported, the latest release of the plugin supporting UE `5.4` will not receive new features, hardware support, or bug fixes. If at any point in the future HTC releases a new version of their ViveOpenXR plugin that supports any Unreal Engine version we actively support, [in accordance with our support policy and Platform Support Matrix](../appendix/platform-support-matrix.html), we will make every reasonable effort to reintroduce HTC Standalone Mode support.
### Documentation
- Added [{fmt} Formatting Library License](../license/fmt-formatting-library.html) section.
- Added [Loguru Logging Library License](../license/loguru-loggin-library.html) section.
- Updated [Setting up the Touch System](../getting-started/setup-touch-system/index.html) section to reflect the recent touch system changes.
- Added [a third-party tutorial to the Android Standalone Mode Deployment](../misc/android-standalone-deployment/third-party-tutorials/) section for UE `5.7` which provides a one-click Android development and build environment setup, instructions on how to setup and use the new UE `5.7` project launcher, and how to enabled OpenXR hand-tracking support on Meta Quest and HTC VIVE devices.
## [2.6.3] - 2025-06-27
This patch release contains no changes to the plugin code. It includes only documentation updates and improvements.
### Documentation
- Added a new section to the handbook titled [Third-Party OpenXR Integrations](../advanced-topics/openxr/third-party-integrations/) section.
- Additional minor fixes and improvements that may not be listed here.
## [2.6.2] - 2025-06-10
This patch release contains no changes to the plugin code. It includes only documentation updates and improvements.
### Documentation
- Added [a third-party tutorial to the Optimizing Your Project for Higher FPS](../misc/optimize-higher-fps/third-party-tutorials/) section.
## [2.6.1] - 2025-06-05
This patch release addresses several critical build and linking issues.
### Fixed
- Fix a linking issue on GNU/Linux with UE `5.6` where SenseGlove libraries were built against dynamic versions of `libc++` and `libc++abi` libraries rather than the static versions.
- Fix an issue where SenseGlove libraries for some targets were not actually built with `C++20` and still were built against `C++17`.
- Fix an issue where SenseGlove libraries for some targets were built or linked with incorrect settings.
- Additional minor fixes and improvements that may not be listed here.
### Changed
- Bumped the SenseGlove libraries to `v2.204.0-3a37b1977`.
### Removed
- SenseGlove plugin no longer ships Boost or wjwwood's Serial Communication Library header files as SenseGlove public headers shipped with `v2.204.0-3a37b1977` render them redundant. This significantly removes clutter, free up disk space, and speed up builds to some extent.
### Documentation
- Fix some changelog typos.
- Additional minor fixes and improvements that may not be listed here.
## [2.6.0] - 2025-06-04
This minor release delivers broad compatibility, stability, and maintainability enhancements, focusing on brining full Unreal Engine `5.6` support, C++20 migration, and resolving various GNU/Linux build issues.
This minor release delivers broad compatibility, stability, and maintainability enhancements, focusing on bringing full Unreal Engine `5.6` support, C++20 migration, and resolving various GNU/Linux build issues.
### Added
+26 -28
View File
@@ -69,17 +69,17 @@
├── include (header files)
│ │
── boost
│ │
├── SenseGlove
├── BLE (SGBLE headers)
├── Connect (SGConnect headers)
── Core (SGCoreCpp headers)
│ │
└── serial
── SenseGlove
├── BLE (SGBLE headers)
├── Common (SGCommon headers)
├── Connect (SGConnect headers)
── Core (SGCore headers)
└── Log (SGLog headers)
├── lib (platform-specific pre-built binary dependencies)
│ │
@@ -87,13 +87,13 @@
│ │ │
│ │ └── r25b (Android NDK r25b dependencies for UE 5.1+)
│ │ │
│ │ ├── arm64 (64-bit ARM variant of Android)
│ │ ├── aarch64 (64-bit ARM variant of Android)
│ │ │ │
│ │ │ ├── debug
│ │ │ │
│ │ │ └── release
│ │ │
│ │ └── x64 (64-bit x86-64 variant of Android)
│ │ └── x86-64 (64-bit x86-64 variant of Android)
│ │ │
│ │ ├── debug
│ │ │
@@ -115,7 +115,7 @@
│ │ │ │
│ │ │ └── release
│ │ │
│ │ ├── v22 (UE 5.3 and 5.4 GNU/Linux dependencies)
│ │ ├── v22 (5.4 GNU/Linux dependencies)
│ │ │ │
│ │ │ ├── aarch64 (dependencies targeting GNU/Linux AArch64 architecture)
│ │ │ │ │
@@ -157,25 +157,23 @@
│ │ │
│ │ └── release
│ │
│ └── win64
│ └── windows
│ │
│ ├── msvc142 (Microsoft Visual Studio 2019 dependencies)
│ ├── v143 (Microsoft Visual Studio 2022 dependencies)
│ │ │
│ │ ── debug
│ │ │
│ │ └── release
│ │
├── msvc143 (Microsoft Visual Studio 2022 dependencies)
│ │ │
│ │ ├── debug
│ │ │
│ │ └── release
│ │ ── x86-64 (dependencies targeting Microsoft Windows x86-64 architecture)
│ │
│ │ ├── debug
│ │
│ └── release
│ │
│ └── rustc (Microsoft Windows binary dependencies built with Rust)
│ │
── debug
│ │
└── release
── x86-64 (dependencies targeting Microsoft Windows x86-64 architecture)
├── debug
│ │
│ └── release
├── SGBleThirdPartyLibs (Third-party module providing SGBLE headers and libraries)
+6 -1
View File
@@ -9,9 +9,10 @@ There are various resources available for older versions of the SenseGlove Unrea
- [Example C++ API Project (only compatible with early v1.x.x releases)](https://dev.azure.com/SenseGlove/_git/SenseGlove-Unreal-SGPlaygroundCpp)
- [Example Blueprint API Project (only compatible with early v1.x.x releases)](https://dev.azure.com/SenseGlove/_git/SenseGlove-Unreal-SGPlaygroundBP)
### OpenXR Integration Demos
### Third-Party OpenXR Integration Demos
- [A VRExpansionPlugin Integration Demo for UE `5.4`](https://dev.azure.com/SenseGlove/_git/SGVRETemplate)
- [Documentation](../advanced-topics/openxr/third-party-integrations/)
## Tutorials
@@ -43,3 +44,7 @@ There are various resources available for older versions of the SenseGlove Unrea
- [Build & Deploy Unreal Engine 5.5 Projects APK to Android & Meta Quest 3S/3/Pro/2 in Standalone Mode](https://youtu.be/EClbEbNcl4k)
- [Unreal Engine OpenXR Hand-Tracking on Android with Meta XR (Quest 3S/3/Pro/2) and HTC VIVE OpenXR (Focus Vision/XR Elite/Focus 3) Plugins](https://youtu.be/BWd3MwtfTJE)
### VR Optimization
- [Optimizing Unreal Engine VR Projects for Higher Framerates (Meta Quest, HTC VIVE, FFR, ETFR, NVIDIA DLSS, AMD FSR, and Intel XeSS Tips Included!)](https://youtu.be/67CZqMrAOns)
@@ -1,6 +1,6 @@
## Planned Features Completion Status
### Implemented as of v2.6.x
### Implemented as of v2.7.x
- [X] Full SenseGlove low-level core API access through Unreal C++.
- [X] Full SenseGlove low-level core API access through Blueprint.
@@ -42,7 +42,7 @@
- [X] Ability to automatically ask for the required permissions on Android when the plugin is enabled in any UE project.
- [X] `ViveOpenXR` plugin compatibility.
### Upcoming features planned for the v2.6.x release
### Upcoming features planned for the v2.8.x release
### Planned features long-term
@@ -2,10 +2,11 @@
| | **Windows (MSVC 2017)** | **Windows (MSVC 2019)** | **Windows (MSVC 2022)** | **Linux x86-64 (Native Toolchain)** | **Linux AArch64 (Native Toolchain)** | **Meta Quest Standalone (Android NDK)** | **HTC VIVE Standalone (Android NDK)** | **Fab** | **Azure DevOps Version** |
|:--------:|-------------------------|-------------------------|-------------------------|:-----------------------------------:|:------------------------------------:|:---------------------------------------:|:-------------------------------------:|:--------:|:------------------------:|
| **5.6** | ❌ | ❌ | ✅ v2.6.x | ✅ v2.6.x | ✅ v2.6.x | ✅ v2.6.x (r25b) | ❓ | ✅ v2.6.0 | ✅ v2.6.0 |
| **5.5** | ❌ | ❌ | ✅ v2.6.x | ✅ v2.6.x | ✅ v2.6.x | ✅ v2.6.x (r25b) | ❓ | ✅ v2.6.0 | ✅ v2.6.0 |
| **5.4** | ❌ | ❌ | ✅ v2.6.x | ✅ v2.6.x | ✅ v2.6.x | ✅ v2.6.x (r25b) | ✅ v2.6.x (r25b) | ✅ v2.6.0 | ✅ v2.6.0 |
| **5.3** | ❌ | ✅ v2.6.x | v2.6.x | v2.6.x | v2.6.x | v2.6.x (r25b) | v2.6.x (r25b) | v2.6.0 | v2.6.0 |
| **5.7** | ❌ | ❌ | ✅ v2.7.x | ✅ v2.7.x | ✅ v2.7.x | ✅ v2.7.x (r25b) | ❓ | ✅ v2.7.3 | ✅ v2.7.3 |
| **5.6** | ❌ | ❌ | ✅ v2.7.x | ✅ v2.7.x | ✅ v2.7.x | ✅ v2.7.x (r25b) | ❓ | ✅ v2.7.3 | ✅ v2.7.3 |
| **5.5** | ❌ | ❌ | ✅ v2.7.x | ✅ v2.7.x | ✅ v2.7.x | ✅ v2.7.x (r25b) | | ✅ v2.7.3 | ✅ v2.7.3 |
| **5.4** | ❌ | | ⚠️ v2.7.x | ⚠️ v2.7.x | ⚠️ v2.7.x | ⚠️ v2.7.x (r25b) | ⚠️ v2.7.x (r25b) | ⚠️ v2.7.3 | ⚠️ v2.7.3 |
| **5.3** | ❌ | ⚠️ v2.6.x | ⚠️ v2.6.x | ⚠️ v2.6.x | ⚠️ v2.6.x | ⚠️ v2.6.x (r25b) | ⚠️ v2.6.x (r25b) | ⚠️ v2.6.3 | ⚠️ v2.6.3 |
| **5.2** | ❌ | ⚠️ v2.4.x | ⚠️ v2.4.x | ⚠️ v2.4.x | ⚠️ v2.4.x | ⚠️ v2.4.x (r25b) | ❓ | ⚠️ v2.4.2 | ⚠️ v2.4.2 |
| **5.1** | ❌ | ⚠️ v2.0.x | ⚠️ v2.0.x | ⚠️ v2.0.x | ⚠️ v2.0.x | ⚠️ v2.0.x (r25b) | ❓ | ⚠️ v2.0.0 | ⚠️ v2.0.2 |
| **5.0** | ❌ | ⚠️ v1.6.x | ⚠️ v1.6.x | ⚠️ v1.6.x | ⚠️ v1.6.x | ⚠️ v1.6.x (r21e) | ❓ | ⚠️ v1.6.1 | ⚠️ v1.6.1 |
@@ -17,7 +18,7 @@
| **4.22** | ⚠️ v1.0.x | ⚠️ v1.0.x | ❌ | ⚠️ v1.0.x | ❌ | ❌ | ❌ | ❌ | ⚠️ v1.0.4 |
* <code>✅</code> Supported
* <code>⚠️</code> Not supported by the latest release and might be lacking features
* <code>⚠️</code> End-of-life (EOL) release that is not supported anymore and might be lacking features
* <code>❌</code> Not supported at all
* <code>❓</code> Unknown or untested
@@ -34,6 +34,32 @@ To set up `XR_EXT_hand_tracking` support on Meta Quest HMDs in Standalone mode,
To set up `XR_EXT_hand_tracking` support on HTC VIVE HMDs in Standalone mode, additional plugins or configuration steps are required.
> [!CAUTION]
> The SenseGlove Unreal Engine Plugin `v2.7.x` is the last release series to
> support Unreal Engine `5.4`, and its support will be removed in future minor
> or major releases. This is important to keep in mind if your target
> development and deployment platform is HTC VIVE in Standalone Mode.
> Unfortunately, HTC has not released any updates to their HTC ViveOpenXR
> plugin since December 6, 2024. Their
> [latest release](https://developer.vive.com/resources/openxr/unreal/unreal-download/latest/)
> [[1]](https://web.archive.org/web/20251113165658/https://developer.vive.com/resources/openxr/unreal/unreal-download/latest/)
> [[2]](https://archive.ph/DlrLr), ViveOpenXR Plugin `v2.5.0`, supports only
> Unreal Engine `5.3` and `5.4`.
> [HTC VIVE PCVR Mode](../pcvr-mode/index.html#htc-vive) is unaffected and will
> remain fully functional because, on Microsoft Windows, it is supported via the
> [OpenXRViveTracker Plugin](../pcvr-mode/index.html#openxrvivetracker-plugin),
> which is bundled with Unreal Engine and officially maintained by Epic Games.
> If you still intend to target HTC in Standalone Mode, you are welcome to
> continue using the latest SenseGlove Unreal Engine Plugin `v2.7.x`, which will
> retain HTC Standalone Mode support. However, please keep in mind that once
> newer versions of the SenseGlove Unreal Engine Plugin are released and UE
> `5.4` is no longer supported, the latest release of the plugin supporting UE
> `5.4` will not receive new features, hardware support, or bug fixes. If at any
> point in the future HTC releases a new version of their ViveOpenXR plugin that
> supports any Unreal Engine version we actively support,+
> [in accordance with our support policy and Platform Support Matrix](../../../appendix/platform-support-matrix.html),
> we will make every reasonable effort to reintroduce HTC Standalone Mode support.
### OpenXRViveTracker Plugin
Unlike the [PCVR-mode on Windows](../pcvr-mode/), the `OpenXRViveTracker` plugin is not required on Android since it only provides an implementation of the `XR_HTCX_vive_tracker_interaction` OpenXR extension which is necessary when we use VIVE Trackers on Windows or we [emulate the VIVE Wrist Trackers as VIVE Trackers on Windows](../pcvr-mode/#vive-business-streaming-app). Instead, we require the `XR_HTCX_vive_wrist_tracker_interaction` OpenXR extension to be able to use VIVE Wrist Trackers on Android, which is provided by the [`ViveOpenXR` plugin](#viveopenxr-plugin). So, you can safely ignore enabling this plugin for Android standalone deployments.
@@ -44,6 +44,33 @@ When running in PCVR mode, the functional wrist-tracking settings looks somethin
### Standalone Mode
> [!CAUTION]
> The SenseGlove Unreal Engine Plugin `v2.7.x` is the last release series to
> support Unreal Engine `5.4`, and its support will be removed in future minor
> or major releases. This is important to keep in mind if your target
> development and deployment platform is
> [HTC VIVE in Standalone Mode](../enabling-xr-ext-hand-tracking-vr-headsets/standalone-mode/index.html#htc-vive).
> Unfortunately, HTC has not released any updates to their HTC ViveOpenXR
> plugin since December 6, 2024. Their
> [latest release](https://developer.vive.com/resources/openxr/unreal/unreal-download/latest/)
> [[1]](https://web.archive.org/web/20251113165658/https://developer.vive.com/resources/openxr/unreal/unreal-download/latest/)
> [[2]](https://archive.ph/DlrLr), ViveOpenXR Plugin `v2.5.0`, supports only
> Unreal Engine `5.3` and `5.4`.
> [HTC VIVE PCVR Mode](../enabling-xr-ext-hand-tracking-vr-headsets/pcvr-mode/index.html#htc-vive) is unaffected and will
> remain fully functional because, on Microsoft Windows, it is supported via the
> [OpenXRViveTracker Plugin](../pcvr-mode/index.html#openxrvivetracker-plugin),
> which is bundled with Unreal Engine and officially maintained by Epic Games.
> If you still intend to target HTC in Standalone Mode, you are welcome to
> continue using the latest SenseGlove Unreal Engine Plugin `v2.7.x`, which will
> retain HTC Standalone Mode support. However, please keep in mind that once
> newer versions of the SenseGlove Unreal Engine Plugin are released and UE
> `5.4` is no longer supported, the latest release of the plugin supporting UE
> `5.4` will not receive new features, hardware support, or bug fixes. If at any
> point in the future HTC releases a new version of their ViveOpenXR plugin that
> supports any Unreal Engine version we actively support,+
> [in accordance with our support policy and Platform Support Matrix](../../appendix/platform-support-matrix.html),
> we will make every reasonable effort to reintroduce HTC Standalone Mode support.
When running in Standalone mode, the functional wrist-tracking settings looks something like this:
![Setting Up the Wrist Tracking Hardware - HTC VIVE Focus 3 Wrist Tracker (Standalone Mode)](senseglove-wrist-tracking-settings-htc-vive-focus-3-wrist-tracker-openxrvivewristtracker.png "Setting Up the Wrist Tracking Hardware - HTC VIVE Focus 3 Wrist Tracker (Standalone Mode)")
![Setting Up the Wrist Tracking Hardware - HTC VIVE Focus 3 Wrist Tracker (Standalone Mode)](senseglove-wrist-tracking-settings-htc-vive-focus-3-wrist-tracker-openxrvivewristtracker.png "Setting Up the Wrist Tracking Hardware - HTC VIVE Focus 3 Wrist Tracker (Standalone Mode)")
@@ -0,0 +1,31 @@
# {fmt} Formatting Library License
```
Copyright (c) 2012 - present, Victor Zverovich and {fmt} 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.
--- 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.
```
@@ -0,0 +1,28 @@
# Loguru Logging Library License
```
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
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 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.
For more information, please refer to <https://unlicense.org>
```
+2
View File
@@ -7,6 +7,8 @@ The following third-party software are used and shipped with the SenseGlove Unre
- [The SenseGlove SDK (a.k.a. SenseGlove Backend Libraries, or SenseGlove Core Libraries)](senseglove-sdk.md)
- [SGBLE and SGBLExx Rust Dependencies](sgble-sgblexx-rust-dependencies.md)
- [The Boost C++ Libraries](boost-cpp-libraries.md)
- [The {fmt} Formatting Library](fmt-formatting-library.md)
- [The Loguru Logging Library License](loguru-loggin-library.md)
- [The Serial Communication Library](serial-communication-library.md)
For more information consult their own respective open-source licenses, please.
@@ -1,5 +1,17 @@
# Third-Party Tutorials: Android Standalone Mode Deployment
## On-Click Unreal Engine 5.7 Android Packaging & APK Build Tutorial | Meta Quest & HTC VIVE Standalone
This tutorial provides a complete, streamlined guide to packaging and deploying Unreal Engine 5.7 projects to Android devices in standalone mode, with full support for Meta Quest and HTC VIVE headsets. Viewers learn how to correctly install and configure every required component, including Android Studio, SDK, NDK, JDK, and Visual Studio, using either a manual setup, or an open-source one-click PowerShell installer featured in the video.
The tutorial walks through creating a fresh Unreal Engine VR Template project, configuring Android project settings, enabling ADB device debugging, and generating a working APK using the updated Project Launcher workflow in UE 5.7. It also covers how to integrate the Meta XR and HTC VIVE OpenXR plugins to ensure proper VR recognition and hand-tracking functionality on each platform.
By the end, developers understand how to go from a blank project to a fully packaged and deployable Android APK, with functioning VR, correct device targeting, and reliable deployment pipelines on both Meta Quest and HTC VIVE standalone headsets.
<div style="margin: 0 auto; width: 560px;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/SCtAfDeWXBM" frameborder="0" allowfullscreen></iframe>
</div>
## Build & Deploy Unreal Engine 5.5 Projects APK to Android & Meta Quest 3S/3/Pro/2 in Standalone Mode
This video will guide you through the process of building and deploying an Unreal Engine 5.5 project (or any version newer than `4.24`) to Android Standalone Mode for Meta Quest 2 and Quest 3 devices. The steps outlined here should also apply to other Android-based VR headsets.
@@ -0,0 +1,20 @@
# Third-Party Tutorials: Optimizing Your Project for Higher FPS
## Optimizing Unreal Engine VR Projects for Higher Framerates (Meta Quest, HTC VIVE, FFR, ETFR, NVIDIA DLSS, AMD FSR, and Intel XeSS Tips Included!)
This beginner-friendly tutorial, covers how to significantly boost the performance of your Unreal Engine VR projects, whether you're building for standalone (mobile) or PCVR (desktop) on devices such as Meta Quest, HTC VIVE, Varjo, or Valve Index.
It covers step-by-step how to:
- Convert a regular project into a VR-ready experience.
- Optimize for both standalone (Android) and PCVR (Windows) platforms.
- Tweak key rendering, lighting, and texture settings for smoother gameplay.
- Configure Meta XR and HTC VIVE OpenXR plugins to fine-tune settings for the best performance possible.
- Utilize and fine-tune engine scalability settings.
- Explore powerful optimization features like DLSS, FSR, XeSS, and Foveated Rendering
Even if youre new to VR development, this guide breaks it down with visuals, clear examples, and actionable tips to take your framerate from sluggish to silky smooth.
<div style="margin: 0 auto; width: 560px;">
<iframe width="560" height="315" src="https://www.youtube.com/embed/67CZqMrAOns" frameborder="0" allowfullscreen></iframe>
</div>
+4
View File
@@ -68,6 +68,7 @@ Toipcs that do not fall under any specific category:
- [Third-Party Tutorials](../misc/android-standalone-deployment/third-party-tutorials/)
- [Upgrade Guide](../misc/upgrade-guide/)
- [Optimizing for Higher FPS](../misc/optimize-higher-fps/)
- [Third-Party Tutorials](../misc/optimize-higher-fps/third-party-tutorials/)
## 🛠️ Advanced Topics
@@ -81,6 +82,7 @@ For users familiar with the basics, this section explores advanced features of t
- [Consuming FXRMotionControllerData](../advanced-topics/openxr/consuming-fxrmotioncontrollerdata/)
- [Blueprint](../advanced-topics/openxr/consuming-fxrmotioncontrollerdata/blueprint.md)
- [C++](../advanced-topics/openxr/consuming-fxrmotioncontrollerdata/cpp.md)
- [Third-Party Integrations](../advanced-topics/openxr/third-party-integrations/)
- [Third-Party Tutorials](../advanced-topics/openxr/third-party-tutorials/)
## 🔌 Low-Level API
@@ -108,4 +110,6 @@ The appendix contains various extra useful information:
- [SenseGlove SDK License](../license/senseglove-sdk.md)
- [SGBLE and SGBLExx Rust Dependencies Licenses](../license/sgble-sgblexx-rust-dependencies.md)
- [Boost C++ Libraries License](../license/boost-cpp-libraries.md)
- [{fmt} Formatting Library License](../license/fmt-formatting-library.md)
- [Loguru Logging Library License](../license/loguru-loggin-library.md)
- [Serial Communication Library License](../license/serial-communication-library.md)
@@ -4,8 +4,8 @@ Provides the tracking settings related to SenseGlove devices.
![The Glove-tracking Settings](glove-tracking-settings.png "The Glove-tracking Settings")
## GloveConnectivityCheckInterval
## DataRetrievalRefreshRate
The interval in which the tracking module checks for glove connectivity.
The glove data retrieval refresh rate. This affects the interval in which the tracking module checks for glove connectivity and data retrieval.
The default is `16.666666f` which means `60` times per second.
The default is s `60Hz` (data retrieval operations per second).
+13 -13
View File
@@ -42,10 +42,10 @@ Deploy:
PasswordEnvVar: SGUM_PACKAGER_REPOSITORY_PASSWORD
Branches:
- "5.7"
- "5.6"
- "5.5"
- "5.4"
- "5.3"
Exclusions:
- .git
@@ -185,6 +185,11 @@ Rocket:
EnginePaths:
- Branch: "5.7"
Path:
Linux: "/opt/UE57"
Windows: "C:\\OPT\\UE_5.7"
- Branch: "5.6"
Path:
Linux: "/opt/UE56"
@@ -200,17 +205,17 @@ Rocket:
Linux: "/opt/UE54"
Windows: "C:\\OPT\\UE_5.4"
- Branch: "5.3"
Path:
Linux: "/opt/UE53"
Windows: "C:\\OPT\\UE_5.3"
NDKPaths:
- Branch: "5.7"
Path:
Linux: "/opt/android/sdk/ndk/27.2.12479018"
Windows: "%LOCALAPPDATA%\\Android\\Sdk\\ndk\\27.2.12479018"
- Branch: "5.6"
Path:
Linux: "/opt/android/sdk/ndk/25.1.8937393"
Windows: "%LOCALAPPDATA%\\Android\\Sdk\\ndk\\25.1.8937393"
Linux: "/opt/android/sdk/ndk/27.2.12479018"
Windows: "%LOCALAPPDATA%\\Android\\Sdk\\ndk\\27.2.12479018"
- Branch: "5.5"
Path:
@@ -222,11 +227,6 @@ Rocket:
Linux: "/opt/android/sdk/ndk/25.1.8937393"
Windows: "%LOCALAPPDATA%\\Android\\Sdk\\ndk\\25.1.8937393"
- Branch: "5.3"
Path:
Linux: "/opt/android/sdk/ndk/25.1.8937393"
Windows: "%LOCALAPPDATA%\\Android\\Sdk\\ndk\\25.1.8937393"
Rsync:
+1 -1
View File
@@ -1,7 +1,7 @@
{
"FileVersion": 3,
"Version": 1,
"VersionName": "2.6.0",
"VersionName": "2.7.3",
"FriendlyName": "SenseGlove",
"Description": "Integrating the SenseGlove haptic controller into Unreal Engine",
"Category": "Virtual Reality",
@@ -108,17 +108,16 @@ void FSGVirtualHandAnimInstanceProxy::PreEvaluateAnimation(UAnimInstance* InAnim
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
const bool bGotHandTrackingState = VirtualHand->GetHandTrackingState(
EXRSpaceType::UnrealWorldSpace, HandTrackingState);
if (!bGotHandTrackingState || !HandTrackingState.bValid)
HandTrackingState = VirtualHand->GetHandTrackingState();
if (!HandTrackingState.bValid)
{
return;
}
ensureAlwaysMsgf(HandTrackingState.HandKeyLocations.Num() == HandTrackingState.HandKeyRotations.Num(),
TEXT("Mismatched hand tracking state locations and rotations!"));
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
const bool bGotMotionControllerData = VirtualHand->GetMotionControllerData(MotionControllerData);
if (!bGotMotionControllerData || !MotionControllerData.bValid)
MotionControllerData = VirtualHand->GetMotionControllerData();
if (!MotionControllerData.bValid)
{
return;
}
@@ -103,8 +103,9 @@ USGTouchComponent::USGTouchComponent(const FObjectInitializer& ObjectInitializer
{
ForceFeedbackLevel = 1.0f;
VibrotactileDuration = 0.25f;
VibrotactileLevel = 0.0f;
VibrotactileAmplitude = 1.0f;
VibrotactileDuration = 1.0f;
VibrotactileFrequency= 180.0f;
}
USGTouchComponent::FImpl::FImpl(USGTouchComponent* InOwner)
@@ -42,12 +42,12 @@
#include "Engine/EngineTypes.h"
#include "Engine/SkeletalMesh.h"
#include "InputCoreTypes.h"
#include "IXRTrackingSystem.h"
#include "Templates/UnrealTypeTraits.h"
#include "UObject/ConstructorHelpers.h"
#include "SenseGlove/Animation/SGVirtualHandAnimInstance.h"
#include "SenseGlove/Components/SGWristTrackerComponent.h"
#include "SGBuildHacks/SGPlatform.h"
#include "SGCore/SGHapticGlove.h"
#include "SGDebug/SGDebugVirtualHand.h"
#include "SGLog/SGLog.h"
@@ -100,6 +100,14 @@ struct USGVirtualHandComponent::FImpl
ECollisionEnabled::Type CachedCollisionEnabled;
FCollisionResponseContainer CachedCollisionResponse;
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7
FXRMotionControllerData MotionControllerData;
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7 */
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
FXRHandTrackingState HandTrackingState;
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
/************************
* Owner object
************************/
@@ -142,6 +150,8 @@ struct USGVirtualHandComponent::FImpl
void DisableCollisionResponse();
void RestoreCollisionResponse() const;
void UpdateXRData();
void SetVisibility(const bool bInVisible);
void UpdateVisibility();
@@ -367,7 +377,7 @@ void USGVirtualHandComponent::InitializeComponent()
Pimpl->SetDefaultMesh();
}
Pimpl->UpdateVisibility();
Pimpl->UpdateXRData();
}
void USGVirtualHandComponent::UninitializeComponent()
@@ -387,7 +397,7 @@ void USGVirtualHandComponent::BeginPlay()
{
Super::BeginPlay();
Pimpl->UpdateVisibility();
Pimpl->UpdateXRData();
}
void USGVirtualHandComponent::EndPlay(const EEndPlayReason::Type EndPlayReason)
@@ -416,7 +426,7 @@ void USGVirtualHandComponent::TickComponent(
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
Pimpl->UpdateVisibility();
Pimpl->UpdateXRData();
if (Pimpl->ShouldDrawDebugVirtualHand())
{
@@ -439,7 +449,7 @@ void USGVirtualHandComponent::SetSkeletalMesh(USkeletalMesh* NewMesh, const bool
void USGVirtualHandComponent::EditorTick(
const float DeltaTime, const ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Pimpl->UpdateVisibility();
Pimpl->UpdateXRData();
if (Pimpl->ShouldDrawDebugVirtualHand())
{
@@ -461,61 +471,11 @@ USGHapticGlove* USGVirtualHandComponent::GetConnectedGlove() const
return Glove;
}
bool USGVirtualHandComponent::GetMotionControllerData(FXRMotionControllerData& OutMotionControllerData)
{
OutMotionControllerData.bValid = false;
const EControllerHand Hand = IsRight() ? EControllerHand::Right : EControllerHand::Left;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const bool bGotMotionControllerData =
FSGXRTracker::GetMotionControllerData(this, Hand, OutMotionControllerData);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
if (!bGotMotionControllerData || !OutMotionControllerData.bValid)
{
return false;
}
return OutMotionControllerData.bValid;
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
bool USGVirtualHandComponent::GetMotionControllerState(
const EXRSpaceType XRSpaceType, const EXRControllerPoseType XRControllerPoseType,
FXRMotionControllerState& OutMotionControllerState)
const FXRHandTrackingState& USGVirtualHandComponent::GetHandTrackingState() const
{
OutMotionControllerState.bValid = false;
const EControllerHand Hand = IsRight() ? EControllerHand::Right : EControllerHand::Left;
const bool bGotMotionControllerState =
FSGXRTracker::GetMotionControllerState(
this, XRSpaceType, Hand, XRControllerPoseType, OutMotionControllerState);
if (!bGotMotionControllerState || !OutMotionControllerState.bValid)
{
return false;
}
return OutMotionControllerState.bValid;
return Pimpl->HandTrackingState;
}
bool USGVirtualHandComponent::GetHandTrackingState(
const EXRSpaceType XRSpaceType,
FXRHandTrackingState& OutHandTrackingState)
{
OutHandTrackingState.bValid = false;
const EControllerHand Hand = IsRight() ? EControllerHand::Right : EControllerHand::Left;
const bool bGotHandTrackingState =
FSGXRTracker::GetHandTrackingState(
this, XRSpaceType, Hand, OutHandTrackingState);
if (!bGotHandTrackingState || !OutHandTrackingState.bValid)
{
return false;
}
return OutHandTrackingState.bValid;
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
const TArray<FName>& USGVirtualHandComponent::GetHandBoneNames() const
@@ -785,6 +745,42 @@ void USGVirtualHandComponent::FImpl::RestoreCollisionResponse() const
Owner->SetCollisionResponseToChannels(CachedCollisionResponse);
}
void USGVirtualHandComponent::FImpl::UpdateXRData()
{
const EControllerHand Hand = Owner->IsRight() ? EControllerHand::Right : EControllerHand::Left;
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7
{
FXRMotionControllerData Data;
Data.bValid = false;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const bool bGotMotionControllerData =
FSGXRTracker::GetMotionControllerData(Owner, Hand, Data);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
(void)
bGotMotionControllerData;
MotionControllerData = MoveTemp(Data);
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7 */
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
{
FXRHandTrackingState State;
State.bValid = false;
const bool bGotHandTrackingState =
FSGXRTracker::GetHandTrackingState(
Owner, EXRSpaceType::UnrealWorldSpace, Hand, State);
(void) bGotHandTrackingState;
HandTrackingState = MoveTemp(State);
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
}
void USGVirtualHandComponent::FImpl::SetVisibility(const bool bInVisible)
{
Owner->SetHiddenInGame(!bInVisible, false);
@@ -803,23 +799,12 @@ void USGVirtualHandComponent::FImpl::SetVisibility(const bool bInVisible)
void USGVirtualHandComponent::FImpl::UpdateVisibility()
{
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
FXRHandTrackingState HandTrackingState;
const bool bGotHandTrackingState =
Owner->GetHandTrackingState(EXRSpaceType::UnrealWorldSpace, HandTrackingState);
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
FXRMotionControllerData MotionControllerData;
const bool bGotMotionControllerData = Owner->GetMotionControllerData(MotionControllerData);
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
const bool bHandDataAvailable =
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
bGotHandTrackingState
&& HandTrackingState.bValid
HandTrackingState.bValid
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
bGotMotionControllerData
&& MotionControllerData.bValid
&& MotionControllerData.DeviceVisualType == EXRVisualType::Hand
MotionControllerData.bValid
&& MotionControllerData.DeviceVisualType == EXRVisualType::Hand
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
;
const bool bHandVisible = Owner->IsVisible();
@@ -881,18 +866,16 @@ void USGVirtualHandComponent::FImpl::DrawDebugVirtualHand() const
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
FXRHandTrackingState HandTrackingState;
const bool bGotHandTrackingState = Owner->GetHandTrackingState(EXRSpaceType::UnrealWorldSpace, HandTrackingState);
if (!bGotHandTrackingState || !HandTrackingState.bValid)
if (!HandTrackingState.bValid)
{
return;
}
FSGDebugVirtualHand::Draw(World, HandTrackingState, Owner->GetVirtualHandSettings().DebuggingSettings);
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
FXRMotionControllerData MotionControllerData;
const bool bGotMotionControllerData = Owner->GetMotionControllerData(MotionControllerData);
if (!bGotMotionControllerData || !MotionControllerData.bValid)
if (!MotionControllerData.bValid
|| MotionControllerData.DeviceVisualType == EXRVisualType::Hand)
{
return;
}
@@ -36,9 +36,10 @@
#include "SenseGlove/Components/SGWristTrackerComponent.h"
#include "IXRTrackingSystem.h"
#include "MotionDelayBuffer.h"
#include "SGBuildHacks/SGPlatform.h"
#include "SGDebug/SGDebugGizmo.h"
#include "SGLog/SGLog.h"
#include "SGSettings/SGSettings.h"
#include "SGTracking/SGXRTracker.h"
@@ -56,6 +57,14 @@ struct USGWristTrackerComponent::FImpl
bool bOverridePluginSettingsPropertyAlreadyModified;
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7
FXRMotionControllerData MotionControllerData;
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7 */
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
FXRHandTrackingState HandTrackingState;
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
/************************
* Owner object
************************/
@@ -85,7 +94,9 @@ struct USGWristTrackerComponent::FImpl
void OverridePluginSettingsPropertyChanged();
void UpdateMotionSource() const;
void UpdateXRData();
void UpdateWristTrackingData() const;
void DrawDebugWristTracker() const;
};
@@ -201,18 +212,18 @@ void USGWristTrackerComponent::InitializeComponent()
{
Super::InitializeComponent();
Pimpl->UpdateWristTrackingData();
Pimpl->UpdateMotionSource();
Pimpl->UpdateXRData();
Pimpl->UpdateWristTrackingData();
}
void USGWristTrackerComponent::BeginPlay()
{
Super::BeginPlay();
Pimpl->UpdateWristTrackingData();
Pimpl->UpdateMotionSource();
Pimpl->UpdateXRData();
Pimpl->UpdateWristTrackingData();
}
void USGWristTrackerComponent::TickComponent(
@@ -228,77 +239,34 @@ void USGWristTrackerComponent::TickComponent(
Super::TickComponent(DeltaTime, TickType, ThisTickFunction);
Pimpl->UpdateXRData();
Pimpl->UpdateWristTrackingData();
if (GetWristTrackingSettings().DebuggingSettings.bDrawDebugWristTracker)
{
Pimpl->DrawDebugWristTracker();
}
Pimpl->UpdateWristTrackingData();
}
void USGWristTrackerComponent::EditorTick(
const float DeltaTime, const ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction)
{
Pimpl->UpdateXRData();
Pimpl->UpdateWristTrackingData();
}
bool USGWristTrackerComponent::GetMotionControllerData(FXRMotionControllerData& OutMotionControllerData)
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7
const FXRMotionControllerData& USGWristTrackerComponent::GetMotionControllerData() const
{
OutMotionControllerData.bValid = false;
const EControllerHand Hand = IsRight() ? EControllerHand::Right : EControllerHand::Left;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const bool bGotMotionControllerData =
FSGXRTracker::GetMotionControllerData(this, Hand, OutMotionControllerData);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
if (!bGotMotionControllerData || !OutMotionControllerData.bValid)
{
return false;
}
return OutMotionControllerData.bValid;
return Pimpl->MotionControllerData;
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7 */
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
bool USGWristTrackerComponent::GetMotionControllerState(
const EXRSpaceType XRSpaceType, const EXRControllerPoseType XRControllerPoseType,
FXRMotionControllerState& OutMotionControllerState)
const FXRHandTrackingState& USGWristTrackerComponent::GetHandTrackingState() const
{
OutMotionControllerState.bValid = false;
const EControllerHand Hand = IsRight() ? EControllerHand::Right : EControllerHand::Left;
const bool bGotMotionControllerState =
FSGXRTracker::GetMotionControllerState(
this, XRSpaceType, Hand, XRControllerPoseType, OutMotionControllerState);
if (!bGotMotionControllerState || !OutMotionControllerState.bValid)
{
return false;
}
return OutMotionControllerState.bValid;
return Pimpl->HandTrackingState;
}
bool USGWristTrackerComponent::GetHandTrackingState(
const EXRSpaceType XRSpaceType,
FXRHandTrackingState& OutHandTrackingState)
{
OutHandTrackingState.bValid = false;
const EControllerHand Hand = IsRight() ? EControllerHand::Right : EControllerHand::Left;
const bool bGotHandTrackingState =
FSGXRTracker::GetHandTrackingState(
this, XRSpaceType, Hand, OutHandTrackingState);
if (!bGotHandTrackingState || !OutHandTrackingState.bValid)
{
return false;
}
return OutHandTrackingState.bValid;
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
USGWristTrackerComponent::FImpl::FImpl(USGWristTrackerComponent* InOwner)
@@ -359,6 +327,41 @@ void USGWristTrackerComponent::FImpl::UpdateMotionSource() const
Owner->SetTrackingMotionSource(TrackingMotionSource);
}
void USGWristTrackerComponent::FImpl::UpdateXRData()
{
const EControllerHand Hand = Owner->IsRight() ? EControllerHand::Right : EControllerHand::Left;
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7
{
FXRMotionControllerData Data;
Data.bValid = false;
PRAGMA_DISABLE_DEPRECATION_WARNINGS
const bool bGotMotionControllerData =
FSGXRTracker::GetMotionControllerData(Owner, Hand, Data);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
(void)
bGotMotionControllerData;
MotionControllerData = MoveTemp(Data);
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7 */
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
{
FXRHandTrackingState State;
State.bValid = false;
const bool bGotHandTrackingState =
FSGXRTracker::GetHandTrackingState(
Owner, EXRSpaceType::UnrealWorldSpace, Hand, State);
(void) bGotHandTrackingState;
HandTrackingState = MoveTemp(State);
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
}
void USGWristTrackerComponent::FImpl::UpdateWristTrackingData() const
{
FVector NewWristLocation{Owner->GetComponentLocation()};
@@ -36,8 +36,6 @@
#include "SenseGlove/GameFramework/SGPlayerController.h"
#include "Runtime/Launch/Resources/Version.h"
#include "Engine/TimerHandle.h"
#include "TimerManager.h"
#include "SenseGlove/Components/SGTouchComponent.h"
#include "SenseGlove/Components/SGVirtualHandComponent.h"
@@ -45,6 +43,7 @@
#include "SenseGlove/Haptics/SGGrabState.h"
#include "SenseGlove/Haptics/SGTouchState.h"
#include "SGBuildHacks/SGPlatform.h"
#include "SGCore/SGCustomWaveform.h"
#include "SGCore/SGHapticGlove.h"
struct ASGPlayerController::FImpl
@@ -55,11 +54,6 @@ struct ASGPlayerController::FImpl
static float GetForceFeedbackLevel(const AActor* Actor);
static float GetVibrotactileDuration(const AActor* ActorThumbTouching, const AActor* ActorIndexTouching,
const AActor* ActorMiddleTouching, const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching);
static float GetVibrotactileLevel(const AActor* Actor);
static TArray<float> GetForceFeedbackLevels(
const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
@@ -67,19 +61,10 @@ struct ASGPlayerController::FImpl
const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching);
static TArray<float> GetVibrotactileLevels(
const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
const AActor* ActorMiddleTouching,
const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching);
/************************
* Member variables
************************/
FTimerHandle TouchVibrotactileStopTimer;
/************************
* Owner object
************************/
@@ -104,6 +89,8 @@ struct ASGPlayerController::FImpl
* Methods
************************/
USGCustomWaveform* GetCustomWaveform(const AActor* Actor);
void UpdateHapticsFeedback(const FSGTouchState& TouchState);
};
@@ -121,74 +108,6 @@ float ASGPlayerController::FImpl::GetForceFeedbackLevel(const AActor* Actor)
return 0.0f;
}
float ASGPlayerController::FImpl::GetVibrotactileDuration(const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
const AActor* ActorMiddleTouching,
const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching)
{
if (IsValid(ActorThumbTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorThumbTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
if (IsValid(ActorIndexTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorIndexTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
if (IsValid(ActorMiddleTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorMiddleTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
if (IsValid(ActorRingTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorRingTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
if (IsValid(ActorPinkyTouching))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(ActorPinkyTouching);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileDuration();
}
}
return 0.0f;
}
float ASGPlayerController::FImpl::GetVibrotactileLevel(const AActor* Actor)
{
if (IsValid(Actor))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(Actor);
if (IsValid(TouchComponent))
{
return TouchComponent->GetVibrotactileLevel();
}
}
return 0.0f;
}
TArray<float> ASGPlayerController::FImpl::GetForceFeedbackLevels(
const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
@@ -213,30 +132,6 @@ TArray<float> ASGPlayerController::FImpl::GetForceFeedbackLevels(
return ForceFeedbackLevels;
}
TArray<float> ASGPlayerController::FImpl::GetVibrotactileLevels(
const AActor* ActorThumbTouching,
const AActor* ActorIndexTouching,
const AActor* ActorMiddleTouching,
const AActor* ActorRingTouching,
const AActor* ActorPinkyTouching)
{
const float ThumbVibrotactileLevel = GetVibrotactileLevel(ActorThumbTouching);
const float IndexVibrotactileLevel = GetVibrotactileLevel(ActorIndexTouching);
const float MiddleVibrotactileLevel = GetVibrotactileLevel(ActorMiddleTouching);
const float RingVibrotactileLevel = GetVibrotactileLevel(ActorRingTouching);
const float PinkyVibrotactileLevel = GetVibrotactileLevel(ActorPinkyTouching);
const TArray<float> ForceFeedbackLevels{
ThumbVibrotactileLevel,
IndexVibrotactileLevel,
MiddleVibrotactileLevel,
RingVibrotactileLevel,
PinkyVibrotactileLevel,
};
return ForceFeedbackLevels;
}
ASGPlayerController::ASGPlayerController(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer),
Pimpl(TUniquePtr<FImpl, FImplDeleter>(new FImpl{this}, PimplDeleter))
@@ -330,6 +225,29 @@ ASGPlayerController::FImpl::FImpl(ASGPlayerController* InOwner)
ASGPlayerController::FImpl::~FImpl() = default;
USGCustomWaveform* ASGPlayerController::FImpl::GetCustomWaveform(const AActor* Actor)
{
float Amplitude = 0.0f;
float Duration = 0.0f;
float Frequency = 0.0f;
if (IsValid(Actor))
{
const USGTouchComponent* TouchComponent = USGTouchComponent::GetTouchComponent(Actor);
if (IsValid(TouchComponent))
{
Amplitude = TouchComponent->GetVibrotactileAmplitude();
Duration = TouchComponent->GetVibrotactileDuration();
Frequency = TouchComponent->GetVibrotactileFrequency();
}
}
USGCustomWaveform* CustomWaveform{
USGCustomWaveform::NewCustomWaveform(Owner, Amplitude, Duration, Frequency)
};
return CustomWaveform;
}
void ASGPlayerController::FImpl::UpdateHapticsFeedback(const FSGTouchState& TouchState)
{
static const TArray<float> VibrotactileOffCommand{0.0f, 0.0f, 0.0, 0.0, 0.0f};
@@ -359,44 +277,43 @@ void ASGPlayerController::FImpl::UpdateHapticsFeedback(const FSGTouchState& Touc
};
Glove->QueueForceFeedbackLevels(MoveTemp(ForceFeedbackLevels));
// Queue the Vibrotactile command...
TArray<float> VibrotactileLevels{
GetVibrotactileLevels(
TouchState.ActorThumbTouching, TouchState.ActorIndexTouching, TouchState.ActorMiddleTouching,
TouchState.ActorRingTouching, TouchState.ActorPinkyTouching)
};
Glove->QueueVibroLevels(MoveTemp(VibrotactileLevels));
// Send the haptics commands!
Glove->SendHaptics();
// Stop the Vibrotactile command after the timeout if any haptic feedback is ongoing.
const float VibrotactileDuration = FImpl::GetVibrotactileDuration(
TouchState.ActorThumbTouching, TouchState.ActorIndexTouching, TouchState.ActorMiddleTouching,
TouchState.ActorRingTouching, TouchState.ActorPinkyTouching);
Owner->GetWorldTimerManager().ClearTimer(TouchVibrotactileStopTimer);
FTimerDelegate TouchVibrotactileStopHandler;
TouchVibrotactileStopHandler.BindLambda([= SG_CAPTURE_THIS]()-> void
// Send Vibrotactile to the thumb finger if it's touching an actor...
if (IsValid(TouchState.ActorThumbTouching))
{
if (!IsValid(Glove))
{
return;
}
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorThumbTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::ThumbTip);
}
const bool bGloveConnected = Glove->IsConnected();
if (!bGloveConnected)
{
return;
}
// Send Vibrotactile to the index finger if it's touching an actor...
if (IsValid(TouchState.ActorIndexTouching))
{
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorIndexTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::IndexTip);
}
Glove->QueueVibroLevels(VibrotactileOffCommand);
Glove->SendHaptics();
});
// Send Vibrotactile to the middle finger if it's touching an actor...
if (IsValid(TouchState.ActorMiddleTouching))
{
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorMiddleTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::MiddleTip);
}
Owner->GetWorldTimerManager().SetTimer(
TouchVibrotactileStopTimer, TouchVibrotactileStopHandler, VibrotactileDuration, false, -1.0f);
// Send Vibrotactile to the ring finger if it's touching an actor...
if (IsValid(TouchState.ActorRingTouching))
{
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorRingTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::RingTip);
}
// Send Vibrotactile to the pinky finger if it's touching an actor...
if (IsValid(TouchState.ActorPinkyTouching))
{
USGCustomWaveform* CustomWaveform(GetCustomWaveform(TouchState.ActorPinkyTouching));
Glove->SendCustomWaveform(CustomWaveform, ESGHapticLocation::PinkyTip);
}
}
void ASGPlayerController::FImplDeleter::operator()(const FImpl* P) const
@@ -57,12 +57,17 @@ private:
meta=(AllowPrivateAccess="false", ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0"))
float ForceFeedbackLevel;
UPROPERTY(EditAnywhere, Category="SenseGlove", meta=(AllowPrivateAccess="false", ClampMin = "0.0", UIMin = "0.0"))
UPROPERTY(EditAnywhere, Category="SenseGlove",
meta=(AllowPrivateAccess="false", ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0"))
float VibrotactileAmplitude;
UPROPERTY(EditAnywhere, Category="SenseGlove",
meta=(AllowPrivateAccess="false", ClampMin = "0.0", ClampMax = "1.0", UIMin = "0.0", UIMax = "1.0"))
float VibrotactileDuration;
UPROPERTY(EditAnywhere, Category="SenseGlove",
meta=(AllowPrivateAccess="false", ClampMin = "0.0", ClampMax = "100.0", UIMin = "0.0", UIMax = "100.0"))
float VibrotactileLevel;
meta=(AllowPrivateAccess="false", ClampMin = "10.0", ClampMax = "500.0", UIMin = "10.0", UIMax = "500.0"))
float VibrotactileFrequency;
private:
struct FImpl;
@@ -86,6 +91,16 @@ public:
ForceFeedbackLevel = Level;
}
FORCEINLINE float GetVibrotactileAmplitude() const
{
return VibrotactileAmplitude;
}
FORCEINLINE void SetVibrotactileAmplitude(const float Amplitude)
{
VibrotactileAmplitude = Amplitude;
}
FORCEINLINE float GetVibrotactileDuration() const
{
return VibrotactileDuration;
@@ -95,13 +110,14 @@ public:
{
VibrotactileDuration = Duration;
}
FORCEINLINE float GetVibrotactileLevel() const
FORCEINLINE float GetVibrotactileFrequency() const
{
return VibrotactileLevel;
return VibrotactileFrequency;
}
FORCEINLINE void SetVibrotactileLevel(const float Level)
FORCEINLINE void SetVibrotactileFrequency(const float Frequency)
{
VibrotactileLevel = Level;
VibrotactileFrequency = Frequency;
}
};
@@ -181,16 +181,8 @@ public:
bool IsGloveConnected() const;
USGHapticGlove* GetConnectedGlove() const;
UE_DEPRECATED(5.5, "Deprecated by UE 5.5 in favor of GetMotionControllerState and GetHandTrackingState")
bool GetMotionControllerData(FXRMotionControllerData& OutMotionControllerData);
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
bool GetMotionControllerState(
EXRSpaceType XRSpaceType, EXRControllerPoseType XRControllerPoseType,
FXRMotionControllerState& OutMotionControllerState);
bool GetHandTrackingState(
EXRSpaceType XRSpaceType,
FXRHandTrackingState& OutHandTrackingState);
const FXRHandTrackingState& GetHandTrackingState() const;
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
public:
@@ -165,15 +165,7 @@ protected:
FActorComponentTickFunction* ThisTickFunction);
public:
UE_DEPRECATED(5.5, "Deprecated by UE 5.5 in favor of GetMotionControllerState and GetHandTrackingState")
bool GetMotionControllerData(FXRMotionControllerData& OutMotionControllerData);
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
bool GetMotionControllerState(
EXRSpaceType XRSpaceType, EXRControllerPoseType XRControllerPoseType,
FXRMotionControllerState& OutMotionControllerState);
bool GetHandTrackingState(
EXRSpaceType XRSpaceType,
FXRHandTrackingState& OutHandTrackingState);
const FXRHandTrackingState& GetHandTrackingState() const;
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
};
-5
View File
@@ -54,12 +54,7 @@ public class SenseGlove : ModuleRules
"InputCore",
"InputDevice",
"OpenXRHMD",
// NOTE
// UE 5.3+ provides UXRDeviceVisualizationComponent as part of the XRBase plugin.
// UE 5.2 provides UXRDeviceVisualizationComponent as part of the HeadMountDisplay module.
#if UE_5_3_OR_LATER
"XRBase",
#endif
}
);
@@ -58,6 +58,7 @@ public class SenseGloveBuildHacks : ModuleRules
new string[]
{
"SGConnectThirdPartyHeaders",
"SGCoreThirdPartyHeaders",
}
);
@@ -42,8 +42,8 @@ public class SenseGloveConnectImpl : ModuleRules
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
bEnableExceptions = true;
bUseRTTI = true;
bEnableExceptions = false;
bUseRTTI = false;
PrivateDependencyModuleNames.AddRange(
new string[]
@@ -58,8 +58,13 @@ public class SenseGloveConnectImpl : ModuleRules
new string[]
{
"SGBleThirdPartyLibs",
"SGCommonThirdPartyLibs",
"SGConnectShmThirdPartyLibs",
"SGConnectThirdPartyLibs",
"SGSerialThirdPartyLibs",
"SGFmtThirdPartyLibs",
"SGLoguruThirdPartyLibs",
"SGWjwwoodSerialThirdPartyLibs",
}
);
@@ -51,7 +51,6 @@ public class SenseGloveCore : ModuleRules
}
);
PrivateDependencyModuleNames.AddRange(
new string[]
{
@@ -35,6 +35,8 @@
#include "SGCoreImpl/SGBetaDeviceImpl.h"
#include <memory>
#include "Containers/StringConv.h"
#include "Misc/AssertionMacros.h"
@@ -70,7 +72,7 @@ TSharedRef<FSGBetaDeviceImpl> FSGBetaDeviceImpl::Parse(const FString& String)
FSGDevicePtrType SGDevicePtr{FBetaDeviceType::Parse(TCHAR_TO_UTF8(*String))};
ensureAlwaysMsgf(SGDevicePtr, TEXT("Invalid SGDevice!"));
const TSharedRef<FSGBetaDeviceImpl> BetaDeviceImpl{
MakeShared<FSGBetaDeviceImpl>(std::dynamic_pointer_cast<FBetaDeviceType>(MoveTemp(SGDevicePtr)))
MakeShared<FSGBetaDeviceImpl>(std::static_pointer_cast<FBetaDeviceType>(MoveTemp(SGDevicePtr)))
};
return BetaDeviceImpl;
}
@@ -133,12 +135,12 @@ FSGBetaDeviceImpl::FBetaDeviceType FSGBetaDeviceImpl::ToBetaDevice() const
FSGBetaDeviceImpl::FBetaDevicePtrType FSGBetaDeviceImpl::ToBetaDevicePtr() const
{
return std::dynamic_pointer_cast<FBetaDeviceType>(ToSGDevicePtr());
return std::static_pointer_cast<FBetaDeviceType>(ToSGDevicePtr());
}
FSGBetaDeviceImpl::FBetaDevicePtrType FSGBetaDeviceImpl::ToBetaDevicePtrChecked() const
{
FBetaDevicePtrType BetaDevice = std::dynamic_pointer_cast<FBetaDeviceType>(ToSGDevicePtr());
FBetaDevicePtrType BetaDevice = std::static_pointer_cast<FBetaDeviceType>(ToSGDevicePtr());
ensureAlwaysMsgf(BetaDevice.get(), TEXT("Invalid BetaDevice"));
return BetaDevice;
}
@@ -35,6 +35,7 @@
#include "SGCoreImpl/SGDeviceImpl.h"
#include <memory>
#include <string>
#include "Containers/StringConv.h"
@@ -157,35 +158,35 @@ TSharedRef<FSGDeviceImpl> FSGDeviceImpl::ToSGDeviceImplRef()
TSharedRef<FSGBetaDeviceImpl> FSGDeviceImpl::ToBetaDeviceImplRef()
{
FSGBetaDeviceImpl* BetaDevice{dynamic_cast<FSGBetaDeviceImpl*>(this)};
FSGBetaDeviceImpl* BetaDevice{static_cast<FSGBetaDeviceImpl*>(this)};
ensureAlwaysMsgf(BetaDevice, TEXT("Invalid BetaDevice!"));
return SharedThis(BetaDevice);
}
TSharedRef<FSGHapticGloveImpl> FSGDeviceImpl::ToHapticGloveImplRef()
{
FSGHapticGloveImpl* HapticGlove{dynamic_cast<FSGHapticGloveImpl*>(this)};
FSGHapticGloveImpl* HapticGlove{static_cast<FSGHapticGloveImpl*>(this)};
ensureAlwaysMsgf(HapticGlove, TEXT("Invalid HapticGlove!"));
return SharedThis(HapticGlove);
}
TSharedRef<FSGNova2GloveImpl> FSGDeviceImpl::ToNova2GloveImplRef()
{
FSGNova2GloveImpl* Nova2Glove{dynamic_cast<FSGNova2GloveImpl*>(this)};
FSGNova2GloveImpl* Nova2Glove{static_cast<FSGNova2GloveImpl*>(this)};
ensureAlwaysMsgf(Nova2Glove, TEXT("Invalid Nova2Glove!"));
return SharedThis(Nova2Glove);
}
TSharedRef<FSGNovaGloveImpl> FSGDeviceImpl::ToNovaGloveImplRef()
{
FSGNovaGloveImpl* NovaGlove{dynamic_cast<FSGNovaGloveImpl*>(this)};
FSGNovaGloveImpl* NovaGlove{static_cast<FSGNovaGloveImpl*>(this)};
ensureAlwaysMsgf(NovaGlove, TEXT("Invalid NovaGlove!"));
return SharedThis(NovaGlove);
}
TSharedRef<FSGSenseGloveImpl> FSGDeviceImpl::ToSenseGloveImplRef()
{
FSGSenseGloveImpl* SenseGlove{dynamic_cast<FSGSenseGloveImpl*>(this)};
FSGSenseGloveImpl* SenseGlove{static_cast<FSGSenseGloveImpl*>(this)};
ensureAlwaysMsgf(SenseGlove, TEXT("Invalid SenseGlove!"));
return SharedThis(SenseGlove);
}
@@ -193,7 +194,7 @@ TSharedRef<FSGSenseGloveImpl> FSGDeviceImpl::ToSenseGloveImplRef()
bool FSGDeviceImpl::IsABetaDevice() const
{
const FSGBetaDeviceImpl::FBetaDevicePtrType BetaDevice{
std::dynamic_pointer_cast<FSGBetaDeviceImpl::FBetaDeviceType>(ToSGDevicePtr())
std::static_pointer_cast<FSGBetaDeviceImpl::FBetaDeviceType>(ToSGDevicePtr())
};
return BetaDevice != nullptr;
}
@@ -201,7 +202,7 @@ bool FSGDeviceImpl::IsABetaDevice() const
bool FSGDeviceImpl::IsAHapticGlove() const
{
const FSGHapticGloveImpl::FHapticGlovePtrType HapticGlove{
std::dynamic_pointer_cast<FSGHapticGloveImpl::FHapticGloveType>(ToSGDevicePtr())
std::static_pointer_cast<FSGHapticGloveImpl::FHapticGloveType>(ToSGDevicePtr())
};
return HapticGlove != nullptr;
}
@@ -209,7 +210,7 @@ bool FSGDeviceImpl::IsAHapticGlove() const
bool FSGDeviceImpl::IsANova2Glove() const
{
const FSGNova2GloveImpl::FNova2GlovePtrType Nova2Glove{
std::dynamic_pointer_cast<FSGNova2GloveImpl::FNova2GloveType>(ToSGDevicePtr())
std::static_pointer_cast<FSGNova2GloveImpl::FNova2GloveType>(ToSGDevicePtr())
};
return Nova2Glove != nullptr;
}
@@ -217,7 +218,7 @@ bool FSGDeviceImpl::IsANova2Glove() const
bool FSGDeviceImpl::IsANovaGlove() const
{
const FSGNovaGloveImpl::FNovaGlovePtrType NovaGlove{
std::dynamic_pointer_cast<FSGNovaGloveImpl::FNovaGloveType>(ToSGDevicePtr())
std::static_pointer_cast<FSGNovaGloveImpl::FNovaGloveType>(ToSGDevicePtr())
};
return NovaGlove != nullptr;
}
@@ -225,7 +226,7 @@ bool FSGDeviceImpl::IsANovaGlove() const
bool FSGDeviceImpl::IsASenseGlove() const
{
const FSGSenseGloveImpl::FSenseGlovePtrType SenseGlove{
std::dynamic_pointer_cast<FSGSenseGloveImpl::FSenseGloveType>(ToSGDevicePtr())
std::static_pointer_cast<FSGSenseGloveImpl::FSenseGloveType>(ToSGDevicePtr())
};
return SenseGlove != nullptr;
}
@@ -233,7 +234,7 @@ bool FSGDeviceImpl::IsASenseGlove() const
TSharedPtr<FSGBetaDeviceImpl> FSGDeviceImpl::AsBetaDevice() const
{
const FSGBetaDeviceImpl::FBetaDevicePtrType BetaDevice{
std::dynamic_pointer_cast<FSGBetaDeviceImpl::FBetaDeviceType>(ToSGDevicePtr())
std::static_pointer_cast<FSGBetaDeviceImpl::FBetaDeviceType>(ToSGDevicePtr())
};
ensureAlwaysMsgf(BetaDevice, TEXT("Invalid BetaDevice!"));
return MakeShared<FSGBetaDeviceImpl>(BetaDevice);
@@ -242,7 +243,7 @@ TSharedPtr<FSGBetaDeviceImpl> FSGDeviceImpl::AsBetaDevice() const
TSharedPtr<FSGHapticGloveImpl> FSGDeviceImpl::AsHapticGlove() const
{
const FSGHapticGloveImpl::FHapticGlovePtrType HapticGlove{
std::dynamic_pointer_cast<FSGHapticGloveImpl::FHapticGloveType>(ToSGDevicePtr())
std::static_pointer_cast<FSGHapticGloveImpl::FHapticGloveType>(ToSGDevicePtr())
};
ensureAlwaysMsgf(HapticGlove, TEXT("Invalid HapticGlove!"));
return MakeShared<FSGHapticGloveImpl>(HapticGlove);
@@ -251,7 +252,7 @@ TSharedPtr<FSGHapticGloveImpl> FSGDeviceImpl::AsHapticGlove() const
TSharedPtr<FSGNova2GloveImpl> FSGDeviceImpl::AsNova2Glove() const
{
const FSGNova2GloveImpl::FNova2GlovePtrType Nova2Glove{
std::dynamic_pointer_cast<FSGNova2GloveImpl::FNova2GloveType>(ToSGDevicePtr())
std::static_pointer_cast<FSGNova2GloveImpl::FNova2GloveType>(ToSGDevicePtr())
};
ensureAlwaysMsgf(Nova2Glove, TEXT("Invalid Nova2Glove!"));
return MakeShared<FSGNova2GloveImpl>(Nova2Glove);
@@ -260,7 +261,7 @@ TSharedPtr<FSGNova2GloveImpl> FSGDeviceImpl::AsNova2Glove() const
TSharedPtr<FSGNovaGloveImpl> FSGDeviceImpl::AsNovaGlove() const
{
const FSGNovaGloveImpl::FNovaGlovePtrType NovaGlove{
std::dynamic_pointer_cast<FSGNovaGloveImpl::FNovaGloveType>(ToSGDevicePtr())
std::static_pointer_cast<FSGNovaGloveImpl::FNovaGloveType>(ToSGDevicePtr())
};
ensureAlwaysMsgf(NovaGlove, TEXT("Invalid NovaGlove!"));
return MakeShared<FSGNovaGloveImpl>(NovaGlove);
@@ -269,7 +270,7 @@ TSharedPtr<FSGNovaGloveImpl> FSGDeviceImpl::AsNovaGlove() const
TSharedPtr<FSGSenseGloveImpl> FSGDeviceImpl::AsSenseGlove() const
{
const FSGSenseGloveImpl::FSenseGlovePtrType SenseGlove{
std::dynamic_pointer_cast<FSGSenseGloveImpl::FSenseGloveType>(ToSGDevicePtr())
std::static_pointer_cast<FSGSenseGloveImpl::FSenseGloveType>(ToSGDevicePtr())
};
ensureAlwaysMsgf(SenseGlove, TEXT("Invalid SenseGlove!"));
return MakeShared<FSGSenseGloveImpl>(SenseGlove);
@@ -35,6 +35,7 @@
#include "SGCoreImpl/SGDeviceListImpl.h"
#include <memory>
#include <string>
#include "Containers/StringConv.h"
@@ -83,7 +84,7 @@ TArray<TSharedRef<FSGDeviceImpl>> FSGDeviceListImpl::GetDevices()
case ESGDeviceType::BetaDevice:
{
FSGBetaDeviceImpl::FBetaDevicePtrType BetaDevice =
std::dynamic_pointer_cast<FSGBetaDeviceImpl::FBetaDeviceType>(Device);
std::static_pointer_cast<FSGBetaDeviceImpl::FBetaDeviceType>(Device);
if (ensureAlwaysMsgf(BetaDevice, TEXT("Invalid BetaDevice!")))
{
TSharedRef<FSGBetaDeviceImpl> BetaDeviceImpl{
@@ -97,7 +98,7 @@ TArray<TSharedRef<FSGDeviceImpl>> FSGDeviceListImpl::GetDevices()
case ESGDeviceType::Nova2:
{
FSGNova2GloveImpl::FNova2GlovePtrType Nova2Glove =
std::dynamic_pointer_cast<FSGNova2GloveImpl::FNova2GloveType>(Device);
std::static_pointer_cast<FSGNova2GloveImpl::FNova2GloveType>(Device);
if (ensureAlwaysMsgf(Nova2Glove, TEXT("Invalid Nova2Glove device!")))
{
TSharedRef<FSGNova2GloveImpl> Nova2GloveImpl{MakeShared<FSGNova2GloveImpl>(Nova2Glove)};
@@ -109,7 +110,7 @@ TArray<TSharedRef<FSGDeviceImpl>> FSGDeviceListImpl::GetDevices()
case ESGDeviceType::Nova:
{
FSGNovaGloveImpl::FNovaGlovePtrType NovaGlove =
std::dynamic_pointer_cast<FSGNovaGloveImpl::FNovaGloveType>(Device);
std::static_pointer_cast<FSGNovaGloveImpl::FNovaGloveType>(Device);
if (ensureAlwaysMsgf(NovaGlove, TEXT("Invalid NovaGlove device!")))
{
TSharedRef<FSGNovaGloveImpl> NovaGloveImpl{MakeShared<FSGNovaGloveImpl>(NovaGlove)};
@@ -121,7 +122,7 @@ TArray<TSharedRef<FSGDeviceImpl>> FSGDeviceListImpl::GetDevices()
case ESGDeviceType::SenseGlove:
{
FSGSenseGloveImpl::FSenseGlovePtrType SenseGlove{
std::dynamic_pointer_cast<FSGSenseGloveImpl::FSenseGloveType>(Device)};
std::static_pointer_cast<FSGSenseGloveImpl::FSenseGloveType>(Device)};
if (ensureAlwaysMsgf(SenseGlove, TEXT("Invalid SenseGlove device!")))
{
TSharedRef<FSGSenseGloveImpl> SenseGloveImpl{
@@ -134,7 +135,7 @@ TArray<TSharedRef<FSGDeviceImpl>> FSGDeviceListImpl::GetDevices()
default:
SGLOG_WARNING(
FString::Printf(TEXT("Unknown SenseGlove device '%s'!"), UTF8_TO_TCHAR(typeid(Device).name())),
FString::Printf(TEXT("Unknown SenseGlove device '%s'!"), *UEnum::GetValueAsString(FSGCoreEnumCast::ToESGDeviceType(Device->GetDeviceType()))),
FString::Printf(TEXT("Device ID: '%s'!"), UTF8_TO_TCHAR(Device->GetDeviceId().c_str())),
FString::Printf(TEXT("Hardware Version: '%s'!"), UTF8_TO_TCHAR(Device->GetHardwareVersion().c_str())),
FString::Printf(TEXT("Firmware Version: '%d'!"), Device->GetFirmwareVersion()),
@@ -140,7 +140,7 @@ FSGHapticGloveImpl::FSGHapticGloveImpl()
}
FSGHapticGloveImpl::FSGHapticGloveImpl(const FHapticGlovePtrType HapticGlove)
: FSGDeviceImpl(std::dynamic_pointer_cast<FSGDeviceType>(HapticGlove)),
: FSGDeviceImpl(std::static_pointer_cast<FSGDeviceType>(HapticGlove)),
Pimpl(TUniquePtr<FImpl, FImplDeleter>(new FImpl{this}, PimplDeleter))
{
}
@@ -168,12 +168,12 @@ FSGHapticGloveImpl& FSGHapticGloveImpl::operator=(FSGHapticGloveImpl&& Rhs) SG_N
FSGHapticGloveImpl::FHapticGlovePtrType FSGHapticGloveImpl::ToHapticGlovePtr() const
{
return std::dynamic_pointer_cast<FHapticGloveType>(ToSGDevicePtr());
return std::static_pointer_cast<FHapticGloveType>(ToSGDevicePtr());
}
FSGHapticGloveImpl::FHapticGlovePtrType FSGHapticGloveImpl::ToHapticGlovePtrChecked() const
{
FHapticGlovePtrType HapticGlove = std::dynamic_pointer_cast<FHapticGloveType>(ToSGDevicePtr());
FHapticGlovePtrType HapticGlove = std::static_pointer_cast<FHapticGloveType>(ToSGDevicePtr());
ensureAlwaysMsgf(HapticGlove.get(), TEXT("Invalid HapticGlove"));
return HapticGlove;
}
@@ -93,7 +93,7 @@ TSharedRef<FSGDeviceImpl> FSGNova2GloveImpl::Parse(const FString& ConstantsStrin
FSGDevicePtrType SGDevicePtr{FNova2GloveType::Parse(MoveTemp(ConstantsStdString))};
ensureAlwaysMsgf(SGDevicePtr, TEXT("Invalid SGDevice!"));
const TSharedRef<FSGNova2GloveImpl> Nova2GloveImpl{
MakeShared<FSGNova2GloveImpl>(std::dynamic_pointer_cast<FNova2GloveType>(MoveTemp(SGDevicePtr)))
MakeShared<FSGNova2GloveImpl>(std::static_pointer_cast<FNova2GloveType>(MoveTemp(SGDevicePtr)))
};
return Nova2GloveImpl;
}
@@ -275,12 +275,12 @@ const FSGNova2GloveImpl::FNova2GloveType& FSGNova2GloveImpl::ToNova2Glove() cons
FSGNova2GloveImpl::FNova2GlovePtrType FSGNova2GloveImpl::ToNova2GlovePtr() const
{
return std::dynamic_pointer_cast<FNova2GloveType>(ToSGDevicePtr());
return std::static_pointer_cast<FNova2GloveType>(ToSGDevicePtr());
}
FSGNova2GloveImpl::FNova2GlovePtrType FSGNova2GloveImpl::ToNova2GlovePtrChecked() const
{
FNova2GlovePtrType Nova2Glove = std::dynamic_pointer_cast<FNova2GloveType>(ToSGDevicePtr());
FNova2GlovePtrType Nova2Glove = std::static_pointer_cast<FNova2GloveType>(ToSGDevicePtr());
ensureAlwaysMsgf(Nova2Glove.get(), TEXT("Invalid Nova2Glove"));
return Nova2Glove;
}
@@ -95,7 +95,7 @@ TSharedRef<FSGDeviceImpl> FSGNovaGloveImpl::Parse(const FString& ConstantsString
FSGDevicePtrType SGDevicePtr{FNovaGloveType::Parse(MoveTemp(ConstantsStdString))};
ensureAlwaysMsgf(SGDevicePtr, TEXT("Invalid SGDevice!"));
const TSharedRef<FSGNovaGloveImpl> NovaGloveImpl{MakeShared<FSGNovaGloveImpl>(
std::dynamic_pointer_cast<FNovaGloveType>(MoveTemp(SGDevicePtr)))};
std::static_pointer_cast<FNovaGloveType>(MoveTemp(SGDevicePtr)))};
return NovaGloveImpl;
}
@@ -288,12 +288,12 @@ const FSGNovaGloveImpl::FNovaGloveType& FSGNovaGloveImpl::ToNovaGlove() const
FSGNovaGloveImpl::FNovaGlovePtrType FSGNovaGloveImpl::ToNovaGlovePtr() const
{
return std::dynamic_pointer_cast<FNovaGloveType>(ToSGDevicePtr());
return std::static_pointer_cast<FNovaGloveType>(ToSGDevicePtr());
}
FSGNovaGloveImpl::FNovaGlovePtrType FSGNovaGloveImpl::ToNovaGlovePtrChecked() const
{
FNovaGlovePtrType NovaGlove{std::dynamic_pointer_cast<FNovaGloveType>(ToSGDevicePtr())};
FNovaGlovePtrType NovaGlove{std::static_pointer_cast<FNovaGloveType>(ToSGDevicePtr())};
ensureAlwaysMsgf(NovaGlove.get(), TEXT("Invalid NovaGlove"));
return NovaGlove;
}
@@ -93,7 +93,7 @@ TSharedRef<FSGDeviceImpl> FSGSenseGloveImpl::Parse(const FString& ConstantsStrin
FSGDevicePtrType SGDevicePtr{FSenseGloveType::Parse(MoveTemp(ConstantsStdString))};
ensureAlwaysMsgf(SGDevicePtr, TEXT("Invalid SGDevice!"));
const TSharedRef<FSGSenseGloveImpl> SenseGloveImpl{
MakeShared<FSGSenseGloveImpl>(std::dynamic_pointer_cast<FSenseGloveType>(MoveTemp(SGDevicePtr)))
MakeShared<FSGSenseGloveImpl>(std::static_pointer_cast<FSenseGloveType>(MoveTemp(SGDevicePtr)))
};
return SenseGloveImpl;
}
@@ -277,7 +277,7 @@ FSGSenseGloveImpl::FSGSenseGloveImpl(const FSenseGloveType SenseGlove)
}
FSGSenseGloveImpl::FSGSenseGloveImpl(const FSenseGlovePtrType SenseGlove)
: FSGHapticGloveImpl(std::dynamic_pointer_cast<FHapticGloveType>(SenseGlove)),
: FSGHapticGloveImpl(std::static_pointer_cast<FHapticGloveType>(SenseGlove)),
Pimpl(TUniquePtr<FImpl, FImplDeleter>(new FImpl{this}, PimplDeleter))
{
}
@@ -310,12 +310,12 @@ const FSGSenseGloveImpl::FSenseGloveType& FSGSenseGloveImpl::ToSenseGlove() cons
FSGSenseGloveImpl::FSenseGlovePtrType FSGSenseGloveImpl::ToSenseGlovePtr() const
{
return std::dynamic_pointer_cast<FSenseGloveType>(ToSGDevicePtr());
return std::static_pointer_cast<FSenseGloveType>(ToSGDevicePtr());
}
FSGSenseGloveImpl::FSenseGlovePtrType FSGSenseGloveImpl::ToSenseGlovePtrChecked() const
{
FSenseGlovePtrType SenseGlove = std::dynamic_pointer_cast<FSenseGloveType>(ToSGDevicePtr());
FSenseGlovePtrType SenseGlove = std::static_pointer_cast<FSenseGloveType>(ToSGDevicePtr());
ensureAlwaysMsgf(SenseGlove.get(), TEXT("Invalid SenseGlove"));
return SenseGlove;
}
@@ -64,15 +64,35 @@ public:
template <typename T>
static TArray<TSharedRef<FSGDeviceImpl>> GetDevices()
{
const std::type_info& TType = typeid(T);
ESGDeviceType TargetType = ESGDeviceType::Unknown;
if constexpr (std::is_same_v<T, FSGNova2GloveImpl>)
{
TargetType = ESGDeviceType::Nova2;
}
else if constexpr (std::is_same_v<T, FSGNovaGloveImpl>)
{
TargetType = ESGDeviceType::Nova;
}
else if constexpr (std::is_same_v<T, FSGSenseGloveImpl>)
{
TargetType = ESGDeviceType::SenseGlove;
}
else if constexpr (std::is_same_v<T, FSGBetaDeviceImpl>)
{
TargetType = ESGDeviceType::BetaDevice;
}
else
{
static_assert(!sizeof(T), "Unsupported device type in GetDevices<T>()");
}
const TArray<TSharedRef<FSGDeviceImpl>> CurrentDevices = GetDevices();
TArray<TSharedRef<FSGDeviceImpl>> Devices;
for (TSharedRef<FSGDeviceImpl> Device : CurrentDevices)
{
auto &d = Device.Get();
const std::type_info& DType = typeid(d);
if (DType.hash_code() == TType.hash_code())
if (Device->GetDeviceType() == TargetType)
{
Devices.Push(Device);
}
@@ -42,8 +42,8 @@ public class SenseGloveCoreImpl : ModuleRules
{
PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;
bEnableExceptions = true;
bUseRTTI = true;
bEnableExceptions = false;
bUseRTTI = false;
PrivateDependencyModuleNames.AddRange(
new string[]
@@ -57,7 +57,12 @@ public class SenseGloveCoreImpl : ModuleRules
PrivateDependencyModuleNames.AddRange(
new string[]
{
"SGCommonThirdPartyLibs",
"SGCoreShmThirdPartyLibs",
"SGCoreThirdPartyLibs",
"SGLogThirdPartyLibs",
"SGFmtThirdPartyLibs",
"SGLoguruThirdPartyLibs",
}
);
@@ -44,49 +44,32 @@
#include "SGDebug/SGDebugCube.h"
#include "SGDebug/SGDebugGizmo.h"
void FSGDebugVirtualHand::Draw(const UWorld* World,
const FXRMotionControllerData& MotionControllerData,
const FSGVirtualHandDebuggingSettings& Settings)
{
ensureAlwaysMsgf(Settings.DrawingMode != ESGDebugVirtualHandDrawingMode::None,
TEXT("Invalid virtual hand drawing mode!"));
ensureAlwaysMsgf(MotionControllerData.bValid,
TEXT("Invalid motion controller data!"));
ensureAlwaysMsgf(MotionControllerData.HandKeyPositions.Num() == MotionControllerData.HandKeyRotations.Num(),
TEXT("Mismatched motion controller data positions and rotations!"));
for (TArray<FVector>::SizeType HandKeyIndex = 0;
HandKeyIndex < MotionControllerData.HandKeyPositions.Num(); ++HandKeyIndex)
{
const FVector& HandKeyPosition{MotionControllerData.HandKeyPositions[HandKeyIndex]};
const FQuat& HandKeyRotation{MotionControllerData.HandKeyRotations[HandKeyIndex]};
if (Settings.DrawingMode == ESGDebugVirtualHandDrawingMode::CubicJoints)
{
FSGDebugCube::Draw(World, HandKeyPosition, HandKeyRotation, Settings.DebugCubicHandSettings);
}
else if (Settings.DrawingMode == ESGDebugVirtualHandDrawingMode::GizmoJoints)
{
FSGDebugGizmo::Draw(World, HandKeyPosition, HandKeyRotation, Settings.DebugGizmoHandSettings);
}
}
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
void FSGDebugVirtualHand::Draw(const UWorld* World,
const FXRHandTrackingState& HandTrackingState,
const FSGVirtualHandDebuggingSettings& Settings)
void FSGDebugVirtualHand::Draw(
const UWorld* World,
const FXRHandTrackingState& HandTrackingState,
const FSGVirtualHandDebuggingSettings& Settings)
{
ensureAlwaysMsgf(Settings.DrawingMode != ESGDebugVirtualHandDrawingMode::None,
TEXT("Invalid virtual hand drawing mode!"));
if (!ensureAlwaysMsgf(
Settings.DrawingMode != ESGDebugVirtualHandDrawingMode::None,
TEXT("Invalid virtual hand drawing mode!")))
{
return;
};
ensureAlwaysMsgf(HandTrackingState.bValid,
TEXT("Invalid hand tracking state!"));
if (!ensureAlwaysMsgf(
HandTrackingState.bValid,
TEXT("Invalid hand tracking state!")))
{
return;
};
ensureAlwaysMsgf(HandTrackingState.HandKeyLocations.Num() == HandTrackingState.HandKeyRotations.Num(),
TEXT("Mismatched hand tracking state locations and rotations!"));
if (!ensureAlwaysMsgf(
HandTrackingState.HandKeyLocations.Num() == HandTrackingState.HandKeyRotations.Num(),
TEXT("Mismatched hand tracking state locations and rotations!")))
{
return;
};
for (TArray<FVector>::SizeType HandKeyIndex = 0;
HandKeyIndex < HandTrackingState.HandKeyLocations.Num(); ++HandKeyIndex)
@@ -48,12 +48,6 @@ class UWorld;
class SENSEGLOVEDEBUG_API FSGDebugVirtualHand final
{
public:
UE_DEPRECATED(5.5, "Deprecated in favor of the variant that accepts FXRHandTrackingState")
static void Draw(
const UWorld* World,
const FXRMotionControllerData& MotionControllerData,
const FSGVirtualHandDebuggingSettings& Settings);
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
static void Draw(
const UWorld* World,
@@ -37,18 +37,6 @@
#include "SGDebug/SGDebugVirtualHand.h"
void USGDebugVirtualHandKismetLibrary::Draw_FXRMotionControllerData(
UObject* WorldContextObject,
const FXRMotionControllerData& MotionControllerData,
const FSGVirtualHandDebuggingSettings& Settings)
{
ensureAlwaysMsgf(WorldContextObject, TEXT("Invalid world context object!"));
PRAGMA_DISABLE_DEPRECATION_WARNINGS
FSGDebugVirtualHand::Draw(WorldContextObject->GetWorld(), MotionControllerData, Settings);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
void USGDebugVirtualHandKismetLibrary::Draw_FXRHandTrackingState(
UObject* WorldContextObject,
const FXRHandTrackingState& HandTrackingState,
@@ -50,13 +50,6 @@ class SENSEGLOVEDEBUGKISMET_API USGDebugVirtualHandKismetLibrary final : public
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, DisplayName="Draw", Category="SenseGlove | Debug | Virtual Hand",
meta=(WorldContext="WorldContextObject"))
static void Draw_FXRMotionControllerData(
UObject* WorldContextObject,
const FXRMotionControllerData& MotionControllerData,
const FSGVirtualHandDebuggingSettings& Settings);
UFUNCTION(BlueprintCallable, DisplayName="Draw", Category="SenseGlove | Debug | Virtual Hand",
meta=(WorldContext="WorldContextObject"))
static void Draw_FXRHandTrackingState(
@@ -60,14 +60,14 @@ void UTouchComponentKismetLibrary::SetForceFeedbackLevel(USGTouchComponent* Touc
TouchComponent->SetForceFeedbackLevel(Level);
}
float UTouchComponentKismetLibrary::GetVibrotactileLevel(const USGTouchComponent* TouchComponent)
float UTouchComponentKismetLibrary::GetVibrotactileAmplitude(const USGTouchComponent* TouchComponent)
{
return TouchComponent->GetVibrotactileLevel();
return TouchComponent->GetVibrotactileAmplitude();
}
void UTouchComponentKismetLibrary::SetVibrotactileLevel(USGTouchComponent* TouchComponent, const float Level)
void UTouchComponentKismetLibrary::SetVibrotactileAmplitude(USGTouchComponent* TouchComponent, const float Amplitude)
{
TouchComponent->SetVibrotactileLevel(Level);
TouchComponent->SetVibrotactileAmplitude(Amplitude);
}
float UTouchComponentKismetLibrary::GetVibrotactileDuration(const USGTouchComponent* TouchComponent)
@@ -78,4 +78,15 @@ float UTouchComponentKismetLibrary::GetVibrotactileDuration(const USGTouchCompon
void UTouchComponentKismetLibrary::SetVibrotactileDuration(USGTouchComponent* TouchComponent, const float Duration)
{
TouchComponent->SetVibrotactileDuration(Duration);
}
}
float UTouchComponentKismetLibrary::GetVibrotactileFrequency(const USGTouchComponent* TouchComponent)
{
return TouchComponent->GetVibrotactileFrequency();
}
void UTouchComponentKismetLibrary::SetVibrotactileFrequency(USGTouchComponent* TouchComponent, const float Frequency)
{
TouchComponent->SetVibrotactileFrequency(Frequency);
}
@@ -110,26 +110,10 @@ USGHapticGlove* UVirtualHandComponentKismetLibrary::GetConnectedGlove(
return VirtualHandComponent->GetConnectedGlove();
}
bool UVirtualHandComponentKismetLibrary::GetMotionControllerData(
USGVirtualHandComponent* VirtualHandComponent, FXRMotionControllerData& OutMotionControllerData)
const FXRHandTrackingState& UVirtualHandComponentKismetLibrary::GetHandTrackingState(
USGVirtualHandComponent* VirtualHandComponent)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
return VirtualHandComponent->GetMotionControllerData(OutMotionControllerData);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
bool UVirtualHandComponentKismetLibrary::GetMotionControllerState(USGVirtualHandComponent* VirtualHandComponent,
const EXRSpaceType XRSpaceType, const EXRControllerPoseType XRControllerPoseType,
FXRMotionControllerState& OutMotionControllerState)
{
return VirtualHandComponent->GetMotionControllerState(
XRSpaceType, XRControllerPoseType, OutMotionControllerState);
}
bool UVirtualHandComponentKismetLibrary::GetHandTrackingState(USGVirtualHandComponent* VirtualHandComponent,
const EXRSpaceType XRSpaceType, FXRHandTrackingState& OutHandTrackingState)
{
return VirtualHandComponent->GetHandTrackingState(XRSpaceType, OutHandTrackingState);
return VirtualHandComponent->GetHandTrackingState();
}
const TArray<FName>& UVirtualHandComponentKismetLibrary::GetHandBoneNames(
@@ -90,27 +90,8 @@ const FRotator& UWristTrackerComponentKismetLibrary::GetWristRotation(
return WristTrackerComponent->GetWristRotation();
}
bool UWristTrackerComponentKismetLibrary::GetMotionControllerData(
USGWristTrackerComponent* WristTrackerComponent, FXRMotionControllerData& OutMotionControllerData)
const FXRHandTrackingState& UWristTrackerComponentKismetLibrary::GetHandTrackingState(
USGWristTrackerComponent* WristTrackerComponent)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
return WristTrackerComponent->GetMotionControllerData(OutMotionControllerData);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
bool UWristTrackerComponentKismetLibrary::GetMotionControllerState(
USGWristTrackerComponent* WristTrackerComponent,
const EXRSpaceType XRSpaceType, const EXRControllerPoseType XRControllerPoseType,
FXRMotionControllerState& OutMotionControllerState)
{
return WristTrackerComponent->GetMotionControllerState(
XRSpaceType, XRControllerPoseType, OutMotionControllerState);
}
bool UWristTrackerComponentKismetLibrary::GetHandTrackingState(
USGWristTrackerComponent* WristTrackerComponent,
const EXRSpaceType XRSpaceType, FXRHandTrackingState& OutHandTrackingState)
{
return WristTrackerComponent->GetHandTrackingState(
XRSpaceType, OutHandTrackingState);
return WristTrackerComponent->GetHandTrackingState();
}
@@ -61,14 +61,20 @@ public:
static void SetForceFeedbackLevel(UPARAM(ref) USGTouchComponent* TouchComponent, float Level);
UFUNCTION(BlueprintPure, Category="SenseGlove | Components | Touch Component")
static float GetVibrotactileLevel(const USGTouchComponent* TouchComponent);
static float GetVibrotactileAmplitude(const USGTouchComponent* TouchComponent);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Touch Component")
static void SetVibrotactileLevel(UPARAM(ref) USGTouchComponent* TouchComponent, float Level);
static void SetVibrotactileAmplitude(UPARAM(ref) USGTouchComponent* TouchComponent, float Amplitude);
UFUNCTION(BlueprintPure, Category="SenseGlove | Components | Touch Component")
static float GetVibrotactileDuration(const USGTouchComponent* TouchComponent);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Touch Component")
static void SetVibrotactileDuration(UPARAM(ref) USGTouchComponent* TouchComponent, float Duration);
UFUNCTION(BlueprintPure, Category="SenseGlove | Components | Touch Component")
static float GetVibrotactileFrequency(const USGTouchComponent* TouchComponent);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Touch Component")
static void SetVibrotactileFrequency(UPARAM(ref) USGTouchComponent* TouchComponent, float Frequency);
};
@@ -103,18 +103,8 @@ public:
static USGHapticGlove* GetConnectedGlove(const USGVirtualHandComponent* VirtualHandComponent);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Virtual Hand Component")
static bool GetMotionControllerData(UPARAM(ref) USGVirtualHandComponent* VirtualHandComponent,
FXRMotionControllerData& OutMotionControllerData);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Virtual Hand Component")
static bool GetMotionControllerState(UPARAM(ref) USGVirtualHandComponent* VirtualHandComponent,
EXRSpaceType XRSpaceType, EXRControllerPoseType XRControllerPoseType,
FXRMotionControllerState& OutMotionControllerState);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Virtual Hand Component")
static bool GetHandTrackingState(UPARAM(ref) USGVirtualHandComponent* VirtualHandComponent,
EXRSpaceType XRSpaceType,
FXRHandTrackingState& OutHandTrackingState);
static const FXRHandTrackingState& GetHandTrackingState(
UPARAM(ref) USGVirtualHandComponent* VirtualHandComponent);
UFUNCTION(BlueprintPure, Category="SenseGlove | Components | Virtual Hand Component")
static const TArray<FName>& GetHandBoneNames(const USGVirtualHandComponent* VirtualHandComponent);
@@ -84,16 +84,6 @@ public:
static const FRotator& GetWristRotation(const USGWristTrackerComponent* WristTrackerComponent);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Wrist Tracker Component")
static bool GetMotionControllerData(UPARAM(ref) USGWristTrackerComponent* WristTrackerComponent,
FXRMotionControllerData& OutMotionControllerData);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Wrist Tracker Component")
static bool GetMotionControllerState(UPARAM(ref) USGWristTrackerComponent* WristTrackerComponent,
EXRSpaceType XRSpaceType, EXRControllerPoseType XRControllerPoseType,
FXRMotionControllerState& OutMotionControllerState);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Components | Wrist Tracker Component")
static bool GetHandTrackingState(UPARAM(ref) USGWristTrackerComponent* WristTrackerComponent,
EXRSpaceType XRSpaceType,
FXRHandTrackingState& OutHandTrackingState);
static const FXRHandTrackingState& GetHandTrackingState(
UPARAM(ref) USGWristTrackerComponent* WristTrackerComponent);
};
@@ -49,12 +49,7 @@ public class SenseGloveKismet : ModuleRules
"CoreUObject",
"Engine",
"HeadMountedDisplay",
// NOTE
// UE 5.3+ provides UXRDeviceVisualizationComponent as part of the XRBase plugin.
// UE 5.2 provides UXRDeviceVisualizationComponent as part of the HeadMountDisplay module.
#if UE_5_3_OR_LATER
"XRBase",
#endif
}
);
@@ -37,13 +37,13 @@
FSGGloveTrackingSettings::FSGGloveTrackingSettings()
: FSGGloveTrackingSettings{
1000.0f / 60.0f
60.0f
}
{
}
FSGGloveTrackingSettings::FSGGloveTrackingSettings(
const float InGloveConnectivityCheckInterval)
: GloveConnectivityCheckInterval(InGloveConnectivityCheckInterval)
const float InDataRetrievalRefreshRate)
: DataRetrievalRefreshRate(InDataRetrievalRefreshRate)
{
}
@@ -51,16 +51,17 @@ struct SENSEGLOVESETTINGS_API FSGGloveTrackingSettings
public:
/**
* The interval in which the tracking module checks for glove connectivity (in milliseconds).
* The glove data retrieval refresh rate. This affects the interval in which
* the tracking module checks for glove connectivity and data retrieval.
*
* The default is 16.666666f which means 60 times per second.
* The default is s 60Hz (data retrieval operations per second).
*/
UPROPERTY(Config, EditDefaultsOnly, Category="Glove Tracking")
float GloveConnectivityCheckInterval;
float DataRetrievalRefreshRate;
public:
FSGGloveTrackingSettings();
explicit FSGGloveTrackingSettings(
float InGloveConnectivityCheckInterval);
float InDataRetrievalRefreshRate);
};
@@ -58,7 +58,7 @@ struct USGGloveTracker::FImpl
{
const USGSettings* Settings{USGSettings::GetInstance()};
ensureAlwaysMsgf(Settings, TEXT("The settings subsystem has not been initialized!"));
return Settings->GetTrackingSettings().GloveTrackingSettings.GloveConnectivityCheckInterval * 0.001f;
return 1.0f / Settings->GetTrackingSettings().GloveTrackingSettings.DataRetrievalRefreshRate;
}
/************************
@@ -124,24 +124,24 @@ void USGGloveTracker::Initialize(FSubsystemCollectionBase& Collection)
{
SGLOG("Starting the glove connectivity check timer...");
const float GloveConnectivityCheckInterval = FImpl::GetGloveConnectivityCheckInterval();
const float Interval = FImpl::GetGloveConnectivityCheckInterval();
FTimerDelegate GloveConnectivityCheckHandler;
GloveConnectivityCheckHandler.BindLambda([= SG_CAPTURE_THIS]()-> void
FTimerDelegate Handler;
Handler.BindLambda([= SG_CAPTURE_THIS]()-> void
{
Pimpl->UpdateGloves();
});
FTimerManager& TimerManager = World->GetTimerManager();
TimerManager.SetTimer(
Pimpl->GloveConnectivityCheckTimer, GloveConnectivityCheckHandler, GloveConnectivityCheckInterval,
Pimpl->GloveConnectivityCheckTimer, Handler, Interval,
true, -1.0f);
if (ensureAlwaysMsgf(TimerManager.IsTimerActive(Pimpl->GloveConnectivityCheckTimer),
TEXT("GloveConnectivityCheckTimer is not active")))
{
SGLOG("The glove connectivity check timer has been started successfully!");
SGLOG("The glove connectivity timer interval is: ", GloveConnectivityCheckInterval);
SGLOG("The glove connectivity timer interval is: ", Interval);
}
else
{
@@ -72,12 +72,12 @@ struct FSGHMDTracker::FStaticImpl
void FSGHMDTracker::FStaticImpl::GetHMDMonitorInfo(
IHeadMountedDisplay* Device, IHeadMountedDisplay::MonitorInfo& OutMonitorInfo)
{
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 5
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 4
Device->GetHMDMonitorInfo(OutMonitorInfo);
return;
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 5 */
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 4 */
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 6
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
TPromise<TOptional<IHeadMountedDisplay::MonitorInfo>> Promise;
const TFuture<TOptional<IHeadMountedDisplay::MonitorInfo>> Future{Promise.GetFuture()};
@@ -100,7 +100,7 @@ void FSGHMDTracker::FStaticImpl::GetHMDMonitorInfo(
OutMonitorInfo = Result.GetValue();
}
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 6 */
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
}
FName FSGHMDTracker::GetDeviceName()
@@ -56,9 +56,6 @@
#include "Misc/Timespan.h"
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5 */
#include "OpenXRCore.h"
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 3
#include "OpenXRHMD.h"
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 3 */
#include "SGCore/SGHapticGlove.h"
#include "SGLog/SGLog.h"
@@ -71,20 +68,6 @@
#include "SGUtils/SGEngineUtils.h"
#include "SGUtils/SGPluginUtils.h"
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 3
void EnumerateOpenXRApiLayers(TArray<XrApiLayerProperties>& OutProperties)
{
uint32 Count = 0;
XR_ENSURE(xrEnumerateApiLayerProperties(0, &Count, nullptr));
OutProperties.SetNum(Count);
for (auto& Prop: OutProperties)
{
Prop = XrApiLayerProperties{XR_TYPE_API_LAYER_PROPERTIES};
}
XR_ENSURE(xrEnumerateApiLayerProperties(Count, &Count, OutProperties.GetData()));
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 3 */
struct FSGXRTracker::FImpl
{
/************************
@@ -667,6 +650,10 @@ struct FSGXRTracker::FImpl
void BuildMotionSourceToKeypointMap();
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7
void CreateHandTracker(XrSession InSession, XrHandEXT HandEXT, FSGXRHandState& HandState) const;
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7 */
bool CanOutputTrackingData(EControllerHand Hand) const;
bool UpdateXRHandTrackingData(FSGXRHandState& OutHandState, const XrHandJointsLocateInfoEXT& LocateInfo) const;
@@ -1026,6 +1013,8 @@ FTransform FSGXRTracker::FImpl::GetMeshFingerStartBoneRefTransform(
return Transform;
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7
bool FSGXRTracker::GetMotionControllerData(
UObject* WorldContextObject,
const EControllerHand Hand,
@@ -1251,6 +1240,8 @@ bool FSGXRTracker::GetMotionControllerData(
return OutMotionControllerData.bValid;
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7 */
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
bool FSGXRTracker::GetMotionControllerState(
@@ -1495,6 +1486,7 @@ bool FSGXRTracker::GetHandTrackingState(
OutHandTrackingState.HandKeyRadii,
bTracked);
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7
/// TODO
// Begin backward compatibility with the deprecated function, remove this block along with the deprecated
// GetAllKeypointStates.
@@ -1511,6 +1503,7 @@ bool FSGXRTracker::GetHandTrackingState(
// The inability to distinguish this is the reason for the deprecation.
}
// End backward compability.
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION < 7 */
if (!ensureAlwaysMsgf(
!OutHandTrackingState.bValid
@@ -1606,7 +1599,7 @@ bool FSGXRTracker::GetRequiredExtensions(TArray<const ANSICHAR*>& OutExtensions)
}
}
OutExtensions.Add("XR_EXT_hand_tracking");
OutExtensions.Add(XR_EXT_HAND_TRACKING_EXTENSION_NAME);
return true;
}
@@ -1655,21 +1648,29 @@ const void* FSGXRTracker::OnBeginSession(const XrSession InSession, const void*
// Create a hand tracker for the left hand that tracks default set of hand joints.
FSGXRHandState& LeftHandState{Pimpl->GetLeftHandState()};
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7
Pimpl->CreateHandTracker(InSession, XR_HAND_LEFT_EXT, LeftHandState);
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7 */
{
XrHandTrackerCreateInfoEXT CreateInfo{XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT};
CreateInfo.hand = XR_HAND_LEFT_EXT;
CreateInfo.handJointSet = XR_HAND_JOINT_SET_DEFAULT_EXT;
XR_ENSURE(Pimpl->XRCreateHandTrackerEXT(InSession, &CreateInfo, &LeftHandState.HandTracker));
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7 */
// Create a hand tracker for the right hand that tracks default set of hand joints.
FSGXRHandState& RightHandState{Pimpl->GetRightHandState()};
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7
Pimpl->CreateHandTracker(InSession, XR_HAND_RIGHT_EXT, RightHandState);
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7 */
{
XrHandTrackerCreateInfoEXT CreateInfo{XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT};
CreateInfo.hand = XR_HAND_RIGHT_EXT;
CreateInfo.handJointSet = XR_HAND_JOINT_SET_DEFAULT_EXT;
XR_ENSURE(Pimpl->XRCreateHandTrackerEXT(InSession, &CreateInfo, &RightHandState.HandTracker));
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7 */
}
return InNext;
@@ -1726,15 +1727,9 @@ void FSGXRTracker::UpdateDeviceLocations(
}
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3
bool FSGXRTracker::GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource,
FRotator& OutOrientation, FVector& OutPosition,
const float WorldToMetersScale) const
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3 */
bool FSGXRTracker::GetControllerOrientationAndPosition(const int32 ControllerIndex, const EControllerHand DeviceHand,
FRotator& OutOrientation, FVector& OutPosition,
const float WorldToMetersScale) const
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3 */
{
if (!IsHandTrackingStateValid())
{
@@ -1753,10 +1748,6 @@ bool FSGXRTracker::GetControllerOrientationAndPosition(const int32 ControllerInd
return false;
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 2
const FName& MotionSource{FImpl::GetControllerHandEnumName(DeviceHand)};
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 2 */
FTransform ControllerTransform;
bool bMotionSourceHandTracking;
const bool bGotTransform = Pimpl->GetControllerTransform(MotionSource, WorldToMetersScale,
@@ -1769,22 +1760,13 @@ bool FSGXRTracker::GetControllerOrientationAndPosition(const int32 ControllerInd
return bGotTransform;
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3
ETrackingStatus FSGXRTracker::GetControllerTrackingStatus(const int32 ControllerIndex, const FName MotionSource) const
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3 */
ETrackingStatus FSGXRTracker::GetControllerTrackingStatus(const int32 ControllerIndex,
const EControllerHand DeviceHand) const
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3 */
{
if (!IsHandTrackingStateValid())
{
return ETrackingStatus::NotTracked;
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 2
const FName& MotionSource{FImpl::GetControllerHandEnumName(DeviceHand)};
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION <= 2 */
const FImpl::FSGMotionSourceInfo* KeyPointInfoPtr{Pimpl->MotionSourceToKeypointMap.Find(MotionSource)};
if (!KeyPointInfoPtr)
{
@@ -2066,6 +2048,27 @@ void FSGXRTracker::FImpl::BuildMotionSourceToKeypointMap()
RightHandSGMotionSourceName, FSGMotionSourceInfo(EHandKeypoint::Wrist, false));
}
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7
void FSGXRTracker::FImpl::CreateHandTracker(XrSession InSession, XrHandEXT HandEXT, FSGXRHandState& HandState) const
{
XrHandTrackerCreateInfoEXT CreateInfo{XR_TYPE_HAND_TRACKER_CREATE_INFO_EXT};
CreateInfo.hand = HandEXT;
CreateInfo.handJointSet = XR_HAND_JOINT_SET_DEFAULT_EXT;
IOpenXRHMD* OpenXRHMD{XRTrackingSystem ? XRTrackingSystem->GetIOpenXRHMD() : nullptr};
if (OpenXRHMD)
{
TArray<IOpenXRExtensionPlugin*> ExtensionPlugins{OpenXRHMD->GetExtensionPlugins()};
for (IOpenXRExtensionPlugin* Plugin : ExtensionPlugins)
{
CreateInfo.next = Plugin->OnCreateHandTracker(CreateInfo.next);
}
}
XR_ENSURE(XRCreateHandTrackerEXT(InSession, &CreateInfo, &HandState.HandTracker));
}
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 7 */
bool FSGXRTracker::FImpl::CanOutputTrackingData(const EControllerHand Hand) const
{
const bool bFallbackToHandTrackingIfNoGloveDetected = ShouldFallbackToHandTrackingIfNoGloveDetected();
@@ -55,12 +55,6 @@ class SENSEGLOVETRACKING_API FSGXRTracker final : public IOpenXRExtensionPlugin,
public IHandTracker
{
public:
UE_DEPRECATED(5.5, "Deprecated by UE 5.5 in favor of GetMotionControllerState and GetHandTrackingState")
static bool GetMotionControllerData(
UObject* WorldContextObject,
EControllerHand Hand,
FXRMotionControllerData& OutMotionControllerData);
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 5
static bool GetMotionControllerState(
UObject* WorldContextObject,
@@ -136,19 +130,11 @@ public:
public:
// The IMotionController interface.
#if ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3
virtual bool GetControllerOrientationAndPosition(const int32 ControllerIndex, const FName MotionSource,
FRotator& OutOrientation, FVector& OutPosition,
float WorldToMetersScale) const override;
virtual ETrackingStatus GetControllerTrackingStatus(const int32 ControllerIndex,
const FName MotionSource) const override;
#else /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3 */
virtual bool GetControllerOrientationAndPosition(const int32 ControllerIndex, const EControllerHand DeviceHand,
FRotator& OutOrientation, FVector& OutPosition,
float WorldToMetersScale) const override;
virtual ETrackingStatus GetControllerTrackingStatus(const int32 ControllerIndex,
const EControllerHand DeviceHand) const override;
#endif /* ENGINE_MAJOR_VERSION >= 5 && ENGINE_MINOR_VERSION >= 3 */
virtual FName GetMotionControllerDeviceTypeName() const override;
virtual void EnumerateSources(TArray<FMotionControllerSource>& SourcesOut) const override;
@@ -55,15 +55,9 @@ public class SenseGloveTracking : ModuleRules
"InputDevice",
"OpenXRHMD",
"OpenXRInput",
// NOTE
// Only UE 5.3+ provides the XRBase plugin.
#if UE_5_3_OR_LATER
"XRBase",
#else
"OpenXR",
#endif
"Slate",
"SlateCore",
"XRBase",
}
);
@@ -39,14 +39,6 @@
#include "SGTracking/SGXRTracker.h"
bool USGXRTrackerKismetLibrary::GetMotionControllerData(
UObject* WorldContextObject, const EControllerHand Hand, FXRMotionControllerData& OutMotionControllerData)
{
PRAGMA_DISABLE_DEPRECATION_WARNINGS
return FSGXRTracker::GetMotionControllerData(WorldContextObject, Hand, OutMotionControllerData);
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}
bool USGXRTrackerKismetLibrary::GetMotionControllerState(
UObject* WorldContextObject,
const EXRSpaceType XRSpaceType, const EControllerHand Hand, const EXRControllerPoseType XRControllerPoseType,
@@ -51,13 +51,6 @@ class SENSEGLOVETRACKINGKISMET_API USGXRTrackerKismetLibrary final : public USGB
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category="SenseGlove | Tracking | XR Tracker",
meta=(WorldContext="WorldContextObject"))
static bool GetMotionControllerData(
UObject* WorldContextObject,
EControllerHand Hand,
FXRMotionControllerData& OutMotionControllerData);
UFUNCTION(BlueprintCallable, Category="SenseGlove | Tracking | XR Tracker",
meta=(WorldContext="WorldContextObject"))
static bool GetMotionControllerState(
Binary file not shown.
@@ -0,0 +1,177 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2025 SenseGlove
*
* 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.
*
* @section DESCRIPTION
*
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnrealBuildTool;
public class SGCommonThirdPartyLibs : ModuleRules
{
public SGCommonThirdPartyLibs(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
string ThirdPartyDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, ".."));
string LibraryPath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "lib"));
string LibraryPathAnroidAArch64 = "";
string LibraryPathAnroidX64 = "";
string LibraryName = "sgcommon";
bool bIsAndroid = Target.IsInPlatformGroup(UnrealPlatformGroup.Android);
bool bIsLinux = Target.Platform == UnrealTargetPlatform.Linux;
bool bIsLinuxArm64 = Target.Platform == UnrealTargetPlatform.LinuxArm64;
bool bIsWin64 = Target.IsInPlatformGroup(UnrealPlatformGroup.Windows) &&
Target.WindowsPlatform.Architecture == UnrealArch.X64;
bool bIsDebugBuild = (Target.Configuration == UnrealTargetConfiguration.Debug);
if (bIsAndroid)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "android"));
#if UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r27c"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r25b"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinux)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinuxArm64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsWin64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "windows"));
switch (Target.WindowsPlatform.Compiler)
{
case WindowsCompiler.VisualStudio2022:
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v143"));
break;
default:
Debug.Assert(false, "Unsupported engine version or compiler!");
break;
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("{0}.lib", LibraryName);
}
else
{
Debug.Assert(false, "Unsupported platform!");
}
string IncludePath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "include"));
PrivateIncludePaths.Add(IncludePath);
if (bIsAndroid)
{
if (bIsDebugBuild)
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "debug"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "debug"));
}
else
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "release"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "release"));
}
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, LibraryName));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, LibraryName));
PublicAdditionalLibraries.Add(LibraryPathAnroidAArch64);
PublicAdditionalLibraries.Add(LibraryPathAnroidX64);
}
else
{
if (bIsDebugBuild)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "debug"));
}
else
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "release"));
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, LibraryName));
PublicAdditionalLibraries.Add(LibraryPath);
}
}
}
@@ -0,0 +1,177 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2025 SenseGlove
*
* 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.
*
* @section DESCRIPTION
*
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnrealBuildTool;
public class SGConnectShmThirdPartyLibs : ModuleRules
{
public SGConnectShmThirdPartyLibs(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
string ThirdPartyDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, ".."));
string LibraryPath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "lib"));
string LibraryPathAnroidAArch64 = "";
string LibraryPathAnroidX64 = "";
string LibraryName = "sgconnectshm";
bool bIsAndroid = Target.IsInPlatformGroup(UnrealPlatformGroup.Android);
bool bIsLinux = Target.Platform == UnrealTargetPlatform.Linux;
bool bIsLinuxArm64 = Target.Platform == UnrealTargetPlatform.LinuxArm64;
bool bIsWin64 = Target.IsInPlatformGroup(UnrealPlatformGroup.Windows) &&
Target.WindowsPlatform.Architecture == UnrealArch.X64;
bool bIsDebugBuild = (Target.Configuration == UnrealTargetConfiguration.Debug);
if (bIsAndroid)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "android"));
#if UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r27c"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r25b"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinux)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinuxArm64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsWin64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "windows"));
switch (Target.WindowsPlatform.Compiler)
{
case WindowsCompiler.VisualStudio2022:
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v143"));
break;
default:
Debug.Assert(false, "Unsupported engine version or compiler!");
break;
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("{0}.lib", LibraryName);
}
else
{
Debug.Assert(false, "Unsupported platform!");
}
string IncludePath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "include"));
PrivateIncludePaths.Add(IncludePath);
if (bIsAndroid)
{
if (bIsDebugBuild)
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "debug"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "debug"));
}
else
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "release"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "release"));
}
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, LibraryName));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, LibraryName));
PublicAdditionalLibraries.Add(LibraryPathAnroidAArch64);
PublicAdditionalLibraries.Add(LibraryPathAnroidX64);
}
else
{
if (bIsDebugBuild)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "debug"));
}
else
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "release"));
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, LibraryName));
PublicAdditionalLibraries.Add(LibraryPath);
}
}
}
@@ -0,0 +1,177 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2025 SenseGlove
*
* 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.
*
* @section DESCRIPTION
*
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnrealBuildTool;
public class SGCoreShmThirdPartyLibs : ModuleRules
{
public SGCoreShmThirdPartyLibs(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
string ThirdPartyDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, ".."));
string LibraryPath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "lib"));
string LibraryPathAnroidAArch64 = "";
string LibraryPathAnroidX64 = "";
string LibraryName = "sgcoreshm";
bool bIsAndroid = Target.IsInPlatformGroup(UnrealPlatformGroup.Android);
bool bIsLinux = Target.Platform == UnrealTargetPlatform.Linux;
bool bIsLinuxArm64 = Target.Platform == UnrealTargetPlatform.LinuxArm64;
bool bIsWin64 = Target.IsInPlatformGroup(UnrealPlatformGroup.Windows) &&
Target.WindowsPlatform.Architecture == UnrealArch.X64;
bool bIsDebugBuild = (Target.Configuration == UnrealTargetConfiguration.Debug);
if (bIsAndroid)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "android"));
#if UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r27c"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r25b"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinux)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinuxArm64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsWin64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "windows"));
switch (Target.WindowsPlatform.Compiler)
{
case WindowsCompiler.VisualStudio2022:
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v143"));
break;
default:
Debug.Assert(false, "Unsupported engine version or compiler!");
break;
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("{0}.lib", LibraryName);
}
else
{
Debug.Assert(false, "Unsupported platform!");
}
string IncludePath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "include"));
PrivateIncludePaths.Add(IncludePath);
if (bIsAndroid)
{
if (bIsDebugBuild)
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "debug"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "debug"));
}
else
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "release"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "release"));
}
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, LibraryName));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, LibraryName));
PublicAdditionalLibraries.Add(LibraryPathAnroidAArch64);
PublicAdditionalLibraries.Add(LibraryPathAnroidX64);
}
else
{
if (bIsDebugBuild)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "debug"));
}
else
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "release"));
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, LibraryName));
PublicAdditionalLibraries.Add(LibraryPath);
}
}
}
@@ -0,0 +1,53 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2025 SenseGlove
*
* 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 CoreION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @section DESCRIPTION
*
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnrealBuildTool;
public class SGCoreThirdPartyHeaders : ModuleRules
{
public SGCoreThirdPartyHeaders(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
string ThirdPartyDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, ".."));
string IncludePath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "include"));
PublicIncludePaths.Add(IncludePath);
}
}
Binary file not shown.
@@ -0,0 +1,182 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2025 SenseGlove
*
* 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.
*
* @section DESCRIPTION
*
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnrealBuildTool;
public class SGFmtThirdPartyLibs : ModuleRules
{
public SGFmtThirdPartyLibs(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
string ThirdPartyDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, ".."));
string LibraryPath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "lib"));
string LibraryPathAnroidAArch64 = "";
string LibraryPathAnroidX64 = "";
string LibraryName = "fmt";
bool bIsAndroid = Target.IsInPlatformGroup(UnrealPlatformGroup.Android);
bool bIsLinux = Target.Platform == UnrealTargetPlatform.Linux;
bool bIsLinuxArm64 = Target.Platform == UnrealTargetPlatform.LinuxArm64;
bool bIsWin64 = Target.IsInPlatformGroup(UnrealPlatformGroup.Windows) &&
Target.WindowsPlatform.Architecture == UnrealArch.X64;
bool bIsDebugBuild = (Target.Configuration == UnrealTargetConfiguration.Debug);
if (bIsDebugBuild)
{
LibraryName += "d";
}
if (bIsAndroid)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "android"));
#if UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r27c"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r25b"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinux)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinuxArm64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsWin64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "windows"));
switch (Target.WindowsPlatform.Compiler)
{
case WindowsCompiler.VisualStudio2022:
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v143"));
break;
default:
Debug.Assert(false, "Unsupported engine version or compiler!");
break;
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("{0}.lib", LibraryName);
}
else
{
Debug.Assert(false, "Unsupported platform!");
}
string IncludePath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "include"));
PrivateIncludePaths.Add(IncludePath);
if (bIsAndroid)
{
if (bIsDebugBuild)
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "debug"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "debug"));
}
else
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "release"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "release"));
}
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, LibraryName));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, LibraryName));
PublicAdditionalLibraries.Add(LibraryPathAnroidAArch64);
PublicAdditionalLibraries.Add(LibraryPathAnroidX64);
}
else
{
if (bIsDebugBuild)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "debug"));
}
else
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "release"));
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, LibraryName));
PublicAdditionalLibraries.Add(LibraryPath);
}
}
}
@@ -0,0 +1,177 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2025 SenseGlove
*
* 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.
*
* @section DESCRIPTION
*
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnrealBuildTool;
public class SGLogThirdPartyLibs : ModuleRules
{
public SGLogThirdPartyLibs(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
string ThirdPartyDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, ".."));
string LibraryPath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "lib"));
string LibraryPathAnroidAArch64 = "";
string LibraryPathAnroidX64 = "";
string LibraryName = "sglog";
bool bIsAndroid = Target.IsInPlatformGroup(UnrealPlatformGroup.Android);
bool bIsLinux = Target.Platform == UnrealTargetPlatform.Linux;
bool bIsLinuxArm64 = Target.Platform == UnrealTargetPlatform.LinuxArm64;
bool bIsWin64 = Target.IsInPlatformGroup(UnrealPlatformGroup.Windows) &&
Target.WindowsPlatform.Architecture == UnrealArch.X64;
bool bIsDebugBuild = (Target.Configuration == UnrealTargetConfiguration.Debug);
if (bIsAndroid)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "android"));
#if UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r27c"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r25b"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinux)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinuxArm64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsWin64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "windows"));
switch (Target.WindowsPlatform.Compiler)
{
case WindowsCompiler.VisualStudio2022:
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v143"));
break;
default:
Debug.Assert(false, "Unsupported engine version or compiler!");
break;
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("{0}.lib", LibraryName);
}
else
{
Debug.Assert(false, "Unsupported platform!");
}
string IncludePath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "include"));
PrivateIncludePaths.Add(IncludePath);
if (bIsAndroid)
{
if (bIsDebugBuild)
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "debug"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "debug"));
}
else
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "release"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "release"));
}
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, LibraryName));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, LibraryName));
PublicAdditionalLibraries.Add(LibraryPathAnroidAArch64);
PublicAdditionalLibraries.Add(LibraryPathAnroidX64);
}
else
{
if (bIsDebugBuild)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "debug"));
}
else
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "release"));
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, LibraryName));
PublicAdditionalLibraries.Add(LibraryPath);
}
}
}
@@ -0,0 +1,182 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2025 SenseGlove
*
* 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.
*
* @section DESCRIPTION
*
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnrealBuildTool;
public class SGLoguruThirdPartyLibs : ModuleRules
{
public SGLoguruThirdPartyLibs(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
string ThirdPartyDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, ".."));
string LibraryPath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "lib"));
string LibraryPathAnroidAArch64 = "";
string LibraryPathAnroidX64 = "";
string LibraryName = "loguru";
bool bIsAndroid = Target.IsInPlatformGroup(UnrealPlatformGroup.Android);
bool bIsLinux = Target.Platform == UnrealTargetPlatform.Linux;
bool bIsLinuxArm64 = Target.Platform == UnrealTargetPlatform.LinuxArm64;
bool bIsWin64 = Target.IsInPlatformGroup(UnrealPlatformGroup.Windows) &&
Target.WindowsPlatform.Architecture == UnrealArch.X64;
bool bIsDebugBuild = (Target.Configuration == UnrealTargetConfiguration.Debug);
if (bIsDebugBuild)
{
LibraryName += "d";
}
if (bIsAndroid)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "android"));
#if UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r27c"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r25b"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinux)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinuxArm64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsWin64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "windows"));
switch (Target.WindowsPlatform.Compiler)
{
case WindowsCompiler.VisualStudio2022:
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v143"));
break;
default:
Debug.Assert(false, "Unsupported engine version or compiler!");
break;
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("{0}.lib", LibraryName);
}
else
{
Debug.Assert(false, "Unsupported platform!");
}
string IncludePath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "include"));
PrivateIncludePaths.Add(IncludePath);
if (bIsAndroid)
{
if (bIsDebugBuild)
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "debug"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "debug"));
}
else
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "release"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "release"));
}
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, LibraryName));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, LibraryName));
PublicAdditionalLibraries.Add(LibraryPathAnroidAArch64);
PublicAdditionalLibraries.Add(LibraryPathAnroidX64);
}
else
{
if (bIsDebugBuild)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "debug"));
}
else
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "release"));
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, LibraryName));
PublicAdditionalLibraries.Add(LibraryPath);
}
}
}
@@ -0,0 +1,177 @@
/**
* @file
*
* @author Mamadou Babaei <mamadou@senseglove.com>
*
* @section LICENSE
*
* (The MIT License)
*
* Copyright (c) 2020 - 2025 SenseGlove
*
* 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.
*
* @section DESCRIPTION
*
*
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using UnrealBuildTool;
public class SGWjwwoodSerialThirdPartyLibs : ModuleRules
{
public SGWjwwoodSerialThirdPartyLibs(ReadOnlyTargetRules Target) : base(Target)
{
Type = ModuleType.External;
string ThirdPartyDirectory = Path.GetFullPath(Path.Combine(ModuleDirectory, ".."));
string LibraryPath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "lib"));
string LibraryPathAnroidAArch64 = "";
string LibraryPathAnroidX64 = "";
string LibraryName = "serial";
bool bIsAndroid = Target.IsInPlatformGroup(UnrealPlatformGroup.Android);
bool bIsLinux = Target.Platform == UnrealTargetPlatform.Linux;
bool bIsLinuxArm64 = Target.Platform == UnrealTargetPlatform.LinuxArm64;
bool bIsWin64 = Target.IsInPlatformGroup(UnrealPlatformGroup.Windows) &&
Target.WindowsPlatform.Architecture == UnrealArch.X64;
bool bIsDebugBuild = (Target.Configuration == UnrealTargetConfiguration.Debug);
if (bIsAndroid)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "android"));
#if UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r27c"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "r25b"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinux)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsLinuxArm64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "linux"));
#if UE_5_7_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v26"));
#elif UE_5_6_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v25"));
#elif UE_5_5_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v23"));
#elif UE_5_4_OR_LATER
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v22"));
#else
Debug.Assert(false, "Unsupported engine version or compiler!");
#endif
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "aarch64"));
LibraryName = string.Format("lib{0}.a", LibraryName);
}
else if (bIsWin64)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "windows"));
switch (Target.WindowsPlatform.Compiler)
{
case WindowsCompiler.VisualStudio2022:
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "v143"));
break;
default:
Debug.Assert(false, "Unsupported engine version or compiler!");
break;
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "x86-64"));
LibraryName = string.Format("{0}.lib", LibraryName);
}
else
{
Debug.Assert(false, "Unsupported platform!");
}
string IncludePath = Path.GetFullPath(Path.Combine(ThirdPartyDirectory, "include"));
PrivateIncludePaths.Add(IncludePath);
if (bIsAndroid)
{
if (bIsDebugBuild)
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "debug"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "debug"));
}
else
{
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, "release"));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, "release"));
}
LibraryPathAnroidAArch64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidAArch64, LibraryName));
LibraryPathAnroidX64 = Path.GetFullPath(Path.Combine(LibraryPathAnroidX64, LibraryName));
PublicAdditionalLibraries.Add(LibraryPathAnroidAArch64);
PublicAdditionalLibraries.Add(LibraryPathAnroidX64);
}
else
{
if (bIsDebugBuild)
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "debug"));
}
else
{
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, "release"));
}
LibraryPath = Path.GetFullPath(Path.Combine(LibraryPath, LibraryName));
PublicAdditionalLibraries.Add(LibraryPath);
}
}
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More