mirror of
https://gitlab.freedesktop.org/monado/monado.git
synced 2024-12-28 02:26:16 +00:00
st/oxr: Implement dpad emulation
This commit is contained in:
parent
803d679e11
commit
aa31ac3789
|
@ -84,11 +84,16 @@ process_dpad(struct oxr_logger *log,
|
|||
for (size_t i = 0; i < ARRAY_SIZE(entry->dpads); i++) {
|
||||
// Have we found a empty slot, add it.
|
||||
if (entry->dpads[i].binding == XR_NULL_PATH) {
|
||||
entry->dpads[i] = *dpad;
|
||||
|
||||
// Don't leave potentially dangling pointers.
|
||||
entry->dpads[i].next = NULL;
|
||||
entry->dpads[i].actionSet = XR_NULL_HANDLE;
|
||||
struct oxr_dpad_binding_modification dpad_binding = {
|
||||
.binding = dpad->binding,
|
||||
.settings = {
|
||||
.forceThreshold = dpad->forceThreshold,
|
||||
.forceThresholdReleased = dpad->forceThresholdReleased,
|
||||
.centerRegion = dpad->centerRegion,
|
||||
.wedgeAngle = dpad->wedgeAngle,
|
||||
.isSticky = dpad->isSticky,
|
||||
}};
|
||||
entry->dpads[i] = dpad_binding;
|
||||
|
||||
entry->dpad_count++;
|
||||
added = true;
|
||||
|
|
|
@ -63,7 +63,7 @@ oxr_dpad_state_get_or_add(struct oxr_dpad_state *state, uint64_t key)
|
|||
void
|
||||
oxr_dpad_state_deinit(struct oxr_dpad_state *state)
|
||||
{
|
||||
if (state->uhi != NULL) {
|
||||
if (state != NULL && state->uhi != NULL) {
|
||||
u_hashmap_int_clear_and_call_for_each(state->uhi, destroy_callback, NULL);
|
||||
u_hashmap_int_destroy(&state->uhi);
|
||||
}
|
||||
|
|
|
@ -1258,6 +1258,115 @@ oxr_action_populate_input_transform(struct oxr_logger *log,
|
|||
return oxr_input_transform_create_chain(log, slog, t, act->data->action_type, act->data->name, str,
|
||||
&action_input->transforms, &action_input->transform_count);
|
||||
}
|
||||
/*!
|
||||
* Find dpad settings in @p dpad_entry whose binding path
|
||||
* is a prefix of @p bound_path_string.
|
||||
*
|
||||
* @returns true if settings were found and written to @p out_dpad_settings
|
||||
*/
|
||||
static bool
|
||||
find_matching_dpad(struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
struct oxr_dpad_entry *dpad_entry,
|
||||
const char *bound_path_string,
|
||||
struct oxr_dpad_binding_modification **out_dpad_binding)
|
||||
{
|
||||
if (dpad_entry != NULL) {
|
||||
for (uint32_t i = 0; i < dpad_entry->dpad_count; i++) {
|
||||
const char *dpad_path_string;
|
||||
size_t dpad_path_length;
|
||||
oxr_path_get_string(log, inst, dpad_entry->dpads[i].binding, &dpad_path_string,
|
||||
&dpad_path_length);
|
||||
if (strncmp(bound_path_string, dpad_path_string, dpad_path_length) == 0) {
|
||||
*out_dpad_binding = &dpad_entry->dpads[i];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Try to produce a transform chain to create a dpad button from the selected input
|
||||
* (potentially using other inputs like `/force` in the process)
|
||||
*
|
||||
* Populates @p action_input->transforms and @p action_input->transform_count on
|
||||
* success.
|
||||
*
|
||||
* @returns false if it could not, true if it could
|
||||
*/
|
||||
static bool
|
||||
oxr_action_populate_input_transform_dpad(struct oxr_logger *log,
|
||||
struct oxr_sink_logger *slog,
|
||||
struct oxr_session *sess,
|
||||
struct oxr_action *act,
|
||||
struct oxr_dpad_entry *dpad_entry,
|
||||
enum oxr_dpad_region dpad_region,
|
||||
struct oxr_interaction_profile *profile,
|
||||
struct oxr_action_input *action_inputs,
|
||||
uint32_t action_input_count,
|
||||
uint32_t selected_input)
|
||||
{
|
||||
struct oxr_action_input *action_input = &(action_inputs[selected_input]);
|
||||
assert(action_input->transforms == NULL);
|
||||
assert(action_input->transform_count == 0);
|
||||
|
||||
const char *bound_path_string;
|
||||
size_t bound_path_length;
|
||||
oxr_path_get_string(log, sess->sys->inst, action_input->bound_path, &bound_path_string, &bound_path_length);
|
||||
|
||||
// find correct dpad entry
|
||||
struct oxr_dpad_binding_modification *dpad_binding_modification = NULL;
|
||||
find_matching_dpad(log, sess->sys->inst, dpad_entry, bound_path_string, &dpad_binding_modification);
|
||||
|
||||
enum xrt_input_type t = XRT_GET_INPUT_TYPE(action_input->input->name);
|
||||
enum xrt_input_type activate_t = XRT_GET_INPUT_TYPE(action_input->dpad_activate_name);
|
||||
|
||||
return oxr_input_transform_create_chain_dpad(
|
||||
log, slog, t, act->data->action_type, bound_path_string, dpad_binding_modification, dpad_region, activate_t,
|
||||
action_input->dpad_activate, &action_input->transforms, &action_input->transform_count);
|
||||
}
|
||||
|
||||
// based on get_subaction_path_from_path
|
||||
static bool
|
||||
get_dpad_region_from_path(struct oxr_logger *log,
|
||||
struct oxr_instance *inst,
|
||||
XrPath path,
|
||||
enum oxr_dpad_region *out_dpad_region)
|
||||
{
|
||||
const char *str = NULL;
|
||||
size_t length = 0;
|
||||
XrResult ret;
|
||||
|
||||
ret = oxr_path_get_string(log, inst, path, &str, &length);
|
||||
if (ret != XR_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: surely there's a better way to do this?
|
||||
if (length >= 10 && strncmp("/dpad_left", str + (length - 10), 10) == 0) {
|
||||
*out_dpad_region = OXR_DPAD_REGION_LEFT;
|
||||
return true;
|
||||
}
|
||||
if (length >= 11 && strncmp("/dpad_right", str + (length - 11), 11) == 0) {
|
||||
*out_dpad_region = OXR_DPAD_REGION_RIGHT;
|
||||
return true;
|
||||
}
|
||||
if (length >= 8 && strncmp("/dpad_up", str + (length - 8), 8) == 0) {
|
||||
*out_dpad_region = OXR_DPAD_REGION_UP;
|
||||
return true;
|
||||
}
|
||||
if (length >= 10 && strncmp("/dpad_down", str + (length - 10), 10) == 0) {
|
||||
*out_dpad_region = OXR_DPAD_REGION_DOWN;
|
||||
return true;
|
||||
}
|
||||
if (length >= 12 && strncmp("/dpad_center", str + (length - 12), 12) == 0) {
|
||||
*out_dpad_region = OXR_DPAD_REGION_CENTER;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
oxr_action_bind_io(struct oxr_logger *log,
|
||||
|
@ -1282,9 +1391,18 @@ oxr_action_bind_io(struct oxr_logger *log,
|
|||
cache->current.active = true;
|
||||
cache->inputs = U_TYPED_ARRAY_CALLOC(struct oxr_action_input, input_count);
|
||||
for (uint32_t i = 0; i < input_count; i++) {
|
||||
|
||||
// Only add the input if we can find a transform.
|
||||
if (oxr_action_populate_input_transform(log, slog, sess, act, &(inputs[i]))) {
|
||||
|
||||
enum oxr_dpad_region dpad_region;
|
||||
if (get_dpad_region_from_path(log, sess->sys->inst, inputs[i].bound_path, &dpad_region)) {
|
||||
struct oxr_dpad_entry *entry =
|
||||
oxr_dpad_state_get(&profile->dpad_state, act->act_set->act_set_key);
|
||||
if (oxr_action_populate_input_transform_dpad(log, slog, sess, act, entry, dpad_region,
|
||||
profile, inputs, input_count, i)) {
|
||||
cache->inputs[count++] = inputs[i];
|
||||
continue;
|
||||
}
|
||||
} else if (oxr_action_populate_input_transform(log, slog, sess, act, &(inputs[i]))) {
|
||||
cache->inputs[count++] = inputs[i];
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
* @ingroup oxr_input_transform
|
||||
*/
|
||||
|
||||
#include "math/m_mathinclude.h"
|
||||
|
||||
#include "oxr_input_transform.h"
|
||||
#include "oxr_logger.h"
|
||||
#include "oxr_objects.h"
|
||||
|
@ -105,6 +107,30 @@ oxr_input_transform_init_vec2_get_y(struct oxr_input_transform *transform, const
|
|||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
oxr_input_transform_init_vec2_dpad(struct oxr_input_transform *transform,
|
||||
const struct oxr_input_transform *parent,
|
||||
struct oxr_dpad_settings dpad_settings,
|
||||
enum oxr_dpad_region dpad_region,
|
||||
enum xrt_input_type activation_input_type,
|
||||
struct xrt_input *activation_input)
|
||||
{
|
||||
assert(transform != NULL);
|
||||
assert(parent != NULL);
|
||||
assert(parent->result_type == XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE);
|
||||
|
||||
U_ZERO(transform);
|
||||
transform->type = INPUT_TRANSFORM_DPAD;
|
||||
transform->result_type = XRT_INPUT_TYPE_BOOLEAN;
|
||||
transform->data.dpad_state.settings = dpad_settings;
|
||||
transform->data.dpad_state.bound_region = dpad_region;
|
||||
transform->data.dpad_state.activation_input_type = activation_input_type;
|
||||
transform->data.dpad_state.activation_input = activation_input;
|
||||
transform->data.dpad_state.already_active = activation_input == NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
oxr_input_transform_init_threshold(struct oxr_input_transform *transform,
|
||||
const struct oxr_input_transform *parent,
|
||||
|
@ -148,7 +174,7 @@ oxr_input_transform_init_bool_to_vec1(struct oxr_input_transform *transform,
|
|||
}
|
||||
|
||||
bool
|
||||
oxr_input_transform_process(const struct oxr_input_transform *transform,
|
||||
oxr_input_transform_process(struct oxr_input_transform *transform,
|
||||
size_t transform_count,
|
||||
const struct oxr_input_value_tagged *input,
|
||||
struct oxr_input_value_tagged *out)
|
||||
|
@ -158,7 +184,7 @@ oxr_input_transform_process(const struct oxr_input_transform *transform,
|
|||
}
|
||||
struct oxr_input_value_tagged data = *input;
|
||||
for (size_t i = 0; i < transform_count; ++i) {
|
||||
const struct oxr_input_transform *xform = &(transform[i]);
|
||||
struct oxr_input_transform *xform = &(transform[i]);
|
||||
switch (xform->type) {
|
||||
case INPUT_TRANSFORM_IDENTITY:
|
||||
// do nothing
|
||||
|
@ -178,6 +204,75 @@ oxr_input_transform_process(const struct oxr_input_transform *transform,
|
|||
data.value.boolean ? xform->data.bool_to_vec1.true_val : xform->data.bool_to_vec1.false_val;
|
||||
break;
|
||||
}
|
||||
case INPUT_TRANSFORM_DPAD: {
|
||||
struct oxr_input_transform_dpad_data *dpad_state = &xform->data.dpad_state;
|
||||
|
||||
if (dpad_state->activation_input != NULL) {
|
||||
bool active = true;
|
||||
|
||||
switch (dpad_state->activation_input_type) {
|
||||
case XRT_INPUT_TYPE_BOOLEAN: {
|
||||
active = dpad_state->activation_input->value.boolean;
|
||||
break;
|
||||
}
|
||||
case XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE: {
|
||||
float force = dpad_state->activation_input->value.vec1.x;
|
||||
active = (force >= dpad_state->settings.forceThreshold) ||
|
||||
(dpad_state->already_active &&
|
||||
force >= dpad_state->settings.forceThresholdReleased);
|
||||
break;
|
||||
}
|
||||
default: active = false;
|
||||
}
|
||||
|
||||
dpad_state->already_active = active;
|
||||
if (!active) {
|
||||
dpad_state->active_regions = OXR_DPAD_REGION_CENTER;
|
||||
data.value.boolean = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
enum oxr_dpad_region bound_region = dpad_state->bound_region;
|
||||
enum oxr_dpad_region active_regions = OXR_DPAD_REGION_CENTER;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
enum oxr_dpad_region query_region = 1 << i;
|
||||
|
||||
bool rot90 =
|
||||
(query_region == OXR_DPAD_REGION_LEFT) || (query_region == OXR_DPAD_REGION_RIGHT);
|
||||
bool rot180 =
|
||||
(query_region == OXR_DPAD_REGION_DOWN) || (query_region == OXR_DPAD_REGION_RIGHT);
|
||||
|
||||
float localX = rot90 ? data.value.vec2.y : data.value.vec2.x;
|
||||
float localY = rot90 ? -data.value.vec2.x : data.value.vec2.y;
|
||||
if (rot180) {
|
||||
localX = -localX;
|
||||
localY = -localY;
|
||||
}
|
||||
|
||||
float centerRadius = dpad_state->settings.centerRegion;
|
||||
if (localX * localX + localY * localY <= centerRadius * centerRadius) {
|
||||
continue;
|
||||
}
|
||||
|
||||
float tanXY = atan2f(localX, localY);
|
||||
float halfAngle = dpad_state->settings.wedgeAngle / 2.0f;
|
||||
if (-halfAngle < tanXY && tanXY <= halfAngle) {
|
||||
active_regions |= query_region;
|
||||
}
|
||||
}
|
||||
|
||||
if (!dpad_state->already_active || !dpad_state->settings.isSticky ||
|
||||
(dpad_state->active_regions == OXR_DPAD_REGION_CENTER) ||
|
||||
(active_regions == OXR_DPAD_REGION_CENTER)) {
|
||||
dpad_state->active_regions = active_regions;
|
||||
}
|
||||
|
||||
data.value.boolean = (dpad_state->active_regions == bound_region) ||
|
||||
((dpad_state->active_regions & bound_region) != 0);
|
||||
break;
|
||||
}
|
||||
case INPUT_TRANSFORM_INVALID:
|
||||
default: return false;
|
||||
}
|
||||
|
@ -346,3 +441,72 @@ oxr_input_transform_create_chain(struct oxr_logger *log,
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
oxr_input_transform_create_chain_dpad(struct oxr_logger *log,
|
||||
struct oxr_sink_logger *slog,
|
||||
enum xrt_input_type input_type,
|
||||
XrActionType result_type,
|
||||
const char *bound_path_string,
|
||||
struct oxr_dpad_binding_modification *dpad_binding_modification,
|
||||
enum oxr_dpad_region dpad_region,
|
||||
enum xrt_input_type activation_input_type,
|
||||
struct xrt_input *activation_input,
|
||||
struct oxr_input_transform **out_transforms,
|
||||
size_t *out_transform_count)
|
||||
{
|
||||
struct oxr_input_transform chain[OXR_MAX_INPUT_TRANSFORMS] = {0};
|
||||
|
||||
// these default settings are specified by OpenXR and thus must not be changed
|
||||
struct oxr_dpad_settings dpad_settings = {
|
||||
.forceThreshold = 0.5f,
|
||||
.forceThresholdReleased = 0.4f,
|
||||
.centerRegion = 0.5f,
|
||||
.wedgeAngle = M_PI_2,
|
||||
.isSticky = false,
|
||||
};
|
||||
|
||||
if (dpad_binding_modification != NULL) {
|
||||
dpad_settings = dpad_binding_modification->settings;
|
||||
}
|
||||
|
||||
oxr_slog(slog, "\t\tAdding dpad transform from '%s' to '%s'\n", xr_action_type_to_str(result_type),
|
||||
xrt_input_type_to_str(input_type));
|
||||
|
||||
struct oxr_input_transform *current_xform = &(chain[0]);
|
||||
if (!oxr_input_transform_init_root(current_xform, input_type)) {
|
||||
*out_transform_count = 0;
|
||||
*out_transforms = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
// We start over here.
|
||||
size_t transform_count = 0;
|
||||
input_type = current_xform->result_type;
|
||||
if (input_type != XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE) {
|
||||
oxr_slog(slog, "\t\t\tUnexpected input type for dpad binding %s\n", bound_path_string);
|
||||
return false;
|
||||
}
|
||||
if (result_type != XR_ACTION_TYPE_BOOLEAN_INPUT) {
|
||||
oxr_slog(slog, "\t\t\tUnexpected output type for dpad binding %s\n", bound_path_string);
|
||||
return false;
|
||||
}
|
||||
|
||||
struct oxr_input_transform *new_xform = &(chain[transform_count]);
|
||||
if (!oxr_input_transform_init_vec2_dpad(new_xform, current_xform, dpad_settings, dpad_region,
|
||||
activation_input_type, activation_input)) {
|
||||
// Error has already been logged.
|
||||
|
||||
*out_transform_count = 0;
|
||||
*out_transforms = NULL;
|
||||
return false;
|
||||
}
|
||||
|
||||
current_xform = new_xform;
|
||||
transform_count++;
|
||||
|
||||
*out_transform_count = transform_count;
|
||||
*out_transforms = oxr_input_transform_clone_chain(chain, transform_count);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "xrt/xrt_device.h"
|
||||
#include "oxr_objects.h"
|
||||
|
||||
// we need no platform-specific defines from OpenXR.
|
||||
#include "openxr/openxr.h"
|
||||
|
@ -80,6 +81,15 @@ enum oxr_input_transform_type
|
|||
* @see oxr_input_transform_bool_to_vec1_data
|
||||
*/
|
||||
INPUT_TRANSFORM_BOOL_TO_VEC1,
|
||||
|
||||
/*!
|
||||
* Interpret a 2D joystick or trackpad as a dpad.
|
||||
*
|
||||
* This transform type has data:
|
||||
*
|
||||
* @see oxr_input_transform_dpad_data
|
||||
*/
|
||||
INPUT_TRANSFORM_DPAD,
|
||||
};
|
||||
|
||||
struct oxr_input_transform;
|
||||
|
@ -110,6 +120,21 @@ struct oxr_input_transform_bool_to_vec1_data
|
|||
float false_val;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Data required for INPUT_TRANSFORM_DPAD
|
||||
* @see oxr_input_transform
|
||||
* @see INPUT_TRANSFORM_DPAD
|
||||
*/
|
||||
struct oxr_input_transform_dpad_data
|
||||
{
|
||||
enum oxr_dpad_region bound_region;
|
||||
enum oxr_dpad_region active_regions;
|
||||
struct oxr_dpad_settings settings;
|
||||
enum xrt_input_type activation_input_type;
|
||||
struct xrt_input *activation_input;
|
||||
bool already_active;
|
||||
};
|
||||
|
||||
/*!
|
||||
* Variant type for input transforms.
|
||||
*
|
||||
|
@ -139,6 +164,11 @@ struct oxr_input_transform
|
|||
* INPUT_TRANSFORM_BOOL_TO_VEC1
|
||||
*/
|
||||
struct oxr_input_transform_bool_to_vec1_data bool_to_vec1;
|
||||
/*!
|
||||
* Populated when oxr_input_transform::type is
|
||||
* INPUT_TRANSFORM_DPAD
|
||||
*/
|
||||
struct oxr_input_transform_dpad_data dpad_state;
|
||||
} data;
|
||||
};
|
||||
|
||||
|
@ -173,7 +203,7 @@ oxr_input_transform_destroy(struct oxr_input_transform **transform_ptr);
|
|||
* @public @memberof oxr_input_transform
|
||||
*/
|
||||
bool
|
||||
oxr_input_transform_process(const struct oxr_input_transform *transforms,
|
||||
oxr_input_transform_process(struct oxr_input_transform *transforms,
|
||||
size_t transform_count,
|
||||
const struct oxr_input_value_tagged *input,
|
||||
struct oxr_input_value_tagged *out);
|
||||
|
@ -300,6 +330,40 @@ oxr_input_transform_create_chain(struct oxr_logger *log,
|
|||
struct oxr_input_transform **out_transforms,
|
||||
size_t *out_transform_count);
|
||||
|
||||
/*!
|
||||
* Create a transform array to process a 2D input plus activation input to a dpad.
|
||||
*
|
||||
* @param[in] log The logger
|
||||
* @param[in] slog The sink logger
|
||||
* @param[in] input_type The type of input received from the hardware
|
||||
* @param[in] result_type The type of input the application requested
|
||||
* @param[in] bound_path_string The path name string that has been bound.
|
||||
* @param[in] dpad_settings The dpad settings provided by the application
|
||||
* as a binding modification. NULL means use the defaults as per the spec.
|
||||
* @param[in] dpad_region The dpad region associated with this binding
|
||||
* @param[in] activation_input_type The type of the activation input
|
||||
* @param[in] activation_input The activation input, i.e. the input used
|
||||
* to determine when the emulated dpad buttons should activate
|
||||
* @param[out] out_transforms A pointer that will be populated with the output
|
||||
* array's address, or NULL.
|
||||
* @param[out] out_transform_count Where to populate the array size
|
||||
* @return false if not possible
|
||||
*
|
||||
* @relates oxr_input_transform
|
||||
*/
|
||||
bool
|
||||
oxr_input_transform_create_chain_dpad(struct oxr_logger *log,
|
||||
struct oxr_sink_logger *slog,
|
||||
enum xrt_input_type input_type,
|
||||
XrActionType result_type,
|
||||
const char *bound_path_string,
|
||||
struct oxr_dpad_binding_modification *dpad_binding_modification,
|
||||
enum oxr_dpad_region dpad_region,
|
||||
enum xrt_input_type activation_input_type,
|
||||
struct xrt_input *activation_input,
|
||||
struct oxr_input_transform **out_transforms,
|
||||
size_t *out_transform_count);
|
||||
|
||||
/*!
|
||||
* @}
|
||||
*/
|
||||
|
|
|
@ -173,6 +173,18 @@ enum oxr_subaction_path
|
|||
OXR_SUB_ACTION_PATH_GAMEPAD,
|
||||
};
|
||||
|
||||
/*!
|
||||
* Region of a dpad binding that an input is mapped to
|
||||
*/
|
||||
enum oxr_dpad_region
|
||||
{
|
||||
OXR_DPAD_REGION_CENTER = 0,
|
||||
OXR_DPAD_REGION_UP = (1 << 0),
|
||||
OXR_DPAD_REGION_DOWN = (1 << 1),
|
||||
OXR_DPAD_REGION_LEFT = (1 << 2),
|
||||
OXR_DPAD_REGION_RIGHT = (1 << 3),
|
||||
};
|
||||
|
||||
/*!
|
||||
* Tracks the state of a image that belongs to a @ref oxr_swapchain.
|
||||
*/
|
||||
|
@ -1596,6 +1608,29 @@ oxr_session_success_focused_result(struct oxr_session *session)
|
|||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* dpad settings we need extracted from XrInteractionProfileDpadBindingEXT
|
||||
*
|
||||
* @ingroup oxr_input
|
||||
*/
|
||||
struct oxr_dpad_settings
|
||||
{
|
||||
float forceThreshold;
|
||||
float forceThresholdReleased;
|
||||
float centerRegion;
|
||||
float wedgeAngle;
|
||||
bool isSticky;
|
||||
};
|
||||
|
||||
/*!
|
||||
* dpad binding extracted from XrInteractionProfileDpadBindingEXT
|
||||
*/
|
||||
struct oxr_dpad_binding_modification
|
||||
{
|
||||
XrPath binding;
|
||||
struct oxr_dpad_settings settings;
|
||||
};
|
||||
|
||||
/*!
|
||||
* A entry in the dpad state for one action set.
|
||||
*
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "oxr_objects.h" // For now needs to come before oxr_logger.h
|
||||
#include "oxr_logger.h"
|
||||
#include "oxr_input_transform.h"
|
||||
#include "oxr_pretty_print.h"
|
||||
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "oxr_objects.h"
|
||||
#include "oxr_logger.h"
|
||||
#include "oxr_handle.h"
|
||||
#include "oxr_input_transform.h"
|
||||
#include "oxr_chain.h"
|
||||
#include "oxr_pretty_print.h"
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
* @author Ryan Pavlik <ryan.pavlik@collabora.com>
|
||||
*/
|
||||
|
||||
#include "math/m_mathinclude.h"
|
||||
|
||||
#include "catch/catch.hpp"
|
||||
|
||||
#include <xrt/xrt_defines.h>
|
||||
|
@ -315,3 +317,236 @@ TEST_CASE("input_transform")
|
|||
oxr_input_transform_destroy(&transforms);
|
||||
CHECK(NULL == transforms);
|
||||
}
|
||||
|
||||
|
||||
struct dpad_test_case
|
||||
{
|
||||
float x;
|
||||
float y;
|
||||
enum oxr_dpad_region active_regions;
|
||||
};
|
||||
|
||||
|
||||
TEST_CASE("input_transform_dpad")
|
||||
{
|
||||
struct oxr_logger log;
|
||||
oxr_log_init(&log, "test");
|
||||
struct oxr_sink_logger slog = {};
|
||||
|
||||
struct oxr_input_transform *transforms = NULL;
|
||||
size_t transform_count = 0;
|
||||
|
||||
oxr_input_value_tagged input = {};
|
||||
oxr_input_value_tagged output = {};
|
||||
|
||||
struct oxr_dpad_binding_modification *dpad_binding_modification = NULL;
|
||||
enum xrt_input_type activation_input_type = XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE;
|
||||
struct xrt_input activation_input = {};
|
||||
enum oxr_dpad_region dpad_region = OXR_DPAD_REGION_UP;
|
||||
|
||||
SECTION("Default settings")
|
||||
{
|
||||
XrActionType action_type = XR_ACTION_TYPE_BOOLEAN_INPUT;
|
||||
|
||||
SECTION("without an activation input")
|
||||
{
|
||||
input.type = XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE;
|
||||
|
||||
CHECK(oxr_input_transform_create_chain_dpad(
|
||||
&log, &slog, input.type, action_type, "/dummy_vec2/dpad_up", dpad_binding_modification,
|
||||
dpad_region, activation_input_type, NULL, &transforms, &transform_count));
|
||||
CHECK(transform_count == 1);
|
||||
CHECK(transforms != nullptr);
|
||||
CHECK(transforms[0].type == INPUT_TRANSFORM_DPAD);
|
||||
|
||||
|
||||
SECTION("up region is off in center")
|
||||
{
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = 0.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(false == output.value.boolean);
|
||||
}
|
||||
|
||||
SECTION("up region is on when pointing up")
|
||||
{
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = 1.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(true == output.value.boolean);
|
||||
}
|
||||
|
||||
struct dpad_test_case cases[9] = {
|
||||
// obvious
|
||||
{0.0f, 0.0f, OXR_DPAD_REGION_CENTER},
|
||||
{0.0f, 1.0f, OXR_DPAD_REGION_UP},
|
||||
{0.0f, -1.0f, OXR_DPAD_REGION_DOWN},
|
||||
{-1.0f, 0.0f, OXR_DPAD_REGION_LEFT},
|
||||
{1.0f, 0.0f, OXR_DPAD_REGION_RIGHT},
|
||||
// boundary cases
|
||||
{1.0f, 1.0f, OXR_DPAD_REGION_UP},
|
||||
{-1.0f, -1.0f, OXR_DPAD_REGION_DOWN},
|
||||
{-1.0f, 1.0f, OXR_DPAD_REGION_LEFT},
|
||||
{1.0f, -1.0f, OXR_DPAD_REGION_RIGHT},
|
||||
};
|
||||
|
||||
for (uint32_t i = 0; i < ARRAY_SIZE(cases); i++) {
|
||||
DYNAMIC_SECTION("with (x, y) of (" << cases[i].x << ", " << cases[i].y << ")")
|
||||
{
|
||||
input.value.vec2.x = cases[i].x;
|
||||
input.value.vec2.y = cases[i].y;
|
||||
CHECK(
|
||||
oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(cases[i].active_regions == transforms[0].data.dpad_state.active_regions);
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("with a boolean activation input")
|
||||
{
|
||||
input.type = XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE;
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = 1.0f;
|
||||
|
||||
activation_input_type = XRT_INPUT_TYPE_BOOLEAN;
|
||||
|
||||
CHECK(oxr_input_transform_create_chain_dpad(
|
||||
&log, &slog, input.type, action_type, "/dummy_vec2/dpad_up", dpad_binding_modification,
|
||||
dpad_region, activation_input_type, &activation_input, &transforms, &transform_count));
|
||||
CHECK(transform_count == 1);
|
||||
CHECK(transforms != nullptr);
|
||||
CHECK(transforms[0].type == INPUT_TRANSFORM_DPAD);
|
||||
|
||||
SECTION("when activation input is set to true")
|
||||
{
|
||||
activation_input.value.boolean = true;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(true == output.value.boolean);
|
||||
}
|
||||
SECTION("when activation input is set to false")
|
||||
{
|
||||
activation_input.value.boolean = false;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(false == output.value.boolean);
|
||||
}
|
||||
}
|
||||
SECTION("with a float activation input")
|
||||
{
|
||||
input.type = XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE;
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = 1.0f;
|
||||
|
||||
activation_input_type = XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE;
|
||||
|
||||
CHECK(oxr_input_transform_create_chain_dpad(
|
||||
&log, &slog, input.type, action_type, "/dummy_vec2/dpad_up", dpad_binding_modification,
|
||||
dpad_region, activation_input_type, &activation_input, &transforms, &transform_count));
|
||||
CHECK(transform_count == 1);
|
||||
CHECK(transforms != nullptr);
|
||||
CHECK(transforms[0].type == INPUT_TRANSFORM_DPAD);
|
||||
|
||||
SECTION("when activation input is set to 1.0")
|
||||
{
|
||||
activation_input.value.vec1.x = 1.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(true == output.value.boolean);
|
||||
}
|
||||
SECTION("when activation input is set to 0.0")
|
||||
{
|
||||
activation_input.value.vec1.x = 0.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(false == output.value.boolean);
|
||||
}
|
||||
SECTION("when activation input varies")
|
||||
{
|
||||
activation_input.value.vec1.x = 0.45f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(false == output.value.boolean);
|
||||
activation_input.value.vec1.x = 0.6f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(true == output.value.boolean);
|
||||
activation_input.value.vec1.x = 0.45f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(true == output.value.boolean);
|
||||
activation_input.value.vec1.x = 0.35f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(false == output.value.boolean);
|
||||
}
|
||||
}
|
||||
}
|
||||
SECTION("Sticky enabled")
|
||||
{
|
||||
XrActionType action_type = XR_ACTION_TYPE_BOOLEAN_INPUT;
|
||||
|
||||
struct oxr_dpad_binding_modification dpad_binding_modification_val = {
|
||||
XR_NULL_PATH, // XrPath binding, unused at this stage
|
||||
{
|
||||
0.5f, // float forceThreshold
|
||||
0.4f, // float forceThresholdReleased
|
||||
0.5f, // float centerRegion
|
||||
M_PI_2, // float wedgeAngle
|
||||
true, // bool isSticky
|
||||
}};
|
||||
dpad_binding_modification = &dpad_binding_modification_val;
|
||||
|
||||
SECTION("without an activation input")
|
||||
{
|
||||
input.type = XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE;
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = 1.0f;
|
||||
|
||||
CHECK(oxr_input_transform_create_chain_dpad(
|
||||
&log, &slog, input.type, action_type, "/dummy_vec2/dpad_up", dpad_binding_modification,
|
||||
dpad_region, activation_input_type, NULL, &transforms, &transform_count));
|
||||
CHECK(transform_count == 1);
|
||||
CHECK(transforms != nullptr);
|
||||
CHECK(transforms[0].type == INPUT_TRANSFORM_DPAD);
|
||||
|
||||
SECTION("up region is off in center")
|
||||
{
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = 0.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(false == output.value.boolean);
|
||||
}
|
||||
|
||||
SECTION("up region is on when pointing up")
|
||||
{
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = 1.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(true == output.value.boolean);
|
||||
}
|
||||
SECTION("up region is off when pointing down")
|
||||
{
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = -1.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(false == output.value.boolean);
|
||||
}
|
||||
|
||||
SECTION("up region stays on when stick moves clockwise to down")
|
||||
{
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = 1.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(true == output.value.boolean);
|
||||
input.value.vec2.x = 1.0f;
|
||||
input.value.vec2.y = 0.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(true == output.value.boolean);
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = -1.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(true == output.value.boolean);
|
||||
input.value.vec2.x = 0.0f;
|
||||
input.value.vec2.y = 0.0f;
|
||||
CHECK(oxr_input_transform_process(transforms, transform_count, &input, &output));
|
||||
CHECK(false == output.value.boolean);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
oxr_log_slog(&log, &slog);
|
||||
oxr_input_transform_destroy(&transforms);
|
||||
CHECK(NULL == transforms);
|
||||
}
|
Loading…
Reference in a new issue