mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2025-01-06 07:06:10 +00:00
d/steamvr_lh: Add Valve Knuckles support and emulated hands
Co-Authored-By: Gabriele Musco <gabmus@disroot.org>
This commit is contained in:
parent
938dd9c74f
commit
c139925e83
|
@ -449,6 +449,7 @@ if(XRT_BUILD_DRIVER_STEAMVR_LIGHTHOUSE)
|
||||||
PRIVATE
|
PRIVATE
|
||||||
aux_util
|
aux_util
|
||||||
aux_math
|
aux_math
|
||||||
|
aux_vive
|
||||||
xrt-interfaces
|
xrt-interfaces
|
||||||
xrt-external-openvr
|
xrt-external-openvr
|
||||||
xrt-external-cjson
|
xrt-external-cjson
|
||||||
|
|
|
@ -14,19 +14,31 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "math/m_api.h"
|
#include "math/m_api.h"
|
||||||
|
#include "math/m_relation_history.h"
|
||||||
|
#include "math/m_space.h"
|
||||||
#include "device.hpp"
|
#include "device.hpp"
|
||||||
#include "interfaces/context.hpp"
|
#include "interfaces/context.hpp"
|
||||||
|
#include "os/os_time.h"
|
||||||
|
#include "util/u_debug.h"
|
||||||
#include "util/u_device.h"
|
#include "util/u_device.h"
|
||||||
|
#include "util/u_hand_simulation.h"
|
||||||
|
#include "util/u_hand_tracking.h"
|
||||||
#include "util/u_logging.h"
|
#include "util/u_logging.h"
|
||||||
#include "util/u_json.hpp"
|
#include "util/u_json.hpp"
|
||||||
#include "xrt/xrt_defines.h"
|
#include "xrt/xrt_defines.h"
|
||||||
#include "xrt/xrt_device.h"
|
#include "xrt/xrt_device.h"
|
||||||
|
|
||||||
|
#include "vive/vive_poses.h"
|
||||||
|
|
||||||
#define DEV_ERR(...) U_LOG_IFL_E(ctx->log_level, __VA_ARGS__)
|
#define DEV_ERR(...) U_LOG_IFL_E(ctx->log_level, __VA_ARGS__)
|
||||||
#define DEV_WARN(...) U_LOG_IFL_W(ctx->log_level, __VA_ARGS__)
|
#define DEV_WARN(...) U_LOG_IFL_W(ctx->log_level, __VA_ARGS__)
|
||||||
#define DEV_INFO(...) U_LOG_IFL_I(ctx->log_level, __VA_ARGS__)
|
#define DEV_INFO(...) U_LOG_IFL_I(ctx->log_level, __VA_ARGS__)
|
||||||
#define DEV_DEBUG(...) U_LOG_IFL_D(ctx->log_level, __VA_ARGS__)
|
#define DEV_DEBUG(...) U_LOG_IFL_D(ctx->log_level, __VA_ARGS__)
|
||||||
|
|
||||||
|
#define DEG_TO_RAD(DEG) (DEG * M_PI / 180.)
|
||||||
|
|
||||||
|
DEBUG_GET_ONCE_BOOL_OPTION(lh_emulate_hand, "LH_EMULATE_HAND", true)
|
||||||
|
|
||||||
// Each device will have its own input class.
|
// Each device will have its own input class.
|
||||||
struct InputClass
|
struct InputClass
|
||||||
{
|
{
|
||||||
|
@ -34,13 +46,14 @@ struct InputClass
|
||||||
std::string description;
|
std::string description;
|
||||||
const std::vector<xrt_input_name> poses;
|
const std::vector<xrt_input_name> poses;
|
||||||
const std::unordered_map<std::string_view, xrt_input_name> non_poses;
|
const std::unordered_map<std::string_view, xrt_input_name> non_poses;
|
||||||
|
const std::unordered_map<std::string_view, IndexFinger> finger_curls;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
const std::unordered_map<std::string_view, InputClass> hmd_classes{
|
const std::unordered_map<std::string_view, InputClass> hmd_classes{
|
||||||
{"vive", InputClass{XRT_DEVICE_GENERIC_HMD, "Vive HMD", {XRT_INPUT_GENERIC_HEAD_POSE}, {}}},
|
{"vive", InputClass{XRT_DEVICE_GENERIC_HMD, "Vive HMD", {XRT_INPUT_GENERIC_HEAD_POSE}, {}, {}}},
|
||||||
{"indexhmd", InputClass{XRT_DEVICE_GENERIC_HMD, "Index HMD", {XRT_INPUT_GENERIC_HEAD_POSE}, {}}},
|
{"indexhmd", InputClass{XRT_DEVICE_GENERIC_HMD, "Index HMD", {XRT_INPUT_GENERIC_HEAD_POSE}, {}, {}}},
|
||||||
{"vive_pro", InputClass{XRT_DEVICE_GENERIC_HMD, "Vive Pro HMD", {XRT_INPUT_GENERIC_HEAD_POSE}, {}}},
|
{"vive_pro", InputClass{XRT_DEVICE_GENERIC_HMD, "Vive Pro HMD", {XRT_INPUT_GENERIC_HEAD_POSE}, {}, {}}},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Adding support for a new controller is a simple as adding it here.
|
// Adding support for a new controller is a simple as adding it here.
|
||||||
|
@ -65,10 +78,57 @@ const std::unordered_map<std::string_view, InputClass> controller_classes{
|
||||||
{"/input/grip/click", XRT_INPUT_VIVE_SQUEEZE_CLICK},
|
{"/input/grip/click", XRT_INPUT_VIVE_SQUEEZE_CLICK},
|
||||||
{"/input/trackpad", XRT_INPUT_VIVE_TRACKPAD},
|
{"/input/trackpad", XRT_INPUT_VIVE_TRACKPAD},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
// No fingers on this controller type
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"index_controller",
|
||||||
|
InputClass{
|
||||||
|
XRT_DEVICE_INDEX_CONTROLLER,
|
||||||
|
"Valve Index Controller",
|
||||||
|
{
|
||||||
|
XRT_INPUT_INDEX_GRIP_POSE,
|
||||||
|
XRT_INPUT_INDEX_AIM_POSE,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{"/input/system/click", XRT_INPUT_INDEX_SYSTEM_CLICK},
|
||||||
|
{"/input/system/touch", XRT_INPUT_INDEX_SYSTEM_TOUCH},
|
||||||
|
{"/input/a/click", XRT_INPUT_INDEX_A_CLICK},
|
||||||
|
{"/input/a/touch", XRT_INPUT_INDEX_A_TOUCH},
|
||||||
|
{"/input/b/click", XRT_INPUT_INDEX_B_CLICK},
|
||||||
|
{"/input/b/touch", XRT_INPUT_INDEX_B_TOUCH},
|
||||||
|
{"/input/trigger/click", XRT_INPUT_INDEX_TRIGGER_CLICK},
|
||||||
|
{"/input/trigger/touch", XRT_INPUT_INDEX_TRIGGER_TOUCH},
|
||||||
|
{"/input/trigger/value", XRT_INPUT_INDEX_TRIGGER_VALUE},
|
||||||
|
{"/input/grip/force", XRT_INPUT_INDEX_SQUEEZE_FORCE},
|
||||||
|
{"/input/grip/value", XRT_INPUT_INDEX_SQUEEZE_VALUE},
|
||||||
|
{"/input/thumbstick/click", XRT_INPUT_INDEX_THUMBSTICK_CLICK},
|
||||||
|
{"/input/thumbstick/touch", XRT_INPUT_INDEX_THUMBSTICK_TOUCH},
|
||||||
|
{"/input/thumbstick", XRT_INPUT_INDEX_THUMBSTICK},
|
||||||
|
{"/input/trackpad/force", XRT_INPUT_INDEX_TRACKPAD_FORCE},
|
||||||
|
{"/input/trackpad/touch", XRT_INPUT_INDEX_TRACKPAD_TOUCH},
|
||||||
|
{"/input/trackpad", XRT_INPUT_INDEX_TRACKPAD},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{"/input/finger/index", IndexFinger::Index},
|
||||||
|
{"/input/finger/middle", IndexFinger::Middle},
|
||||||
|
{"/input/finger/ring", IndexFinger::Ring},
|
||||||
|
{"/input/finger/pinky", IndexFinger::Pinky},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint64_t
|
||||||
|
chrono_timestamp_ns()
|
||||||
|
{
|
||||||
|
auto now = std::chrono::steady_clock::now().time_since_epoch();
|
||||||
|
uint64_t ts = std::chrono::duration_cast<std::chrono::nanoseconds>(now).count();
|
||||||
|
return ts;
|
||||||
|
}
|
||||||
|
|
||||||
// Template for calling a member function of Device from a free function
|
// Template for calling a member function of Device from a free function
|
||||||
template <typename DeviceType, auto Func, typename Ret, typename... Args>
|
template <typename DeviceType, auto Func, typename Ret, typename... Args>
|
||||||
inline Ret
|
inline Ret
|
||||||
|
@ -95,17 +155,26 @@ ControllerDevice::ControllerDevice(vr::PropertyContainerHandle_t handle, const D
|
||||||
{
|
{
|
||||||
this->device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER;
|
this->device_type = XRT_DEVICE_TYPE_ANY_HAND_CONTROLLER;
|
||||||
this->container_handle = handle;
|
this->container_handle = handle;
|
||||||
this->xrt_device::set_output = &device_bouncer<ControllerDevice, &ControllerDevice::set_output>;
|
#define SETUP_MEMBER_FUNC(name) this->xrt_device::name = &device_bouncer<ControllerDevice, &ControllerDevice::name>
|
||||||
|
SETUP_MEMBER_FUNC(set_output);
|
||||||
|
SETUP_MEMBER_FUNC(get_hand_tracking);
|
||||||
|
#undef SETUP_MEMBER_FUNC
|
||||||
|
}
|
||||||
|
|
||||||
|
Device::~Device()
|
||||||
|
{
|
||||||
|
m_relation_history_destroy(&relation_hist);
|
||||||
}
|
}
|
||||||
|
|
||||||
Device::Device(const DeviceBuilder &builder) : xrt_device({}), ctx(builder.ctx), driver(builder.driver)
|
Device::Device(const DeviceBuilder &builder) : xrt_device({}), ctx(builder.ctx), driver(builder.driver)
|
||||||
{
|
{
|
||||||
|
m_relation_history_create(&relation_hist);
|
||||||
std::strncpy(this->serial, builder.serial, XRT_DEVICE_NAME_LEN - 1);
|
std::strncpy(this->serial, builder.serial, XRT_DEVICE_NAME_LEN - 1);
|
||||||
this->serial[XRT_DEVICE_NAME_LEN - 1] = 0;
|
this->serial[XRT_DEVICE_NAME_LEN - 1] = 0;
|
||||||
this->tracking_origin = ctx.get();
|
this->tracking_origin = ctx.get();
|
||||||
this->orientation_tracking_supported = true;
|
this->orientation_tracking_supported = true;
|
||||||
this->position_tracking_supported = true;
|
this->position_tracking_supported = true;
|
||||||
this->hand_tracking_supported = false;
|
this->hand_tracking_supported = true;
|
||||||
this->force_feedback_supported = false;
|
this->force_feedback_supported = false;
|
||||||
this->form_factor_check_supported = false;
|
this->form_factor_check_supported = false;
|
||||||
|
|
||||||
|
@ -123,6 +192,14 @@ Device::Device(const DeviceBuilder &builder) : xrt_device({}), ctx(builder.ctx),
|
||||||
init_chaperone(builder.steam_install);
|
init_chaperone(builder.steam_install);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ControllerDevice::set_hand_tracking_hand(xrt_input_name name)
|
||||||
|
{
|
||||||
|
if (has_index_hand_tracking) {
|
||||||
|
inputs_map["HAND"]->name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Device::set_input_class(const InputClass *input_class)
|
Device::set_input_class(const InputClass *input_class)
|
||||||
{
|
{
|
||||||
|
@ -131,7 +208,7 @@ Device::set_input_class(const InputClass *input_class)
|
||||||
this->input_class = input_class;
|
this->input_class = input_class;
|
||||||
|
|
||||||
// reserve to ensure our pointers don't get invalidated
|
// reserve to ensure our pointers don't get invalidated
|
||||||
inputs_vec.reserve(input_class->poses.size() + input_class->non_poses.size());
|
inputs_vec.reserve(input_class->poses.size() + input_class->non_poses.size() + 1);
|
||||||
for (xrt_input_name input : input_class->poses) {
|
for (xrt_input_name input : input_class->poses) {
|
||||||
inputs_vec.push_back({true, 0, input, {}});
|
inputs_vec.push_back({true, 0, input, {}});
|
||||||
}
|
}
|
||||||
|
@ -140,11 +217,94 @@ Device::set_input_class(const InputClass *input_class)
|
||||||
inputs_vec.push_back({true, 0, input, {}});
|
inputs_vec.push_back({true, 0, input, {}});
|
||||||
inputs_map.insert({path, &inputs_vec.back()});
|
inputs_map.insert({path, &inputs_vec.back()});
|
||||||
}
|
}
|
||||||
|
|
||||||
this->inputs = inputs_vec.data();
|
this->inputs = inputs_vec.data();
|
||||||
this->input_count = inputs_vec.size();
|
this->input_count = inputs_vec.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ControllerDevice::set_input_class(const InputClass *input_class)
|
||||||
|
{
|
||||||
|
Device::set_input_class(input_class);
|
||||||
|
if (!debug_get_bool_option_lh_emulate_hand()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
has_index_hand_tracking = !input_class->finger_curls.empty();
|
||||||
|
if (!has_index_hand_tracking) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
finger_inputs_vec.reserve(input_class->finger_curls.size());
|
||||||
|
for (const auto &[path, finger] : input_class->finger_curls) {
|
||||||
|
finger_inputs_vec.push_back({0, finger, 0.f});
|
||||||
|
finger_inputs_map.insert({path, &finger_inputs_vec.back()});
|
||||||
|
}
|
||||||
|
inputs_vec.push_back({true, 0, XRT_INPUT_GENERIC_HAND_TRACKING_LEFT, {}});
|
||||||
|
inputs_map.insert({std::string_view("HAND"), &inputs_vec.back()});
|
||||||
|
this->inputs = inputs_vec.data();
|
||||||
|
this->input_count = inputs_vec.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
xrt_hand
|
||||||
|
ControllerDevice::get_xrt_hand()
|
||||||
|
{
|
||||||
|
switch (this->device_type) {
|
||||||
|
case XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER: {
|
||||||
|
return xrt_hand::XRT_HAND_LEFT;
|
||||||
|
}
|
||||||
|
case XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER: {
|
||||||
|
return xrt_hand::XRT_HAND_RIGHT;
|
||||||
|
}
|
||||||
|
default: DEV_ERR("Device %s cannot be tracked as a hand!", serial); return xrt_hand::XRT_HAND_LEFT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> FACE_BUTTONS = {
|
||||||
|
"/input/system/touch", "/input/a/touch", "/input/b/touch", "/input/thumbstick/touch", "/input/trackpad/touch",
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
ControllerDevice::update_hand_tracking(struct xrt_hand_joint_set *out)
|
||||||
|
{
|
||||||
|
if (!has_index_hand_tracking)
|
||||||
|
return;
|
||||||
|
float index = 0.f;
|
||||||
|
float middle = 0.f;
|
||||||
|
float ring = 0.f;
|
||||||
|
float pinky = 0.f;
|
||||||
|
float thumb = 0.f;
|
||||||
|
for (auto fi : finger_inputs_vec) {
|
||||||
|
switch (fi.finger) {
|
||||||
|
case IndexFinger::Index: index = fi.value; break;
|
||||||
|
case IndexFinger::Middle: middle = fi.value; break;
|
||||||
|
case IndexFinger::Ring: ring = fi.value; break;
|
||||||
|
case IndexFinger::Pinky: pinky = fi.value; break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const auto &name : FACE_BUTTONS) {
|
||||||
|
auto *input = get_input_from_name(name);
|
||||||
|
if (input && input->value.boolean) {
|
||||||
|
thumb = 1.f;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto curl_values = u_hand_tracking_curl_values{pinky, ring, middle, index, thumb};
|
||||||
|
|
||||||
|
struct xrt_space_relation hand_relation = {};
|
||||||
|
|
||||||
|
m_relation_history_get(relation_hist, last_pose_timestamp, &hand_relation);
|
||||||
|
|
||||||
|
u_hand_sim_simulate_for_valve_index_knuckles(&curl_values, get_xrt_hand(), &hand_relation, out);
|
||||||
|
|
||||||
|
struct xrt_relation_chain chain = {};
|
||||||
|
|
||||||
|
struct xrt_pose pose_offset = XRT_POSE_IDENTITY;
|
||||||
|
vive_poses_get_pose_offset(name, device_type, inputs_map["HAND"]->name, &pose_offset);
|
||||||
|
|
||||||
|
m_relation_chain_push_pose(&chain, &pose_offset);
|
||||||
|
m_relation_chain_push_relation(&chain, &hand_relation);
|
||||||
|
m_relation_chain_resolve(&chain, &out->hand_pose);
|
||||||
|
}
|
||||||
|
|
||||||
xrt_input *
|
xrt_input *
|
||||||
Device::get_input_from_name(const std::string_view name)
|
Device::get_input_from_name(const std::string_view name)
|
||||||
{
|
{
|
||||||
|
@ -169,6 +329,10 @@ ControllerDevice::set_haptic_handle(vr::VRInputComponentHandle_t handle)
|
||||||
name = XRT_OUTPUT_NAME_VIVE_HAPTIC;
|
name = XRT_OUTPUT_NAME_VIVE_HAPTIC;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case XRT_DEVICE_INDEX_CONTROLLER: {
|
||||||
|
name = XRT_OUTPUT_NAME_INDEX_HAPTIC;
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
DEV_WARN("Unknown device name (%u), haptics will not work", this->name);
|
DEV_WARN("Unknown device name (%u), haptics will not work", this->name);
|
||||||
return;
|
return;
|
||||||
|
@ -185,22 +349,57 @@ Device::update_inputs()
|
||||||
ctx->maybe_run_frame(++current_frame);
|
ctx->maybe_run_frame(++current_frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
IndexFingerInput *
|
||||||
Device::get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation)
|
ControllerDevice::get_finger_from_name(const std::string_view name)
|
||||||
{
|
{
|
||||||
*out_relation = this->relation;
|
auto finger = finger_inputs_map.find(name);
|
||||||
|
if (finger == finger_inputs_map.end()) {
|
||||||
|
DEV_WARN("requested unknown finger name %s for device %s", std::string(name).c_str(), serial);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return finger->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ControllerDevice::get_hand_tracking(enum xrt_input_name name,
|
||||||
|
uint64_t desired_timestamp_ns,
|
||||||
|
struct xrt_hand_joint_set *out_value,
|
||||||
|
uint64_t *out_timestamp_ns)
|
||||||
|
{
|
||||||
|
if (!has_index_hand_tracking)
|
||||||
|
return;
|
||||||
|
update_hand_tracking(out_value);
|
||||||
|
out_value->is_active = true;
|
||||||
|
hand_tracking_timestamp = desired_timestamp_ns;
|
||||||
|
*out_timestamp_ns = hand_tracking_timestamp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
HmdDevice::get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation)
|
HmdDevice::get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation)
|
||||||
{
|
{
|
||||||
*out_relation = relation;
|
*out_relation = relation;
|
||||||
|
// TODO: figure this out, it's not doing anything like this
|
||||||
|
// at_timestamp_ns += vsync_to_photon_ns == 0.f ? 11000000L : static_cast<uint64_t>(vsync_to_photon_ns);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ControllerDevice::get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation)
|
ControllerDevice::get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation)
|
||||||
{
|
{
|
||||||
*out_relation = relation;
|
xrt_space_relation rel = {};
|
||||||
|
m_relation_history_get(relation_hist, last_pose_timestamp, &rel);
|
||||||
|
|
||||||
|
xrt_pose pose_offset = XRT_POSE_IDENTITY;
|
||||||
|
vive_poses_get_pose_offset(input_class->name, device_type, name, &pose_offset);
|
||||||
|
|
||||||
|
xrt_relation_chain relchain = {};
|
||||||
|
|
||||||
|
m_relation_chain_push_pose(&relchain, &pose_offset);
|
||||||
|
m_relation_chain_push_relation(&relchain, &rel);
|
||||||
|
m_relation_chain_resolve(&relchain, out_relation);
|
||||||
|
|
||||||
|
struct xrt_pose *p = &out_relation->pose;
|
||||||
|
DEV_DEBUG("controller %u: GET_POSITION (%f %f %f) GET_ORIENTATION (%f, %f, %f, %f)", name, p->position.x,
|
||||||
|
p->position.y, p->position.z, p->orientation.x, p->orientation.y, p->orientation.z, p->orientation.w);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -413,6 +612,11 @@ Device::update_pose(const vr::DriverPose_t &newPose)
|
||||||
relation.relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
|
relation.relation_flags = XRT_SPACE_RELATION_BITMASK_NONE;
|
||||||
}
|
}
|
||||||
this->relation = relation;
|
this->relation = relation;
|
||||||
|
uint64_t ts = chrono_timestamp_ns();
|
||||||
|
uint64_t ts_offset = static_cast<uint64_t>(newPose.poseTimeOffset * 1000000.0);
|
||||||
|
ts += ts_offset;
|
||||||
|
last_pose_timestamp = ts;
|
||||||
|
m_relation_history_push(relation_hist, &relation, ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -507,6 +711,24 @@ ControllerDevice::handle_property_write(const vr::PropertyWrite_t &prop)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: break;
|
case vr::Prop_ControllerRoleHint_Int32: {
|
||||||
|
vr::ETrackedControllerRole role = *static_cast<vr::ETrackedControllerRole *>(prop.pvBuffer);
|
||||||
|
switch (role) {
|
||||||
|
case vr::TrackedControllerRole_RightHand: {
|
||||||
|
this->device_type = XRT_DEVICE_TYPE_RIGHT_HAND_CONTROLLER;
|
||||||
|
set_hand_tracking_hand(XRT_INPUT_GENERIC_HAND_TRACKING_RIGHT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vr::TrackedControllerRole_LeftHand: {
|
||||||
|
this->device_type = XRT_DEVICE_TYPE_LEFT_HAND_CONTROLLER;
|
||||||
|
set_hand_tracking_hand(XRT_INPUT_GENERIC_HAND_TRACKING_LEFT);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: DEV_DEBUG("Unassigned controller property: %i", prop.prop); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
|
||||||
|
#include "interfaces/context.hpp"
|
||||||
|
#include "math/m_relation_history.h"
|
||||||
#include "xrt/xrt_device.h"
|
#include "xrt/xrt_device.h"
|
||||||
#include "openvr_driver.h"
|
#include "openvr_driver.h"
|
||||||
|
|
||||||
|
@ -39,8 +41,9 @@ class Device : public xrt_device
|
||||||
|
|
||||||
public:
|
public:
|
||||||
xrt_space_relation relation = XRT_SPACE_RELATION_ZERO;
|
xrt_space_relation relation = XRT_SPACE_RELATION_ZERO;
|
||||||
|
m_relation_history *relation_hist;
|
||||||
|
|
||||||
virtual ~Device() = default;
|
virtual ~Device();
|
||||||
|
|
||||||
xrt_input *
|
xrt_input *
|
||||||
get_input_from_name(std::string_view name);
|
get_input_from_name(std::string_view name);
|
||||||
|
@ -62,6 +65,13 @@ protected:
|
||||||
Device(const DeviceBuilder &builder);
|
Device(const DeviceBuilder &builder);
|
||||||
std::shared_ptr<Context> ctx;
|
std::shared_ptr<Context> ctx;
|
||||||
vr::PropertyContainerHandle_t container_handle{0};
|
vr::PropertyContainerHandle_t container_handle{0};
|
||||||
|
std::unordered_map<std::string_view, xrt_input *> inputs_map;
|
||||||
|
std::vector<xrt_input> inputs_vec;
|
||||||
|
inline static xrt_vec3 chaperone_center{};
|
||||||
|
inline static xrt_quat chaperone_yaw = XRT_QUAT_IDENTITY;
|
||||||
|
const InputClass *input_class;
|
||||||
|
uint64_t last_pose_timestamp{0};
|
||||||
|
|
||||||
float vsync_to_photon_ns{0.f};
|
float vsync_to_photon_ns{0.f};
|
||||||
|
|
||||||
virtual void
|
virtual void
|
||||||
|
@ -72,16 +82,11 @@ protected:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vr::ITrackedDeviceServerDriver *driver;
|
vr::ITrackedDeviceServerDriver *driver;
|
||||||
const InputClass *input_class;
|
|
||||||
std::vector<xrt_binding_profile> binding_profiles_vec;
|
std::vector<xrt_binding_profile> binding_profiles_vec;
|
||||||
std::unordered_map<std::string_view, xrt_input *> inputs_map;
|
|
||||||
std::vector<xrt_input> inputs_vec;
|
|
||||||
uint64_t current_frame{0};
|
uint64_t current_frame{0};
|
||||||
|
|
||||||
void
|
void
|
||||||
init_chaperone(const std::string &steam_install);
|
init_chaperone(const std::string &steam_install);
|
||||||
inline static xrt_vec3 chaperone_center{};
|
|
||||||
inline static xrt_quat chaperone_yaw = XRT_QUAT_IDENTITY;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class HmdDevice : public Device
|
class HmdDevice : public Device
|
||||||
|
@ -140,6 +145,10 @@ private:
|
||||||
|
|
||||||
class ControllerDevice : public Device
|
class ControllerDevice : public Device
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
|
void
|
||||||
|
set_input_class(const InputClass *input_class);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ControllerDevice(vr::PropertyContainerHandle_t container_handle, const DeviceBuilder &builder);
|
ControllerDevice(vr::PropertyContainerHandle_t container_handle, const DeviceBuilder &builder);
|
||||||
|
|
||||||
|
@ -152,9 +161,31 @@ public:
|
||||||
void
|
void
|
||||||
get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation) override;
|
get_tracked_pose(xrt_input_name name, uint64_t at_timestamp_ns, xrt_space_relation *out_relation) override;
|
||||||
|
|
||||||
|
IndexFingerInput *
|
||||||
|
get_finger_from_name(std::string_view name);
|
||||||
|
|
||||||
|
void
|
||||||
|
get_hand_tracking(enum xrt_input_name name,
|
||||||
|
uint64_t desired_timestamp_ns,
|
||||||
|
struct xrt_hand_joint_set *out_value,
|
||||||
|
uint64_t *out_timestamp_ns);
|
||||||
|
|
||||||
|
xrt_hand
|
||||||
|
get_xrt_hand();
|
||||||
|
|
||||||
|
void
|
||||||
|
update_hand_tracking(struct xrt_hand_joint_set *out);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
vr::VRInputComponentHandle_t haptic_handle{0};
|
vr::VRInputComponentHandle_t haptic_handle{0};
|
||||||
std::unique_ptr<xrt_output> output{nullptr};
|
std::unique_ptr<xrt_output> output{nullptr};
|
||||||
|
bool has_index_hand_tracking{false};
|
||||||
|
std::vector<IndexFingerInput> finger_inputs_vec;
|
||||||
|
std::unordered_map<std::string_view, IndexFingerInput *> finger_inputs_map;
|
||||||
|
uint64_t hand_tracking_timestamp;
|
||||||
|
|
||||||
|
void
|
||||||
|
set_hand_tracking_hand(xrt_input_name name);
|
||||||
|
|
||||||
void
|
void
|
||||||
handle_property_write(const vr::PropertyWrite_t &prop) override;
|
handle_property_write(const vr::PropertyWrite_t &prop) override;
|
||||||
|
|
|
@ -28,6 +28,22 @@
|
||||||
|
|
||||||
#include "xrt/xrt_tracking.h"
|
#include "xrt/xrt_tracking.h"
|
||||||
|
|
||||||
|
enum IndexFinger
|
||||||
|
{
|
||||||
|
Invalid = -1,
|
||||||
|
Index = 1,
|
||||||
|
Middle,
|
||||||
|
Ring,
|
||||||
|
Pinky,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IndexFingerInput
|
||||||
|
{
|
||||||
|
int64_t timestamp;
|
||||||
|
IndexFinger finger;
|
||||||
|
float value;
|
||||||
|
};
|
||||||
|
|
||||||
struct xrt_input;
|
struct xrt_input;
|
||||||
class Device;
|
class Device;
|
||||||
class Context final : public xrt_tracking_origin,
|
class Context final : public xrt_tracking_origin,
|
||||||
|
@ -49,7 +65,9 @@ class Context final : public xrt_tracking_origin,
|
||||||
|
|
||||||
uint64_t current_frame{0};
|
uint64_t current_frame{0};
|
||||||
|
|
||||||
|
std::vector<vr::VRInputComponentHandle_t> handles;
|
||||||
std::unordered_map<vr::VRInputComponentHandle_t, xrt_input *> handle_to_input;
|
std::unordered_map<vr::VRInputComponentHandle_t, xrt_input *> handle_to_input;
|
||||||
|
std::unordered_map<vr::VRInputComponentHandle_t, IndexFingerInput *> handle_to_finger;
|
||||||
struct Vec2Components
|
struct Vec2Components
|
||||||
{
|
{
|
||||||
vr::VRInputComponentHandle_t x;
|
vr::VRInputComponentHandle_t x;
|
||||||
|
@ -86,6 +104,14 @@ class Context final : public xrt_tracking_origin,
|
||||||
setup_controller(const char *serial, vr::ITrackedDeviceServerDriver *driver);
|
setup_controller(const char *serial, vr::ITrackedDeviceServerDriver *driver);
|
||||||
vr::IServerTrackedDeviceProvider *provider;
|
vr::IServerTrackedDeviceProvider *provider;
|
||||||
|
|
||||||
|
inline vr::VRInputComponentHandle_t
|
||||||
|
new_handle()
|
||||||
|
{
|
||||||
|
vr::VRInputComponentHandle_t h = handles.size() + 1;
|
||||||
|
handles.push_back(h);
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Context(const std::string &steam_install, const std::string &steamvr_install, u_logging_level level);
|
Context(const std::string &steam_install, const std::string &steamvr_install, u_logging_level level);
|
||||||
|
|
||||||
|
|
|
@ -351,9 +351,17 @@ Context::create_component_common(vr::PropertyContainerHandle_t container,
|
||||||
}
|
}
|
||||||
if (xrt_input *input = device->get_input_from_name(name); input) {
|
if (xrt_input *input = device->get_input_from_name(name); input) {
|
||||||
CTX_DEBUG("creating component %s", name);
|
CTX_DEBUG("creating component %s", name);
|
||||||
vr::VRInputComponentHandle_t handle = handle_to_input.size() + 1;
|
vr::VRInputComponentHandle_t handle = new_handle();
|
||||||
handle_to_input[handle] = input;
|
handle_to_input[handle] = input;
|
||||||
*pHandle = handle;
|
*pHandle = handle;
|
||||||
|
} else if (device != hmd) {
|
||||||
|
auto *controller = static_cast<ControllerDevice *>(device);
|
||||||
|
if (IndexFingerInput *finger = controller->get_finger_from_name(name); finger) {
|
||||||
|
CTX_DEBUG("creating finger component %s", name);
|
||||||
|
vr::VRInputComponentHandle_t handle = new_handle();
|
||||||
|
handle_to_finger[handle] = finger;
|
||||||
|
*pHandle = handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return vr::VRInputError_None;
|
return vr::VRInputError_None;
|
||||||
}
|
}
|
||||||
|
@ -404,7 +412,8 @@ Context::CreateScalarComponent(vr::PropertyContainerHandle_t ulContainer,
|
||||||
// Lighthouse gives thumbsticks/trackpads as x/y components,
|
// Lighthouse gives thumbsticks/trackpads as x/y components,
|
||||||
// we need to combine them for Monado
|
// we need to combine them for Monado
|
||||||
auto end = name.back();
|
auto end = name.back();
|
||||||
if (end == 'x' || end == 'y') {
|
auto second_last = name.at(name.size() - 2);
|
||||||
|
if (second_last == '/' && (end == 'x' || end == 'y')) {
|
||||||
Device *device = prop_container_to_device(ulContainer);
|
Device *device = prop_container_to_device(ulContainer);
|
||||||
if (!device) {
|
if (!device) {
|
||||||
return vr::VRInputError_InvalidHandle;
|
return vr::VRInputError_InvalidHandle;
|
||||||
|
@ -421,7 +430,7 @@ Context::CreateScalarComponent(vr::PropertyContainerHandle_t ulContainer,
|
||||||
Vec2Components *components =
|
Vec2Components *components =
|
||||||
vec2_input_to_components.try_emplace(input, new Vec2Components).first->second.get();
|
vec2_input_to_components.try_emplace(input, new Vec2Components).first->second.get();
|
||||||
|
|
||||||
vr::VRInputComponentHandle_t new_handle = handle_to_input.size() + 1;
|
vr::VRInputComponentHandle_t new_handle = this->new_handle();
|
||||||
if (x)
|
if (x)
|
||||||
components->x = new_handle;
|
components->x = new_handle;
|
||||||
else
|
else
|
||||||
|
@ -437,8 +446,8 @@ Context::CreateScalarComponent(vr::PropertyContainerHandle_t ulContainer,
|
||||||
vr::EVRInputError
|
vr::EVRInputError
|
||||||
Context::UpdateScalarComponent(vr::VRInputComponentHandle_t ulComponent, float fNewValue, double fTimeOffset)
|
Context::UpdateScalarComponent(vr::VRInputComponentHandle_t ulComponent, float fNewValue, double fTimeOffset)
|
||||||
{
|
{
|
||||||
|
if (auto h = handle_to_input.find(ulComponent); h != handle_to_input.end() && h->second) {
|
||||||
xrt_input *input = update_component_common(ulComponent, fTimeOffset);
|
xrt_input *input = update_component_common(ulComponent, fTimeOffset);
|
||||||
if (input) {
|
|
||||||
if (XRT_GET_INPUT_TYPE(input->name) == XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE) {
|
if (XRT_GET_INPUT_TYPE(input->name) == XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE) {
|
||||||
std::unique_ptr<Vec2Components> &components = vec2_input_to_components.at(input);
|
std::unique_ptr<Vec2Components> &components = vec2_input_to_components.at(input);
|
||||||
if (components->x == ulComponent) {
|
if (components->x == ulComponent) {
|
||||||
|
@ -456,6 +465,21 @@ Context::UpdateScalarComponent(vr::VRInputComponentHandle_t ulComponent, float f
|
||||||
} else {
|
} else {
|
||||||
input->value.vec1.x = fNewValue;
|
input->value.vec1.x = fNewValue;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if (ulComponent != vr::k_ulInvalidInputComponentHandle) {
|
||||||
|
if (auto finger_input = handle_to_finger.find(ulComponent);
|
||||||
|
finger_input != handle_to_finger.end() && finger_input->second) {
|
||||||
|
auto now = std::chrono::steady_clock::now();
|
||||||
|
std::chrono::duration<double, std::chrono::seconds::period> offset_dur(fTimeOffset);
|
||||||
|
std::chrono::duration offset = (now + offset_dur).time_since_epoch();
|
||||||
|
int64_t timestamp =
|
||||||
|
std::chrono::duration_cast<std::chrono::nanoseconds>(offset).count();
|
||||||
|
finger_input->second->timestamp = timestamp;
|
||||||
|
finger_input->second->value = fNewValue;
|
||||||
|
} else {
|
||||||
|
CTX_WARN("Unmapped component %lu", ulComponent);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return vr::VRInputError_None;
|
return vr::VRInputError_None;
|
||||||
}
|
}
|
||||||
|
@ -479,7 +503,7 @@ Context::CreateHapticComponent(vr::PropertyContainerHandle_t ulContainer,
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *device = static_cast<ControllerDevice *>(d);
|
auto *device = static_cast<ControllerDevice *>(d);
|
||||||
vr::VRInputComponentHandle_t handle = handle_to_input.size() + 1;
|
vr::VRInputComponentHandle_t handle = new_handle();
|
||||||
handle_to_input[handle] = nullptr;
|
handle_to_input[handle] = nullptr;
|
||||||
device->set_haptic_handle(handle);
|
device->set_haptic_handle(handle);
|
||||||
*pHandle = handle;
|
*pHandle = handle;
|
||||||
|
|
Loading…
Reference in a new issue