Skip to content

Commit

Permalink
Adding HTC tracker support
Browse files Browse the repository at this point in the history
  • Loading branch information
BastiaanOlij committed Mar 9, 2022
1 parent bf16b86 commit c1a3608
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 21 deletions.
2 changes: 2 additions & 0 deletions src/ARVRInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "openxr/extensions/xr_fb_foveation_extension_wrapper.h"
#include "openxr/extensions/xr_fb_passthrough_extension_wrapper.h"
#include "openxr/extensions/xr_fb_swapchain_update_state_extension_wrapper.h"
#include "openxr/extensions/xr_htc_vive_tracker_extension_wrapper.h"
#include <ARVRInterface.hpp>
#include <MainLoop.hpp>

Expand Down Expand Up @@ -128,6 +129,7 @@ godot_bool godot_arvr_initialize(void *p_data) {
arvr_data->openxr_api->register_extension_wrapper<XRFbDisplayRefreshRateExtensionWrapper>();
arvr_data->openxr_api->register_extension_wrapper<XRExtHandTrackingExtensionWrapper>();
arvr_data->openxr_api->register_extension_wrapper<XRFbPassthroughExtensionWrapper>();
arvr_data->openxr_api->register_extension_wrapper<XRHTCViveTrackerExtensionWrapper>();

// not initialise
arvr_data->openxr_api->initialize();
Expand Down
119 changes: 109 additions & 10 deletions src/openxr/OpenXRApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,19 @@ const char *OpenXRApi::default_action_sets_json = R"===(
"localised_name": "Grip Pose",
"paths": [
"/user/hand/left",
"/user/hand/right"
"/user/hand/right",
"/user/vive_tracker_htcx/role/left_foot",
"/user/vive_tracker_htcx/role/right_foot",
"/user/vive_tracker_htcx/role/left_shoulder",
"/user/vive_tracker_htcx/role/right_shoulder",
"/user/vive_tracker_htcx/role/left_elbow",
"/user/vive_tracker_htcx/role/right_elbow",
"/user/vive_tracker_htcx/role/left_knee",
"/user/vive_tracker_htcx/role/right_knee",
"/user/vive_tracker_htcx/role/waist",
"/user/vive_tracker_htcx/role/chest",
"/user/vive_tracker_htcx/role/camera",
"/user/vive_tracker_htcx/role/keyboard"
]
},
{
Expand Down Expand Up @@ -214,7 +226,19 @@ const char *OpenXRApi::default_action_sets_json = R"===(
"localised_name": "Controller haptic vibration",
"paths": [
"/user/hand/left",
"/user/hand/right"
"/user/hand/right",
"/user/vive_tracker_htcx/role/left_foot",
"/user/vive_tracker_htcx/role/right_foot",
"/user/vive_tracker_htcx/role/left_shoulder",
"/user/vive_tracker_htcx/role/right_shoulder",
"/user/vive_tracker_htcx/role/left_elbow",
"/user/vive_tracker_htcx/role/right_elbow",
"/user/vive_tracker_htcx/role/left_knee",
"/user/vive_tracker_htcx/role/right_knee",
"/user/vive_tracker_htcx/role/waist",
"/user/vive_tracker_htcx/role/chest",
"/user/vive_tracker_htcx/role/camera",
"/user/vive_tracker_htcx/role/keyboard"
]
}
]
Expand Down Expand Up @@ -1290,6 +1314,47 @@ const char *OpenXRApi::default_interaction_profiles_json = R"===(
]
}
]
},)==="
R"===({
"path": "/interaction_profiles/htc/vive_tracker_htcx",
"bindings": [
{
"set": "godot",
"action": "grip_pose",
"paths": [
"/user/vive_tracker_htcx/role/left_foot/input/grip/pose",
"/user/vive_tracker_htcx/role/right_foot/input/grip/pose",
"/user/vive_tracker_htcx/role/left_shoulder/input/grip/pose",
"/user/vive_tracker_htcx/role/right_shoulder/input/grip/pose",
"/user/vive_tracker_htcx/role/left_elbow/input/grip/pose",
"/user/vive_tracker_htcx/role/right_elbow/input/grip/pose",
"/user/vive_tracker_htcx/role/left_knee/input/grip/pose",
"/user/vive_tracker_htcx/role/right_knee/input/grip/pose",
"/user/vive_tracker_htcx/role/waist/input/grip/pose",
"/user/vive_tracker_htcx/role/chest/input/grip/pose",
"/user/vive_tracker_htcx/role/camera/input/grip/pose",
"/user/vive_tracker_htcx/role/keyboard/input/grip/pose"
]
},
{
"set": "godot",
"action": "haptic",
"paths": [
"/user/vive_tracker_htcx/role/left_foot/output/haptic",
"/user/vive_tracker_htcx/role/right_foot/output/haptic",
"/user/vive_tracker_htcx/role/left_shoulder/output/haptic",
"/user/vive_tracker_htcx/role/right_shoulder/output/haptic",
"/user/vive_tracker_htcx/role/left_elbow/output/haptic",
"/user/vive_tracker_htcx/role/right_elbow/output/haptic",
"/user/vive_tracker_htcx/role/left_knee/output/haptic",
"/user/vive_tracker_htcx/role/right_knee/output/haptic",
"/user/vive_tracker_htcx/role/waist/output/haptic",
"/user/vive_tracker_htcx/role/chest/output/haptic",
"/user/vive_tracker_htcx/role/camera/output/haptic",
"/user/vive_tracker_htcx/role/keyboard/output/haptic"
]
}
]
}
]
)===";
Expand Down Expand Up @@ -2177,6 +2242,38 @@ void OpenXRApi::cleanupSwapChains() {
}
}

