mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2024-12-28 18:46:18 +00:00
st/oxr: Add interaction profile code
Not a complete implementation but gets us far enough to respect the bindings that a application gives us.
This commit is contained in:
parent
2337299279
commit
79ad85e9b7
|
@ -18,6 +18,7 @@ set(OXR_SOURCE_FILES
|
|||
oxr_api_swapchain.c
|
||||
oxr_api_system.c
|
||||
oxr_api_verify.h
|
||||
oxr_binding.c
|
||||
oxr_chain.h
|
||||
oxr_event.cpp
|
||||
oxr_extension_support.h
|
||||
|
|
|
@ -382,9 +382,9 @@ oxr_xrEnumerateBoundSourcesForAction(
|
|||
XR_TYPE_BOUND_SOURCES_FOR_ACTION_ENUMERATE_INFO);
|
||||
OXR_VERIFY_ACTION_NOT_NULL(&log, enumerateInfo->action, act);
|
||||
|
||||
return oxr_action_get_bound_sources(&log, sess, act->key,
|
||||
sourceCapacityInput,
|
||||
sourceCountOutput, sources);
|
||||
return oxr_action_enumerate_bound_sources(&log, sess, act->key,
|
||||
sourceCapacityInput,
|
||||
sourceCountOutput, sources);
|
||||
}
|
||||
|
||||
|
||||
|
|
821
src/xrt/state_trackers/oxr/oxr_binding.c
Normal file
821
src/xrt/state_trackers/oxr/oxr_binding.c
Normal file
|
@ -0,0 +1,821 @@
|
|||
// Copyright 2018-2019, Collabora, Ltd.
|
||||
// SPDX-License-Identifier: BSL-1.0
|
||||
/*!
|
||||
* @file
|
||||
* @brief Holds binding related functions.
|
||||
* @author Jakob Bornecrantz <jakob@collabora.com>
|
||||
* @ingroup oxr_main
|
||||
*/
|
||||
|
||||
#include "util/u_misc.h"
|
||||
|
||||
#include "xrt/xrt_compiler.h"
|
||||
|
||||
#include "oxr_objects.h"
|
||||
#include "oxr_logger.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
struct binding_template
|
||||
{
|
||||
const char *paths[8];
|
||||
enum xrt_input_name inputs[8];
|
||||
enum xrt_output_name outputs[8];
|
||||
enum oxr_sub_action_path sub_path;
|
||||
};
|
||||
|
||||
struct profile_template
|
||||
{
|
||||
const char *path;
|
||||
|
||||
|
||||
|
||||
struct binding_template *bindings;
|
||||
size_t num_bindings;
|
||||
};
|
||||
|
||||
static struct binding_template khr_simple_controller_bindings[10];
|
||||
static struct binding_template google_daydream_controller_bindings[12];
|
||||
|
||||
static struct profile_template profiles[2] = {
|
||||
{
|
||||
.path = "/interaction_profiles/khr/simple_controller",
|
||||
.bindings = khr_simple_controller_bindings,
|
||||
.num_bindings = ARRAY_SIZE(khr_simple_controller_bindings),
|
||||
},
|
||||
{
|
||||
.path = "/interaction_profiles/google/daydream_controller",
|
||||
.bindings = google_daydream_controller_bindings,
|
||||
.num_bindings = ARRAY_SIZE(google_daydream_controller_bindings),
|
||||
},
|
||||
};
|
||||
|
||||
static void
|
||||
setup_paths(struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
struct binding_template *templ,
|
||||
struct oxr_binding *binding)
|
||||
{
|
||||
size_t count = 0;
|
||||
while (templ->paths[count] != NULL) {
|
||||
count++;
|
||||
}
|
||||
|
||||
binding->num_paths = count;
|
||||
binding->paths = U_TYPED_ARRAY_CALLOC(XrPath, count);
|
||||
|
||||
for (size_t x = 0; x < binding->num_paths; x++) {
|
||||
const char *str = templ->paths[x];
|
||||
size_t len = strlen(str);
|
||||
oxr_path_get_or_create(log, inst, str, len, &binding->paths[x]);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setup_inputs(struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
struct binding_template *templ,
|
||||
struct oxr_binding *binding)
|
||||
{
|
||||
size_t count = 0;
|
||||
while (templ->inputs[count] != 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
binding->num_inputs = count;
|
||||
binding->inputs = U_TYPED_ARRAY_CALLOC(enum xrt_input_name, count);
|
||||
|
||||
for (size_t x = 0; x < binding->num_inputs; x++) {
|
||||
binding->inputs[x] = templ->inputs[x];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
setup_outputs(struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
struct binding_template *templ,
|
||||
struct oxr_binding *binding)
|
||||
{
|
||||
size_t count = 0;
|
||||
while (templ->outputs[count] != 0) {
|
||||
count++;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
binding->num_outputs = count;
|
||||
binding->outputs = U_TYPED_ARRAY_CALLOC(enum xrt_output_name, count);
|
||||
|
||||
for (size_t x = 0; x < binding->num_outputs; x++) {
|
||||
binding->outputs[x] = templ->outputs[x];
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
is_valid_interaction_profile(struct oxr_instance *inst, XrPath path)
|
||||
{
|
||||
return inst->path_cache.khr_simple_controller == path ||
|
||||
inst->path_cache.google_daydream_controller == path ||
|
||||
inst->path_cache.htc_vive_controller == path ||
|
||||
inst->path_cache.htc_vive_pro == path ||
|
||||
inst->path_cache.microsoft_motion_controller == path ||
|
||||
inst->path_cache.microsoft_xbox_controller == path ||
|
||||
inst->path_cache.oculus_go_controller == path ||
|
||||
inst->path_cache.oculus_touch_controller == path ||
|
||||
inst->path_cache.valve_index_controller == path;
|
||||
}
|
||||
|
||||
static bool
|
||||
interaction_profile_find(struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
XrPath path,
|
||||
struct oxr_interaction_profile **out_p)
|
||||
{
|
||||
for (size_t x = 0; x < inst->num_profiles; x++) {
|
||||
struct oxr_interaction_profile *p = inst->profiles[x];
|
||||
if (p->path != path) {
|
||||
continue;
|
||||
}
|
||||
|
||||
*out_p = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool
|
||||
interaction_profile_find_or_create(struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
XrPath path,
|
||||
struct oxr_interaction_profile **out_p)
|
||||
{
|
||||
if (interaction_profile_find(log, inst, path, out_p)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
struct profile_template *templ = NULL;
|
||||
for (size_t x = 0; x < ARRAY_SIZE(profiles); x++) {
|
||||
templ = &profiles[x];
|
||||
XrPath t_path = XR_NULL_PATH;
|
||||
|
||||
oxr_path_get_or_create(log, inst, templ->path,
|
||||
strlen(templ->path), &t_path);
|
||||
if (t_path == path) {
|
||||
break;
|
||||
} else {
|
||||
templ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (templ == NULL) {
|
||||
*out_p = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
struct oxr_interaction_profile *p =
|
||||
U_TYPED_CALLOC(struct oxr_interaction_profile);
|
||||
|
||||
p->num_bindings = templ->num_bindings;
|
||||
p->bindings = U_TYPED_ARRAY_CALLOC(struct oxr_binding, p->num_bindings);
|
||||
p->path = path;
|
||||
|
||||
for (size_t x = 0; x < templ->num_bindings; x++) {
|
||||
struct binding_template *t = &templ->bindings[x];
|
||||
struct oxr_binding *b = &p->bindings[x];
|
||||
|
||||
b->sub_path = t->sub_path;
|
||||
setup_paths(log, inst, t, b);
|
||||
setup_inputs(log, inst, t, b);
|
||||
setup_outputs(log, inst, t, b);
|
||||
}
|
||||
|
||||
// Add to the list of currently created interaction profiles.
|
||||
size_t size =
|
||||
sizeof(struct oxr_interaction_profile) * (inst->num_profiles + 1);
|
||||
inst->profiles = realloc(inst->profiles, size);
|
||||
inst->profiles[inst->num_profiles++] = p;
|
||||
|
||||
*out_p = p;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_all_keys(struct oxr_binding *bindings, size_t num_bindings)
|
||||
{
|
||||
for (size_t x = 0; x < num_bindings; x++) {
|
||||
free(bindings[x].keys);
|
||||
bindings[x].keys = NULL;
|
||||
bindings[x].num_keys = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
add_key_to_matching_bindings(struct oxr_binding *bindings,
|
||||
size_t num_bindings,
|
||||
XrPath path,
|
||||
uint32_t key)
|
||||
{
|
||||
for (size_t x = 0; x < num_bindings; x++) {
|
||||
struct oxr_binding *b = &bindings[x];
|
||||
|
||||
bool found = false;
|
||||
for (size_t y = 0; y < b->num_paths; y++) {
|
||||
if (b->paths[y] == path) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t size = sizeof(uint32_t) * (b->num_keys + 1);
|
||||
b->keys = realloc(b->keys, size);
|
||||
b->keys[b->num_keys++] = key;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* 'Exported' functions.
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
oxr_find_profile_for_device(struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
struct xrt_device *xdev,
|
||||
struct oxr_interaction_profile **out_p)
|
||||
{
|
||||
if (xdev == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
enum xrt_device_name name = xdev->name;
|
||||
|
||||
//! @todo A lot more clever selecting the profile here.
|
||||
switch (name) {
|
||||
case XRT_DEVICE_HYDRA:
|
||||
// clang-format off
|
||||
interaction_profile_find(log, inst, inst->path_cache.khr_simple_controller, out_p);
|
||||
// clang-format on
|
||||
return;
|
||||
case XRT_DEVICE_PSMV:
|
||||
// clang-format off
|
||||
interaction_profile_find(log, inst, inst->path_cache.khr_simple_controller, out_p);
|
||||
// clang-format on
|
||||
return;
|
||||
default: return;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
oxr_binding_find_bindings_from_key(struct oxr_logger *log,
|
||||
struct oxr_interaction_profile *p,
|
||||
uint32_t key,
|
||||
struct oxr_binding *bindings[32],
|
||||
size_t *num_bindings)
|
||||
{
|
||||
if (p == NULL) {
|
||||
*num_bindings = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
//! @todo This function should be a two call function, or handle more
|
||||
//! then 32 bindings.
|
||||
size_t num = 0;
|
||||
|
||||
for (size_t y = 0; y < p->num_bindings; y++) {
|
||||
struct oxr_binding *b = &p->bindings[y];
|
||||
|
||||
for (size_t z = 0; z < b->num_keys; z++) {
|
||||
if (b->keys[z] == key) {
|
||||
bindings[num++] = b;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (num >= 32) {
|
||||
*num_bindings = num;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
*num_bindings = num;
|
||||
}
|
||||
|
||||
void
|
||||
oxr_binding_destroy_all(struct oxr_logger *log, struct oxr_instance *inst)
|
||||
{
|
||||
for (size_t x = 0; x < inst->num_profiles; x++) {
|
||||
struct oxr_interaction_profile *p = inst->profiles[x];
|
||||
|
||||
for (size_t y = 0; y < p->num_bindings; y++) {
|
||||
struct oxr_binding *b = &p->bindings[y];
|
||||
free(b->paths);
|
||||
free(b->inputs);
|
||||
free(b->outputs);
|
||||
|
||||
b->paths = NULL;
|
||||
b->inputs = NULL;
|
||||
b->outputs = NULL;
|
||||
b->num_paths = 0;
|
||||
b->num_inputs = 0;
|
||||
b->num_outputs = 0;
|
||||
}
|
||||
|
||||
free(p->bindings);
|
||||
p->bindings = NULL;
|
||||
p->num_bindings = 0;
|
||||
}
|
||||
|
||||
free(inst->profiles);
|
||||
inst->profiles = NULL;
|
||||
inst->num_profiles = 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Client functions.
|
||||
*
|
||||
*/
|
||||
|
||||
XrResult
|
||||
oxr_action_suggest_interaction_profile_bindings(
|
||||
struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
const XrInteractionProfileSuggestedBinding *suggestedBindings)
|
||||
{
|
||||
struct oxr_interaction_profile *p = NULL;
|
||||
XrPath path = suggestedBindings->interactionProfile;
|
||||
const char *str;
|
||||
size_t length;
|
||||
|
||||
// Check if this profile is valid.
|
||||
if (!is_valid_interaction_profile(inst, path)) {
|
||||
oxr_path_get_string(log, inst, path, &str, &length);
|
||||
|
||||
return oxr_error(log, XR_ERROR_PATH_UNSUPPORTED,
|
||||
"(suggestedBindings->interactionProfile) "
|
||||
"non-supported profile '%s'",
|
||||
str);
|
||||
}
|
||||
|
||||
interaction_profile_find_or_create(log, inst, path, &p);
|
||||
|
||||
// Valid path, but not used.
|
||||
//! @todo Still needs to validate the paths.
|
||||
if (p == NULL) {
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
struct oxr_binding *bindings = p->bindings;
|
||||
size_t num_bindings = p->num_bindings;
|
||||
|
||||
//! @todo Validate keys **FIRST** then reset.
|
||||
reset_all_keys(bindings, num_bindings);
|
||||
|
||||
for (size_t i = 0; i < suggestedBindings->countSuggestedBindings; i++) {
|
||||
const XrActionSuggestedBinding *s =
|
||||
&suggestedBindings->suggestedBindings[i];
|
||||
struct oxr_action *act = (struct oxr_action *)s->action;
|
||||
|
||||
#if 0
|
||||
oxr_path_get_string(log, inst, s->binding, &str, &length);
|
||||
fprintf(stderr, "\t\t%s %i -> %s\n", act->name, act->key, str);
|
||||
#endif
|
||||
|
||||
add_key_to_matching_bindings(bindings, num_bindings, s->binding,
|
||||
act->key);
|
||||
}
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
XrResult
|
||||
oxr_action_get_current_interaction_profile(
|
||||
struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
XrPath topLevelUserPath,
|
||||
XrInteractionProfileState *interactionProfile)
|
||||
{
|
||||
struct oxr_instance *inst = sess->sys->inst;
|
||||
|
||||
if (!sess->actionsAttached) {
|
||||
return oxr_error(log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
||||
" xrAttachSessionActionSets has not been "
|
||||
"called on this session.");
|
||||
}
|
||||
|
||||
if (topLevelUserPath == inst->path_cache.head) {
|
||||
return sess->head;
|
||||
} else if (topLevelUserPath == inst->path_cache.left) {
|
||||
return sess->left;
|
||||
} else if (topLevelUserPath == inst->path_cache.right) {
|
||||
return sess->right;
|
||||
} else if (topLevelUserPath == inst->path_cache.gamepad) {
|
||||
return sess->gamepad;
|
||||
} else {
|
||||
return oxr_error(log, XR_ERROR_HANDLE_INVALID,
|
||||
" not implemented");
|
||||
}
|
||||
}
|
||||
|
||||
XrResult
|
||||
oxr_action_get_input_source_localized_name(
|
||||
struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
const XrInputSourceLocalizedNameGetInfo *getInfo,
|
||||
uint32_t bufferCapacityInput,
|
||||
uint32_t *bufferCountOutput,
|
||||
char *buffer)
|
||||
{
|
||||
//! @todo Implement
|
||||
return oxr_error(log, XR_ERROR_HANDLE_INVALID, " not implemented");
|
||||
}
|
||||
|
||||
XrResult
|
||||
oxr_action_enumerate_bound_sources(struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
uint64_t key,
|
||||
uint32_t sourceCapacityInput,
|
||||
uint32_t *sourceCountOutput,
|
||||
XrPath *sources)
|
||||
{
|
||||
//! @todo Implement
|
||||
return oxr_error(log, XR_ERROR_HANDLE_INVALID, " not implemented");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Shipped bindings.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*
|
||||
* KHR Simple Controller
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
static struct binding_template khr_simple_controller_bindings[10] = {
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/select/click",
|
||||
"/user/hand/left/input/select",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
XRT_INPUT_PSMV_TRIGGER_VALUE,
|
||||
XRT_INPUT_HYDRA_TRIGGER_VALUE,
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/menu/click",
|
||||
"/user/hand/left/input/menu",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
XRT_INPUT_PSMV_MOVE_CLICK,
|
||||
XRT_INPUT_HYDRA_MIDDLE_CLICK,
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/grip/pose",
|
||||
"/user/hand/left/input/grip",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
XRT_INPUT_PSMV_BODY_CENTER_POSE,
|
||||
XRT_INPUT_HYDRA_POSE,
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/aim/pose",
|
||||
"/user/hand/left/input/aim",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
XRT_INPUT_PSMV_BALL_TIP_POSE,
|
||||
XRT_INPUT_HYDRA_POSE,
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/output/haptic",
|
||||
NULL,
|
||||
},
|
||||
.outputs =
|
||||
{
|
||||
XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION,
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/select/click",
|
||||
"/user/hand/right/input/select",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
XRT_INPUT_PSMV_TRIGGER_VALUE,
|
||||
XRT_INPUT_HYDRA_TRIGGER_VALUE,
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/menu/click",
|
||||
"/user/hand/right/input/menu",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
XRT_INPUT_PSMV_MOVE_CLICK,
|
||||
XRT_INPUT_HYDRA_MIDDLE_CLICK,
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/grip/pose",
|
||||
"/user/hand/right/input/grip",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
XRT_INPUT_PSMV_BODY_CENTER_POSE,
|
||||
XRT_INPUT_HYDRA_POSE,
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/aim/pose",
|
||||
"/user/hand/right/input/aim",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
XRT_INPUT_PSMV_BALL_TIP_POSE,
|
||||
XRT_INPUT_HYDRA_POSE,
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/output/haptic",
|
||||
NULL,
|
||||
},
|
||||
.outputs =
|
||||
{
|
||||
XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION,
|
||||
0,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
*
|
||||
*
|
||||
* Google Daydream Controller
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
|
||||
static struct binding_template google_daydream_controller_bindings[12] = {
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/select/click",
|
||||
"/user/hand/left/input/select",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
#if 0
|
||||
XRT_INPUT_PSMV_TRIGGER_VALUE,
|
||||
XRT_INPUT_HYDRA_TRIGGER_VALUE,
|
||||
#endif
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
//! @todo Flag that this is a trackpad
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/trackpad",
|
||||
"/user/hand/left/input/trackpad/x",
|
||||
"/user/hand/left/input/trackpad/y",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/trackpad/click",
|
||||
"/user/hand/left/input/trackpad",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/trackpad/touch",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/grip/pose",
|
||||
"/user/hand/left/input/grip",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
#if 0
|
||||
XRT_INPUT_PSMV_BODY_CENTER_POSE,
|
||||
XRT_INPUT_HYDRA_POSE,
|
||||
#endif
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_LEFT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/left/input/aim/pose",
|
||||
"/user/hand/left/input/aim",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
#if 0
|
||||
XRT_INPUT_PSMV_BALL_TIP_POSE,
|
||||
XRT_INPUT_HYDRA_POSE,
|
||||
#endif
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/select/click",
|
||||
"/user/hand/right/input/select",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
#if 0
|
||||
XRT_INPUT_PSMV_TRIGGER_VALUE,
|
||||
XRT_INPUT_HYDRA_TRIGGER_VALUE,
|
||||
#endif
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
//! @todo Flag that this is a trackpad
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/trackpad",
|
||||
"/user/hand/right/input/trackpad/x",
|
||||
"/user/hand/right/input/trackpad/y",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/trackpad/click",
|
||||
"/user/hand/right/input/trackpad",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/trackpad/touch",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/grip/pose",
|
||||
"/user/hand/right/input/grip",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
#if 0
|
||||
XRT_INPUT_PSMV_BODY_CENTER_POSE,
|
||||
XRT_INPUT_HYDRA_POSE,
|
||||
#endif
|
||||
0,
|
||||
},
|
||||
},
|
||||
{
|
||||
.sub_path = OXR_SUB_ACTION_PATH_RIGHT,
|
||||
.paths =
|
||||
{
|
||||
"/user/hand/right/input/aim/pose",
|
||||
"/user/hand/right/input/aim",
|
||||
NULL,
|
||||
},
|
||||
.inputs =
|
||||
{
|
||||
#if 0
|
||||
XRT_INPUT_PSMV_BALL_TIP_POSE,
|
||||
XRT_INPUT_HYDRA_POSE,
|
||||
#endif
|
||||
0,
|
||||
},
|
||||
},
|
||||
};
|
|
@ -23,24 +23,6 @@
|
|||
#include "oxr_handle.h"
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Struct and defines.
|
||||
*
|
||||
*/
|
||||
|
||||
enum sub_action_path
|
||||
{
|
||||
// clang-format off
|
||||
OXR_SUB_ACTION_PATH_USER = 1 << 0,
|
||||
OXR_SUB_ACTION_PATH_HEAD = 1 << 1,
|
||||
OXR_SUB_ACTION_PATH_LEFT = 1 << 2,
|
||||
OXR_SUB_ACTION_PATH_RIGHT = 1 << 3,
|
||||
OXR_SUB_ACTION_PATH_GAMEPAD = 1 << 4,
|
||||
// clang-format on
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* Pre declare functions.
|
||||
|
@ -75,19 +57,24 @@ oxr_source_update(struct oxr_logger* log,
|
|||
|
||||
static void
|
||||
oxr_source_bind_inputs(struct oxr_logger* log,
|
||||
struct oxr_sink_logger* slog,
|
||||
struct oxr_session* sess,
|
||||
struct oxr_action* act,
|
||||
struct oxr_source_cache* cache,
|
||||
enum sub_action_path sub_path);
|
||||
struct oxr_interaction_profile* profile,
|
||||
enum oxr_sub_action_path sub_path);
|
||||
|
||||
static XrResult
|
||||
oxr_source_destroy_cb(struct oxr_logger* log, struct oxr_handle_base* hb);
|
||||
|
||||
static XrResult
|
||||
oxr_source_create(struct oxr_logger* log,
|
||||
struct oxr_session* sess,
|
||||
struct oxr_source_set* src_set,
|
||||
struct oxr_action* act,
|
||||
struct oxr_source** out_src);
|
||||
struct oxr_interaction_profile* head,
|
||||
struct oxr_interaction_profile* left,
|
||||
struct oxr_interaction_profile* right,
|
||||
struct oxr_interaction_profile* gamepad);
|
||||
|
||||
|
||||
/*
|
||||
|
@ -122,8 +109,10 @@ oxr_action_set_create(struct oxr_logger* log,
|
|||
oxr_action_set_destroy_cb, &inst->handle);
|
||||
|
||||
act_set->key = key_gen++;
|
||||
act_set->generation = 1;
|
||||
|
||||
act_set->inst = inst;
|
||||
strncpy(act_set->name, createInfo->actionSetName,
|
||||
sizeof(act_set->name));
|
||||
|
||||
*out_act_set = act_set;
|
||||
|
||||
|
@ -143,10 +132,6 @@ oxr_action_destroy_cb(struct oxr_logger* log, struct oxr_handle_base* hb)
|
|||
//! @todo Move to oxr_objects.h
|
||||
struct oxr_action* act = (struct oxr_action*)hb;
|
||||
|
||||
// Need to keep track of the generation of this
|
||||
// action set to rebuild bindings when used.
|
||||
act->act_set->generation++;
|
||||
|
||||
free(act);
|
||||
|
||||
return XR_SUCCESS;
|
||||
|
@ -178,10 +163,6 @@ oxr_action_create(struct oxr_logger* log,
|
|||
|
||||
strncpy(act->name, createInfo->actionName, sizeof(act->name));
|
||||
|
||||
// Need to keep track of the generation of this
|
||||
// action set to rebuild bindings when used.
|
||||
act_set->generation++;
|
||||
|
||||
*out_act = act;
|
||||
|
||||
return XR_SUCCESS;
|
||||
|
@ -280,65 +261,164 @@ oxr_source_get_pose_input(struct oxr_logger* log,
|
|||
|
||||
/*
|
||||
*
|
||||
* MEGA HACK Functions!
|
||||
* Not so hack functions.
|
||||
*
|
||||
*/
|
||||
|
||||
static void
|
||||
MEGA_HACK_get_binding(struct oxr_logger* log,
|
||||
struct oxr_session* sess,
|
||||
struct oxr_action* act,
|
||||
enum sub_action_path sub_path,
|
||||
struct oxr_source_input inputs[16],
|
||||
uint32_t* num_inputs,
|
||||
struct oxr_source_output outputs[16],
|
||||
uint32_t* num_outputs)
|
||||
static bool
|
||||
do_inputs(struct oxr_binding* bind,
|
||||
struct xrt_device* xdev,
|
||||
struct oxr_source_input inputs[16],
|
||||
uint32_t* num_inputs)
|
||||
{
|
||||
struct xrt_input* input = NULL;
|
||||
struct xrt_output* output = NULL;
|
||||
struct xrt_device* xdev = NULL;
|
||||
bool found = false;
|
||||
|
||||
for (size_t i = 0; i < bind->num_inputs; i++) {
|
||||
if (oxr_xdev_find_input(xdev, bind->inputs[i], &input)) {
|
||||
uint32_t index = (*num_inputs)++;
|
||||
inputs[index].input = input;
|
||||
inputs[index].xdev = xdev;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool
|
||||
do_outputs(struct oxr_binding* bind,
|
||||
struct xrt_device* xdev,
|
||||
struct oxr_source_output outputs[16],
|
||||
uint32_t* num_outputs)
|
||||
{
|
||||
struct xrt_output* output = NULL;
|
||||
bool found = false;
|
||||
|
||||
for (size_t i = 0; i < bind->num_outputs; i++) {
|
||||
if (oxr_xdev_find_output(xdev, bind->outputs[i], &output)) {
|
||||
uint32_t index = (*num_outputs)++;
|
||||
outputs[index].name = output->name;
|
||||
outputs[index].xdev = xdev;
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static bool
|
||||
do_io_bindings(struct oxr_binding* b,
|
||||
struct oxr_action* act,
|
||||
struct xrt_device* xdev,
|
||||
struct oxr_source_input inputs[16],
|
||||
uint32_t* num_inputs,
|
||||
struct oxr_source_output outputs[16],
|
||||
uint32_t* num_outputs)
|
||||
{
|
||||
bool found = false;
|
||||
|
||||
if (act->action_type == XR_ACTION_TYPE_VIBRATION_OUTPUT) {
|
||||
found |= do_outputs(b, xdev, outputs, num_outputs);
|
||||
} else {
|
||||
found |= do_inputs(b, xdev, inputs, num_inputs);
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
static void
|
||||
get_binding(struct oxr_logger* log,
|
||||
struct oxr_sink_logger* slog,
|
||||
struct oxr_session* sess,
|
||||
struct oxr_action* act,
|
||||
struct oxr_interaction_profile* profile,
|
||||
enum oxr_sub_action_path sub_path,
|
||||
struct oxr_source_input inputs[16],
|
||||
uint32_t* num_inputs,
|
||||
struct oxr_source_output outputs[16],
|
||||
uint32_t* num_outputs)
|
||||
{
|
||||
struct xrt_device* xdev = NULL;
|
||||
struct oxr_binding* bindings[32];
|
||||
const char* profile_str;
|
||||
const char* user_path_str;
|
||||
size_t length;
|
||||
|
||||
//! @todo This probably falls on its head if the application doesn't use
|
||||
//! sub action paths.
|
||||
switch (sub_path) {
|
||||
case OXR_SUB_ACTION_PATH_USER: xdev = NULL; break;
|
||||
case OXR_SUB_ACTION_PATH_HEAD: xdev = sess->sys->head; break;
|
||||
case OXR_SUB_ACTION_PATH_LEFT: xdev = sess->sys->left; break;
|
||||
case OXR_SUB_ACTION_PATH_RIGHT: xdev = sess->sys->right; break;
|
||||
case OXR_SUB_ACTION_PATH_GAMEPAD: xdev = NULL; break;
|
||||
case OXR_SUB_ACTION_PATH_USER:
|
||||
user_path_str = "/user";
|
||||
xdev = NULL;
|
||||
break;
|
||||
case OXR_SUB_ACTION_PATH_HEAD:
|
||||
user_path_str = "/user/head";
|
||||
xdev = sess->sys->head;
|
||||
break;
|
||||
case OXR_SUB_ACTION_PATH_LEFT:
|
||||
user_path_str = "/user/hand/left";
|
||||
xdev = sess->sys->left;
|
||||
break;
|
||||
case OXR_SUB_ACTION_PATH_RIGHT:
|
||||
user_path_str = "/user/hand/right";
|
||||
xdev = sess->sys->right;
|
||||
break;
|
||||
case OXR_SUB_ACTION_PATH_GAMEPAD:
|
||||
user_path_str = "/user/hand/gamepad";
|
||||
xdev = NULL;
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
bool bound = false;
|
||||
if (strcmp(act->name, "grab_object") == 0) {
|
||||
bound = oxr_xdev_find_input(xdev, XRT_INPUT_PSMV_TRIGGER_VALUE,
|
||||
&input) ||
|
||||
oxr_xdev_find_input(xdev, XRT_INPUT_HYDRA_TRIGGER_VALUE,
|
||||
&input);
|
||||
} else if (strcmp(act->name, "hand_pose") == 0) {
|
||||
bound = oxr_xdev_find_input(
|
||||
xdev, XRT_INPUT_PSMV_BODY_CENTER_POSE, &input) ||
|
||||
oxr_xdev_find_input(xdev, XRT_INPUT_HYDRA_POSE, &input);
|
||||
} else if (strcmp(act->name, "quit_session") == 0) {
|
||||
bound =
|
||||
oxr_xdev_find_input(xdev, XRT_INPUT_PSMV_PS_CLICK, &input);
|
||||
} else if (strcmp(act->name, "vibrate_hand") == 0) {
|
||||
bound = oxr_xdev_find_output(
|
||||
xdev, XRT_OUTPUT_NAME_PSMV_RUMBLE_VIBRATION, &output);
|
||||
oxr_slog(slog, "\tFor: %s\n", user_path_str);
|
||||
|
||||
if (xdev == NULL) {
|
||||
oxr_slog(slog, "\t\tNo xdev!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (input != NULL) {
|
||||
uint32_t index = (*num_inputs)++;
|
||||
inputs[index].input = input;
|
||||
inputs[index].xdev = xdev;
|
||||
if (profile == NULL) {
|
||||
oxr_slog(slog, "\t\tNo profile!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (output != NULL) {
|
||||
uint32_t index = (*num_outputs)++;
|
||||
outputs[index].name = output->name;
|
||||
outputs[index].xdev = xdev;
|
||||
oxr_path_get_string(log, sess->sys->inst, profile->path, &profile_str,
|
||||
&length);
|
||||
|
||||
oxr_slog(slog, "\t\tProfile: %s\n", profile_str);
|
||||
|
||||
size_t num = 0;
|
||||
oxr_binding_find_bindings_from_key(log, profile, act->key, bindings,
|
||||
&num);
|
||||
if (num == 0) {
|
||||
oxr_slog(slog, "\t\tNo bindings\n");
|
||||
return;
|
||||
}
|
||||
|
||||
//! @todo preserve this value and return it.
|
||||
(void)bound;
|
||||
for (size_t i = 0; i < num; i++) {
|
||||
const char* str = NULL;
|
||||
struct oxr_binding* b = bindings[i];
|
||||
|
||||
// Just pick the first path.
|
||||
oxr_path_get_string(log, sess->sys->inst, b->paths[0], &str,
|
||||
&length);
|
||||
oxr_slog(slog, "\t\t\tBinding: %s\n", str);
|
||||
|
||||
if (b->sub_path != sub_path) {
|
||||
oxr_slog(slog, "\t\t\t\tRejected! (SUB PATH)\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
bool found = do_io_bindings(b, act, xdev, inputs, num_inputs,
|
||||
outputs, num_outputs);
|
||||
|
||||
if (found) {
|
||||
oxr_slog(slog, "\t\t\t\tBound!\n");
|
||||
} else {
|
||||
oxr_slog(slog, "\t\t\t\tRejected! (NO XDEV MAPPING)\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -369,8 +449,7 @@ oxr_source_set_create(struct oxr_logger* log,
|
|||
OXR_ALLOCATE_HANDLE_OR_RETURN(log, src_set, OXR_XR_DEBUG_SOURCESET,
|
||||
oxr_source_set_destroy_cb, &sess->handle);
|
||||
|
||||
src_set->generation = act_set->generation;
|
||||
|
||||
src_set->sess = sess;
|
||||
u_hashmap_int_insert(sess->act_sets, act_set->key, src_set);
|
||||
|
||||
*out_src_set = src_set;
|
||||
|
@ -408,42 +487,55 @@ oxr_source_destroy_cb(struct oxr_logger* log, struct oxr_handle_base* hb)
|
|||
|
||||
static XrResult
|
||||
oxr_source_create(struct oxr_logger* log,
|
||||
struct oxr_session* sess,
|
||||
struct oxr_source_set* src_set,
|
||||
struct oxr_action* act,
|
||||
struct oxr_source** out_src)
|
||||
struct oxr_interaction_profile* head,
|
||||
struct oxr_interaction_profile* left,
|
||||
struct oxr_interaction_profile* right,
|
||||
struct oxr_interaction_profile* gamepad)
|
||||
{
|
||||
struct oxr_session* sess = src_set->sess;
|
||||
struct oxr_source* src = NULL;
|
||||
struct oxr_sink_logger slog = {0};
|
||||
OXR_ALLOCATE_HANDLE_OR_RETURN(log, src, OXR_XR_DEBUG_SOURCE,
|
||||
oxr_source_destroy_cb, &sess->handle);
|
||||
oxr_source_destroy_cb, &src_set->handle);
|
||||
|
||||
u_hashmap_int_insert(sess->sources, act->key, src);
|
||||
u_hashmap_int_insert(src_set->sess->sources, act->key, src);
|
||||
|
||||
// Start logging into a single buffer.
|
||||
oxr_slog(&slog, ": Binding %s/%s\n", act->act_set->name, act->name);
|
||||
|
||||
if (act->sub_paths.user || act->sub_paths.any) {
|
||||
oxr_source_bind_inputs(log, sess, act, &src->user,
|
||||
#if 0
|
||||
oxr_source_bind_inputs(log, slog, sess, act, &src->user, user,
|
||||
OXR_SUB_ACTION_PATH_USER);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (act->sub_paths.head || act->sub_paths.any) {
|
||||
oxr_source_bind_inputs(log, sess, act, &src->head,
|
||||
oxr_source_bind_inputs(log, &slog, sess, act, &src->head, head,
|
||||
OXR_SUB_ACTION_PATH_HEAD);
|
||||
}
|
||||
|
||||
if (act->sub_paths.left || act->sub_paths.any) {
|
||||
oxr_source_bind_inputs(log, sess, act, &src->left,
|
||||
oxr_source_bind_inputs(log, &slog, sess, act, &src->left, left,
|
||||
OXR_SUB_ACTION_PATH_LEFT);
|
||||
}
|
||||
|
||||
if (act->sub_paths.right || act->sub_paths.any) {
|
||||
oxr_source_bind_inputs(log, sess, act, &src->right,
|
||||
OXR_SUB_ACTION_PATH_RIGHT);
|
||||
oxr_source_bind_inputs(log, &slog, sess, act, &src->right,
|
||||
right, OXR_SUB_ACTION_PATH_RIGHT);
|
||||
}
|
||||
|
||||
if (act->sub_paths.gamepad || act->sub_paths.any) {
|
||||
oxr_source_bind_inputs(log, sess, act, &src->gamepad,
|
||||
OXR_SUB_ACTION_PATH_GAMEPAD);
|
||||
oxr_source_bind_inputs(log, &slog, sess, act, &src->gamepad,
|
||||
gamepad, OXR_SUB_ACTION_PATH_GAMEPAD);
|
||||
}
|
||||
|
||||
*out_src = src;
|
||||
oxr_slog(&slog, "\tDone");
|
||||
|
||||
// Also frees all data.
|
||||
oxr_log_slog(log, &slog);
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
@ -520,10 +612,7 @@ oxr_source_update(struct oxr_logger* log,
|
|||
struct oxr_source* src = NULL;
|
||||
|
||||
oxr_session_get_source(sess, act->key, &src);
|
||||
if (src == NULL) {
|
||||
oxr_source_create(log, sess, act, &src);
|
||||
}
|
||||
|
||||
// This really shouldn't be happening.
|
||||
if (src == NULL) {
|
||||
return;
|
||||
}
|
||||
|
@ -543,18 +632,20 @@ oxr_source_update(struct oxr_logger* log,
|
|||
|
||||
static void
|
||||
oxr_source_bind_inputs(struct oxr_logger* log,
|
||||
struct oxr_sink_logger* slog,
|
||||
struct oxr_session* sess,
|
||||
struct oxr_action* act,
|
||||
struct oxr_source_cache* cache,
|
||||
enum sub_action_path sub_path)
|
||||
struct oxr_interaction_profile* profile,
|
||||
enum oxr_sub_action_path sub_path)
|
||||
{
|
||||
struct oxr_source_input inputs[16] = {0};
|
||||
uint32_t num_inputs = 0;
|
||||
struct oxr_source_output outputs[16] = {0};
|
||||
uint32_t num_outputs = 0;
|
||||
|
||||
MEGA_HACK_get_binding(log, sess, act, sub_path, inputs, &num_inputs,
|
||||
outputs, &num_outputs);
|
||||
get_binding(log, slog, sess, act, profile, sub_path, inputs,
|
||||
&num_inputs, outputs, &num_outputs);
|
||||
|
||||
cache->current.active = false;
|
||||
|
||||
|
@ -614,41 +705,53 @@ oxr_session_get_source(struct oxr_session* sess,
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Loop over all actions in a action set and destroy the sources linked to those
|
||||
* actions, this is so we can regenerate the bindings.
|
||||
*/
|
||||
static void
|
||||
oxr_session_destroy_all_sources(struct oxr_logger* log,
|
||||
struct oxr_session* sess,
|
||||
struct oxr_action_set* act_set)
|
||||
{
|
||||
for (uint32_t k = 0; k < XRT_MAX_HANDLE_CHILDREN; k++) {
|
||||
// This assumes that all children are actions.
|
||||
struct oxr_action* act =
|
||||
(struct oxr_action*)act_set->handle.children[k];
|
||||
|
||||
if (act == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
struct oxr_source* src = NULL;
|
||||
oxr_session_get_source(sess, act->key, &src);
|
||||
if (src == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
u_hashmap_int_erase(sess->sources, act->key);
|
||||
oxr_handle_destroy(log, &src->handle);
|
||||
}
|
||||
}
|
||||
|
||||
XrResult
|
||||
oxr_session_attach_action_sets(struct oxr_logger* log,
|
||||
struct oxr_session* sess,
|
||||
const XrSessionActionSetsAttachInfo* bindInfo)
|
||||
{
|
||||
//! @todo not implementeds
|
||||
struct oxr_instance* inst = sess->sys->inst;
|
||||
struct oxr_interaction_profile* head = NULL;
|
||||
struct oxr_interaction_profile* left = NULL;
|
||||
struct oxr_interaction_profile* right = NULL;
|
||||
struct oxr_action_set* act_set = NULL;
|
||||
struct oxr_source_set* src_set = NULL;
|
||||
struct oxr_action* act = NULL;
|
||||
|
||||
oxr_find_profile_for_device(log, inst, sess->sys->head, &head);
|
||||
oxr_find_profile_for_device(log, inst, sess->sys->left, &left);
|
||||
oxr_find_profile_for_device(log, inst, sess->sys->right, &right);
|
||||
|
||||
// Has any of the bound action sets been updated.
|
||||
for (uint32_t i = 0; i < bindInfo->countActionSets; i++) {
|
||||
act_set = (struct oxr_action_set*)bindInfo->actionSets[i];
|
||||
act_set->attached = true;
|
||||
|
||||
oxr_source_set_create(log, sess, act_set, &src_set);
|
||||
|
||||
for (uint32_t k = 0; k < XRT_MAX_HANDLE_CHILDREN; k++) {
|
||||
act = (struct oxr_action*)act_set->handle.children[k];
|
||||
if (act == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
oxr_source_create(log, src_set, act, head, left, right,
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
|
||||
if (head != NULL) {
|
||||
sess->head = head->path;
|
||||
}
|
||||
if (left != NULL) {
|
||||
sess->left = left->path;
|
||||
}
|
||||
if (right != NULL) {
|
||||
sess->right = right->path;
|
||||
}
|
||||
|
||||
sess->actionsAttached = true;
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -661,6 +764,18 @@ oxr_action_sync_data(struct oxr_logger* log,
|
|||
struct oxr_action_set* act_set = NULL;
|
||||
struct oxr_source_set* src_set = NULL;
|
||||
|
||||
// Check that all action sets has been attached.
|
||||
for (uint32_t i = 0; i < countActionSets; i++) {
|
||||
oxr_session_get_source_set(sess, actionSets[i].actionSet,
|
||||
&src_set, &act_set);
|
||||
if (src_set == NULL) {
|
||||
return oxr_error(
|
||||
log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
||||
"(actionSets[%i].actionSet) has not been attached",
|
||||
i);
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronize outputs to this time.
|
||||
int64_t now = time_state_get_now(sess->sys->inst->timekeeping);
|
||||
|
||||
|
@ -670,31 +785,6 @@ oxr_action_sync_data(struct oxr_logger* log,
|
|||
sess->sys->inst->timekeeping);
|
||||
}
|
||||
|
||||
//! @todo These semantics below are all wrong!
|
||||
|
||||
// Has any of the bound action sets been updated.
|
||||
for (uint32_t i = 0; i < countActionSets; i++) {
|
||||
oxr_session_get_source_set(sess, actionSets[i].actionSet,
|
||||
&src_set, &act_set);
|
||||
|
||||
// No source set found, create it. This will set it to the
|
||||
// current action set generation, that's okay since we will
|
||||
// be creating the sources for the actions below.
|
||||
if (src_set == NULL) {
|
||||
oxr_source_set_create(log, sess, act_set, &src_set);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Generations match, nothing to do.
|
||||
if (src_set->generation == act_set->generation) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found possible out of date bindings, we need to redo these
|
||||
// bindings. Destroy the actions currently on this action set.
|
||||
oxr_session_destroy_all_sources(log, sess, act_set);
|
||||
}
|
||||
|
||||
// Go over all action sets and update them.
|
||||
for (uint32_t i = 0; i < countActionSets; i++) {
|
||||
struct oxr_sub_paths sub_paths;
|
||||
|
@ -723,66 +813,6 @@ oxr_action_sync_data(struct oxr_logger* log,
|
|||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
XrResult
|
||||
oxr_action_suggest_interaction_profile_bindings(
|
||||
struct oxr_logger* log,
|
||||
struct oxr_instance* inst,
|
||||
const XrInteractionProfileSuggestedBinding* suggestedBindings)
|
||||
{
|
||||
//! @todo Implement
|
||||
const char* str;
|
||||
size_t length;
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "%s\n", __func__);
|
||||
|
||||
oxr_path_get_string(log, inst, suggestedBindings->interactionProfile,
|
||||
&str, &length);
|
||||
fprintf(stderr, "\tinteractionProfile: %s\n", str);
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < suggestedBindings->countSuggestedBindings; i++) {
|
||||
const XrActionSuggestedBinding* s =
|
||||
&suggestedBindings->suggestedBindings[i];
|
||||
struct oxr_action* act = (struct oxr_action*)s->action;
|
||||
#if 0
|
||||
oxr_path_get_string(log, inst, s->binding, &str, &length);
|
||||
fprintf(stderr, "\t\t%s -> %s\n", act->name, str);
|
||||
#else
|
||||
(void)inst;
|
||||
(void)act;
|
||||
(void)str;
|
||||
(void)length;
|
||||
#endif
|
||||
}
|
||||
|
||||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
XrResult
|
||||
oxr_action_get_current_interaction_profile(
|
||||
struct oxr_logger* log,
|
||||
struct oxr_session* sess,
|
||||
XrPath topLevelUserPath,
|
||||
XrInteractionProfileState* interactionProfile)
|
||||
{
|
||||
//! @todo Implement
|
||||
return oxr_error(log, XR_ERROR_HANDLE_INVALID, " not implemented");
|
||||
}
|
||||
|
||||
XrResult
|
||||
oxr_action_get_input_source_localized_name(
|
||||
struct oxr_logger* log,
|
||||
struct oxr_session* sess,
|
||||
const XrInputSourceLocalizedNameGetInfo* getInfo,
|
||||
uint32_t bufferCapacityInput,
|
||||
uint32_t* bufferCountOutput,
|
||||
char* buffer)
|
||||
{
|
||||
//! @todo Implement
|
||||
return oxr_error(log, XR_ERROR_HANDLE_INVALID, " not implemented");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -995,18 +1025,6 @@ oxr_action_get_pose(struct oxr_logger* log,
|
|||
return XR_SUCCESS;
|
||||
}
|
||||
|
||||
XrResult
|
||||
oxr_action_get_bound_sources(struct oxr_logger* log,
|
||||
struct oxr_session* sess,
|
||||
uint64_t key,
|
||||
uint32_t sourceCapacityInput,
|
||||
uint32_t* sourceCountOutput,
|
||||
XrPath* sources)
|
||||
{
|
||||
//! @todo Implement
|
||||
return oxr_error(log, XR_ERROR_HANDLE_INVALID, " not implemented");
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
|
|
|
@ -43,6 +43,7 @@ oxr_instance_destroy(struct oxr_logger *log, struct oxr_handle_base *hb)
|
|||
|
||||
u_var_remove_root((void *)inst);
|
||||
|
||||
oxr_binding_destroy_all(log, inst);
|
||||
oxr_path_destroy_all(log, inst);
|
||||
|
||||
if (inst->path_store != NULL) {
|
||||
|
@ -94,11 +95,22 @@ oxr_instance_create(struct oxr_logger *log,
|
|||
}
|
||||
|
||||
// Cache certain often looked up paths.
|
||||
// clang-format off
|
||||
cache_path(log, inst, "/user", &inst->path_cache.user);
|
||||
cache_path(log, inst, "/user/hand/head", &inst->path_cache.head);
|
||||
cache_path(log, inst, "/user/hand/left", &inst->path_cache.left);
|
||||
cache_path(log, inst, "/user/hand/right", &inst->path_cache.right);
|
||||
cache_path(log, inst, "/user/hand/gamepad", &inst->path_cache.gamepad);
|
||||
cache_path(log, inst, "/interaction_profiles/khr/simple_controller", &inst->path_cache.khr_simple_controller);
|
||||
cache_path(log, inst, "/interaction_profiles/google/daydream_controller", &inst->path_cache.google_daydream_controller);
|
||||
cache_path(log, inst, "/interaction_profiles/htc/vive_controller", &inst->path_cache.htc_vive_controller);
|
||||
cache_path(log, inst, "/interaction_profiles/htc/vive_pro", &inst->path_cache.htc_vive_pro);
|
||||
cache_path(log, inst, "/interaction_profiles/microsoft/motion_controller", &inst->path_cache.microsoft_motion_controller);
|
||||
cache_path(log, inst, "/interaction_profiles/microsoft/xbox_controller", &inst->path_cache.microsoft_xbox_controller);
|
||||
cache_path(log, inst, "/interaction_profiles/oculus/go_controller", &inst->path_cache.oculus_go_controller);
|
||||
cache_path(log, inst, "/interaction_profiles/oculus/touch_controller", &inst->path_cache.oculus_touch_controller);
|
||||
cache_path(log, inst, "/interaction_profiles/valve/index_controller", &inst->path_cache.valve_index_controller);
|
||||
// clang-format on
|
||||
|
||||
p_ret = xrt_prober_create(&inst->prober);
|
||||
if (p_ret != 0) {
|
||||
|
|
|
@ -79,6 +79,8 @@ struct oxr_source;
|
|||
struct oxr_source_set;
|
||||
struct oxr_source_input;
|
||||
struct oxr_source_output;
|
||||
struct oxr_binding;
|
||||
struct oxr_interaction_profile;
|
||||
|
||||
#define XRT_MAX_HANDLE_CHILDREN 256
|
||||
|
||||
|
@ -103,6 +105,18 @@ enum oxr_handle_state
|
|||
OXR_HANDLE_STATE_DESTROYED,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Sub action paths.
|
||||
*/
|
||||
enum oxr_sub_action_path
|
||||
{
|
||||
OXR_SUB_ACTION_PATH_USER,
|
||||
OXR_SUB_ACTION_PATH_HEAD,
|
||||
OXR_SUB_ACTION_PATH_LEFT,
|
||||
OXR_SUB_ACTION_PATH_RIGHT,
|
||||
OXR_SUB_ACTION_PATH_GAMEPAD,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
|
@ -284,28 +298,6 @@ oxr_action_sync_data(struct oxr_logger *log,
|
|||
uint32_t countActionSets,
|
||||
const XrActiveActionSet *actionSets);
|
||||
|
||||
XrResult
|
||||
oxr_action_suggest_interaction_profile_bindings(
|
||||
struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
const XrInteractionProfileSuggestedBinding *suggestedBindings);
|
||||
|
||||
XrResult
|
||||
oxr_action_get_current_interaction_profile(
|
||||
struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
XrPath topLevelUserPath,
|
||||
XrInteractionProfileState *interactionProfile);
|
||||
|
||||
XrResult
|
||||
oxr_action_get_input_source_localized_name(
|
||||
struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
const XrInputSourceLocalizedNameGetInfo *getInfo,
|
||||
uint32_t bufferCapacityInput,
|
||||
uint32_t *bufferCountOutput,
|
||||
char *buffer);
|
||||
|
||||
XrResult
|
||||
oxr_action_get_boolean(struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
|
@ -335,14 +327,6 @@ oxr_action_get_pose(struct oxr_logger *log,
|
|||
struct oxr_sub_paths sub_paths,
|
||||
XrActionStatePose *data);
|
||||
|
||||
XrResult
|
||||
oxr_action_get_bound_sources(struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
uint64_t key,
|
||||
uint32_t sourceCapacityInput,
|
||||
uint32_t *sourceCountOutput,
|
||||
XrPath *sources);
|
||||
|
||||
XrResult
|
||||
oxr_action_apply_haptic_feedback(struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
|
@ -357,6 +341,70 @@ oxr_action_stop_haptic_feedback(struct oxr_logger *log,
|
|||
struct oxr_sub_paths sub_paths);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* oxr_binding.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Find the best matching profile for the given @ref xrt_device.
|
||||
*
|
||||
* @param xdev Can be null.
|
||||
*/
|
||||
void
|
||||
oxr_find_profile_for_device(struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
struct xrt_device *xdev,
|
||||
struct oxr_interaction_profile **out_p);
|
||||
|
||||
/*!
|
||||
* Free all memory allocated by the binding system.
|
||||
*/
|
||||
void
|
||||
oxr_binding_destroy_all(struct oxr_logger *log, struct oxr_instance *inst);
|
||||
|
||||
/*!
|
||||
* Find all bindings that is the given action key is bound to.
|
||||
*/
|
||||
void
|
||||
oxr_binding_find_bindings_from_key(struct oxr_logger *log,
|
||||
struct oxr_interaction_profile *profile,
|
||||
uint32_t key,
|
||||
struct oxr_binding *bindings[32],
|
||||
size_t *num_bindings);
|
||||
|
||||
XrResult
|
||||
oxr_action_suggest_interaction_profile_bindings(
|
||||
struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
const XrInteractionProfileSuggestedBinding *suggestedBindings);
|
||||
|
||||
XrResult
|
||||
oxr_action_get_current_interaction_profile(
|
||||
struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
XrPath topLevelUserPath,
|
||||
XrInteractionProfileState *interactionProfile);
|
||||
|
||||
XrResult
|
||||
oxr_action_get_input_source_localized_name(
|
||||
struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
const XrInputSourceLocalizedNameGetInfo *getInfo,
|
||||
uint32_t bufferCapacityInput,
|
||||
uint32_t *bufferCountOutput,
|
||||
char *buffer);
|
||||
|
||||
XrResult
|
||||
oxr_action_enumerate_bound_sources(struct oxr_logger *log,
|
||||
struct oxr_session *sess,
|
||||
uint64_t key,
|
||||
uint32_t sourceCapacityInput,
|
||||
uint32_t *sourceCountOutput,
|
||||
XrPath *sources);
|
||||
|
||||
|
||||
/*
|
||||
*
|
||||
* oxr_session.c
|
||||
|
@ -825,6 +873,9 @@ struct oxr_instance
|
|||
struct oxr_event *last_event;
|
||||
struct oxr_event *next_event;
|
||||
|
||||
struct oxr_interaction_profile **profiles;
|
||||
size_t num_profiles;
|
||||
|
||||
|
||||
struct
|
||||
{
|
||||
|
@ -833,6 +884,16 @@ struct oxr_instance
|
|||
XrPath left;
|
||||
XrPath right;
|
||||
XrPath gamepad;
|
||||
|
||||
XrPath khr_simple_controller;
|
||||
XrPath google_daydream_controller;
|
||||
XrPath htc_vive_controller;
|
||||
XrPath htc_vive_pro;
|
||||
XrPath microsoft_motion_controller;
|
||||
XrPath microsoft_xbox_controller;
|
||||
XrPath oculus_go_controller;
|
||||
XrPath oculus_touch_controller;
|
||||
XrPath valve_index_controller;
|
||||
} path_cache;
|
||||
|
||||
//! Debug messengers
|
||||
|
@ -857,6 +918,21 @@ struct oxr_session
|
|||
struct u_hashmap_int *act_sets;
|
||||
struct u_hashmap_int *sources;
|
||||
|
||||
//! Has xrAttachSessionActionSets been called?
|
||||
bool actionsAttached;
|
||||
|
||||
/*!
|
||||
* Currently bound interaction profile.
|
||||
* @{
|
||||
*/
|
||||
XrPath left;
|
||||
XrPath right;
|
||||
XrPath head;
|
||||
XrPath gamepad;
|
||||
/*!
|
||||
* @}
|
||||
*/
|
||||
|
||||
/*!
|
||||
* IPD, to be expanded to a proper 3D relation.
|
||||
*/
|
||||
|
@ -873,6 +949,36 @@ struct oxr_session
|
|||
struct oxr_swapchain **);
|
||||
};
|
||||
|
||||
/*!
|
||||
* A single interaction profile.
|
||||
*/
|
||||
struct oxr_interaction_profile
|
||||
{
|
||||
XrPath path;
|
||||
struct oxr_binding *bindings;
|
||||
size_t num_bindings;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Interaction profile binding state.
|
||||
*/
|
||||
struct oxr_binding
|
||||
{
|
||||
XrPath *paths;
|
||||
size_t num_paths;
|
||||
|
||||
enum oxr_sub_action_path sub_path;
|
||||
|
||||
uint32_t *keys;
|
||||
size_t num_keys;
|
||||
|
||||
enum xrt_input_name *inputs;
|
||||
size_t num_inputs;
|
||||
|
||||
enum xrt_output_name *outputs;
|
||||
size_t num_outputs;
|
||||
};
|
||||
|
||||
/*!
|
||||
* To carry around a sementic selection of sub action paths.
|
||||
*/
|
||||
|
@ -896,8 +1002,8 @@ struct oxr_source_set
|
|||
//! Common structure for things referred to by OpenXR handles.
|
||||
struct oxr_handle_base handle;
|
||||
|
||||
//! Which generation of the XrActionSet was this created from.
|
||||
uint32_t generation;
|
||||
//! Owning session.
|
||||
struct oxr_session *sess;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
@ -1072,11 +1178,11 @@ struct oxr_action_set
|
|||
//! Onwer of this messenger.
|
||||
struct oxr_instance *inst;
|
||||
|
||||
/*!
|
||||
* Every change that is done to a action set will increment this
|
||||
* counter and trigger a rebinding of inputs when syncing actions.
|
||||
*/
|
||||
uint32_t generation;
|
||||
//! Application supplied name of this action.
|
||||
char name[XR_MAX_ACTION_SET_NAME_SIZE];
|
||||
|
||||
//! Has this action set been attached.
|
||||
bool attached;
|
||||
|
||||
//! Unique key for the session hashmap.
|
||||
uint32_t key;
|
||||
|
|
Loading…
Reference in a new issue