void OpenXRApi::add_input_map(const char * p_path) {
InputMap im;

int len = strlen(p_path);
if (len > XR_MAX_PATH_LENGTH - 1) {
len = XR_MAX_PATH_LENGTH - 1;
}
memcpy(im.name, p_path, len);
im.name[len] = '\0';
im.toplevel_path = XR_NULL_PATH;
im.godot_controller = -1;
im.active_profile = XR_NULL_PATH;
im.active_profile_str[0] = '\0';
im.tracking_confidence = TRACKING_CONFIDENCE_NONE;

inputmaps.push_back(im);
}

void OpenXRApi::setup_input_maps() {
add_input_map("/user/hand/left");
add_input_map("/user/hand/right");

for (XRExtensionWrapper *wrapper : registered_extension_wrappers) {
wrapper->add_input_maps();
}
}

void OpenXRApi::cleanup_input_maps() {
// unbindActionSets should already have been called so we can just clear our map
inputmaps.clear();
}

bool OpenXRApi::loadActionSets() {
#ifdef DEBUG
Godot::print("OpenXR loadActionSets");
Expand Down Expand Up @@ -2209,7 +2306,7 @@ bool OpenXRApi::bindActionSets() {
// a developer that is not using the internal actions but defines their own may not care about these missing

// Init our input paths and godot controllers for our mapping to
for (uint64_t i = 0; i < USER_INPUT_MAX; i++) {
for (uint64_t i = 0; i < inputmaps.size(); i++) {
XrResult res = xrStringToPath(instance, inputmaps[i].name, &inputmaps[i].toplevel_path);
xr_result(res, "OpenXR Couldn't obtain path for {0}", inputmaps[i].name);
}
Expand All @@ -2229,7 +2326,7 @@ bool OpenXRApi::bindActionSets() {

void OpenXRApi::unbindActionSets() {
// cleanup our controller mapping
for (uint64_t i = 0; i < USER_INPUT_MAX; i++) {
for (uint64_t i = 0; i < inputmaps.size(); i++) {
inputmaps[i].toplevel_path = XR_NULL_PATH;
inputmaps[i].active_profile = XR_NULL_PATH;
if (inputmaps[i].godot_controller >= 0) {
Expand Down Expand Up @@ -2418,6 +2515,7 @@ bool OpenXRApi::on_state_ready() {
initialiseSpaces();
initialiseSwapChains();

setup_input_maps();
bindActionSets();

running = true;
Expand Down Expand Up @@ -2493,6 +2591,7 @@ bool OpenXRApi::on_state_stopping() {
// need to cleanup various things which would otherwise be re-allocated if we have a state change back to ready
// note that cleaning up our action sets will invalidate many of the OpenXR nodes so we need to improve that as well.
unbindActionSets();
cleanup_input_maps();
cleanupSwapChains();
cleanupSpaces();

Expand Down Expand Up @@ -2578,7 +2677,7 @@ godot::Array OpenXRApi::get_enabled_extensions() const {
}

TrackingConfidence OpenXRApi::get_controller_tracking_confidence(const int p_godot_controller) const {
for (int i = 0; i < USER_INPUT_MAX; i++) {
for (int i = 0; i < inputmaps.size(); i++) {
if (inputmaps[i].godot_controller == p_godot_controller) {
return inputmaps[i].tracking_confidence;
}
Expand Down Expand Up @@ -3163,7 +3262,7 @@ void OpenXRApi::update_actions() {

const float ws = ARVRServer::get_singleton()->get_world_scale();

for (uint64_t i = 0; i < USER_INPUT_MAX; i++) {
for (uint64_t i = 0; i < inputmaps.size(); i++) {
XrPath input_path = inputmaps[i].toplevel_path;
if (input_path == XR_NULL_PATH) {
// no path, skip this
Expand Down Expand Up @@ -3523,7 +3622,7 @@ bool OpenXRApi::poll_events() {
.next = nullptr
};

for (int i = 0; i < USER_INPUT_MAX; i++) {
for (int i = 0; i < inputmaps.size(); i++) {
XrPath input_path = inputmaps[i].toplevel_path;
if (input_path == XR_NULL_PATH) {
// incorrect path
Expand All @@ -3541,18 +3640,18 @@ bool OpenXRApi::poll_events() {
if (inputmaps[i].active_profile != new_profile) {
inputmaps[i].active_profile = new_profile;
if (new_profile == XR_NULL_PATH) {
inputmaps[i].active_profile_str[0]='/0';
Godot::print("OpenXR No interaction profile for {0}", inputmaps[i].name);
continue;
}

uint32_t strl;
char profile_str[XR_MAX_PATH_LENGTH];
res = xrPathToString(instance, new_profile, XR_MAX_PATH_LENGTH, &strl, profile_str);
res = xrPathToString(instance, new_profile, XR_MAX_PATH_LENGTH, &strl, inputmaps[i].active_profile_str);
if (!xr_result(res, "Failed to get interaction profile path str for {0}", inputmaps[i].name)) {
continue;
}

Godot::print("OpenXR Event: Interaction profile changed for {0}: {1}", inputmaps[i].name, profile_str);
Godot::print("OpenXR Event: Interaction profile changed for {0}: {1}", inputmaps[i].name, inputmaps[i].active_profile_str);
}
}

Expand Down
19 changes: 8 additions & 11 deletions src/openxr/OpenXRApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ enum TrackingConfidence {
#include "openxr/actions/action.h"
#include "openxr/actions/actionset.h"

#define USER_INPUT_MAX 2

using namespace godot;

class OpenXRApi {
Expand All @@ -74,21 +72,15 @@ class OpenXRApi {
// If not configured in our action sets they will be defunct

struct InputMap {
const char *name;
char name[XR_MAX_PATH_LENGTH];
XrPath toplevel_path;
godot_int godot_controller;
XrPath active_profile; // note, this can be a profile added in the OpenXR runtime unknown to our default mappings
char active_profile_str[XR_MAX_PATH_LENGTH];
TrackingConfidence tracking_confidence;
};

InputMap inputmaps[USER_INPUT_MAX] = {
{ "/user/hand/left", XR_NULL_PATH, -1, XR_NULL_PATH, TRACKING_CONFIDENCE_NONE },
{ "/user/hand/right", XR_NULL_PATH, -1, XR_NULL_PATH, TRACKING_CONFIDENCE_NONE },
// gamepad is already supported in Godots own joystick handling, head we're using directly
// { "/user/foot/left", XR_NULL_PATH, -1, XR_NULL_PATH, TRACKING_CONFIDENCE_NONE },
// { "/user/foot/right", XR_NULL_PATH, -1, XR_NULL_PATH, TRACKING_CONFIDENCE_NONE },
// { "/user/treadmill", XR_NULL_PATH, -1, XR_NULL_PATH, TRACKING_CONFIDENCE_NONE },
};
std::vector<InputMap> inputmaps;

// Default actions we support so we can mimic our old ARVRController handling
enum DefaultActions {
Expand Down Expand Up @@ -250,6 +242,9 @@ class OpenXRApi {
bool initialiseSwapChains();
void cleanupSwapChains();

void setup_input_maps();
void cleanup_input_maps();

bool loadActionSets();
bool bindActionSets();
void unbindActionSets();
Expand Down Expand Up @@ -358,6 +353,8 @@ class OpenXRApi {

TrackingConfidence get_controller_tracking_confidence(const int p_godot_controller) const;

void add_input_map(const char * p_path);

static const char *default_action_sets_json;
godot::String get_action_sets_json() const;
void set_action_sets_json(const godot::String &p_action_sets_json);
Expand Down
2 changes: 2 additions & 0 deletions src/openxr/extensions/xr_extension_wrapper.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class XRExtensionWrapper {

virtual void on_session_initialized(const XrSession session) {}

virtual void add_input_maps() {}

virtual void on_state_idle() {}

virtual void on_state_ready() {}
Expand Down
57 changes: 57 additions & 0 deletions src/openxr/extensions/xr_htc_vive_tracker_extension_wrapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#include "xr_htc_vive_tracker_extension_wrapper.h"

XRHTCViveTrackerExtensionWrapper *XRHTCViveTrackerExtensionWrapper::singleton = nullptr;

XRHTCViveTrackerExtensionWrapper *XRHTCViveTrackerExtensionWrapper::get_singleton() {
if (!singleton) {
singleton = new XRHTCViveTrackerExtensionWrapper();
}

return singleton;
}

XRHTCViveTrackerExtensionWrapper::XRHTCViveTrackerExtensionWrapper() {
openxr_api = OpenXRApi::openxr_get_api();

request_extensions[XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME] = &available;
}

XRHTCViveTrackerExtensionWrapper::~XRHTCViveTrackerExtensionWrapper() {
OpenXRApi::openxr_release_api();
}

bool XRHTCViveTrackerExtensionWrapper::is_available() {
return available;
}

void XRHTCViveTrackerExtensionWrapper::add_input_maps() {
if (available) {
openxr_api->add_input_map("/user/vive_tracker_htcx/role/left_foot");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/left_foot");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/right_foot");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/left_shoulder");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/right_shoulder");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/left_elbow");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/right_elbow");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/left_knee");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/right_knee");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/waist");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/chest");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/camera");
openxr_api->add_input_map("/user/vive_tracker_htcx/role/keyboard");
}
}

bool XRHTCViveTrackerExtensionWrapper::on_event_polled(const XrEventDataBuffer &event) {
switch (event.type) {
case XR_TYPE_EVENT_DATA_VIVE_TRACKER_CONNECTED_HTCX: {
// Investigate if we need to do more here
printf("OpenXR EVENT: VIVE tracker connected");

return true;
} break;
default: {
return false;
} break;
}
}
26 changes: 26 additions & 0 deletions src/openxr/extensions/xr_htc_vive_tracker_extension_wrapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#ifndef XR_HTC_VIVE_TRACKER_EXTENSION_H
#define XR_HTC_VIVE_TRACKER_EXTENSION_H

#include "openxr/OpenXRApi.h"
#include "xr_extension_wrapper.h"
#include "openxr/include/util.h"

class XRHTCViveTrackerExtensionWrapper : public XRExtensionWrapper {
public:
static XRHTCViveTrackerExtensionWrapper *get_singleton();

XRHTCViveTrackerExtensionWrapper();
virtual ~XRHTCViveTrackerExtensionWrapper() override;

bool is_available();
virtual void add_input_maps() override;
virtual bool on_event_polled(const XrEventDataBuffer &event) override;

private:
static XRHTCViveTrackerExtensionWrapper *singleton;

OpenXRApi *openxr_api = nullptr;
bool available = false;
};

#endif // !XR_HTC_VIVE_TRACKER_EXTENSION_H

0 comments on commit c1a3608

Please sign in to comment.