2020-06-01 20:32:43 +00:00
|
|
|
// Copyright 2018-2020, Collabora, Ltd.
|
2019-05-07 12:47:18 +00:00
|
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
|
|
/*!
|
|
|
|
* @file
|
|
|
|
* @brief Holds input related functions.
|
|
|
|
* @author Jakob Bornecrantz <jakob@collabora.com>
|
|
|
|
* @ingroup oxr_main
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "util/u_debug.h"
|
|
|
|
#include "util/u_time.h"
|
|
|
|
#include "util/u_misc.h"
|
|
|
|
|
|
|
|
#include "xrt/xrt_compiler.h"
|
|
|
|
|
|
|
|
#include "oxr_objects.h"
|
|
|
|
#include "oxr_logger.h"
|
|
|
|
#include "oxr_handle.h"
|
2020-06-15 15:58:48 +00:00
|
|
|
#include "oxr_input_transform.h"
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-10-28 10:56:45 +00:00
|
|
|
#include <math.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Pre declare functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static void
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_session_get_action_set_attachment(
|
|
|
|
struct oxr_session *sess,
|
|
|
|
XrActionSet actionSet,
|
|
|
|
struct oxr_action_set_attachment **act_set_attached,
|
|
|
|
struct oxr_action_set **act_set);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
static void
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_session_get_action_attachment(
|
|
|
|
struct oxr_session *sess,
|
|
|
|
uint32_t act_key,
|
|
|
|
struct oxr_action_attachment **out_act_attached);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
static void
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_update(struct oxr_logger *log,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_session *sess,
|
2020-06-16 21:31:29 +00:00
|
|
|
struct oxr_action_cache *cache,
|
2019-05-07 12:47:18 +00:00
|
|
|
int64_t time,
|
|
|
|
bool select);
|
|
|
|
|
|
|
|
static void
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_action_attachment_update(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_action_attachment *act_attached,
|
|
|
|
int64_t time,
|
|
|
|
struct oxr_sub_paths sub_paths);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
static void
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_bind_inputs(struct oxr_logger *log,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_sink_logger *slog,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_action *act,
|
2020-06-16 21:31:29 +00:00
|
|
|
struct oxr_action_cache *cache,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_interaction_profile *profile,
|
2019-09-02 21:04:13 +00:00
|
|
|
enum oxr_sub_action_path sub_path);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Action attachment functions
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
2020-06-16 21:31:29 +00:00
|
|
|
* De-initialize/de-allocate all dynamic members of @ref oxr_action_cache
|
|
|
|
* @private @memberof oxr_action_cache
|
2020-06-15 21:46:21 +00:00
|
|
|
*/
|
|
|
|
static void
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_teardown(struct oxr_action_cache *cache)
|
2020-06-15 21:46:21 +00:00
|
|
|
{
|
2020-06-15 15:58:48 +00:00
|
|
|
// Clean up input transforms
|
|
|
|
for (uint32_t i = 0; i < cache->num_inputs; i++) {
|
|
|
|
struct oxr_action_input *action_input = &cache->inputs[i];
|
|
|
|
oxr_input_transform_destroy(&(action_input->transforms));
|
|
|
|
action_input->num_transforms = 0;
|
|
|
|
}
|
2020-06-15 21:46:21 +00:00
|
|
|
free(cache->inputs);
|
|
|
|
cache->inputs = NULL;
|
|
|
|
free(cache->outputs);
|
|
|
|
cache->outputs = NULL;
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
/*!
|
2020-06-15 21:46:21 +00:00
|
|
|
* Tear down an action attachment struct.
|
2020-06-15 19:16:38 +00:00
|
|
|
*
|
2020-06-15 21:46:21 +00:00
|
|
|
* Does not deallocate the struct itself.
|
|
|
|
*
|
|
|
|
* @public @memberof oxr_action_attachment
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
oxr_action_attachment_teardown(struct oxr_action_attachment *act_attached)
|
|
|
|
{
|
|
|
|
struct oxr_session *sess = act_attached->sess;
|
2020-06-15 22:05:32 +00:00
|
|
|
u_hashmap_int_erase(sess->act_attachments_by_key,
|
|
|
|
act_attached->act_key);
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_teardown(&(act_attached->user));
|
|
|
|
oxr_action_cache_teardown(&(act_attached->head));
|
|
|
|
oxr_action_cache_teardown(&(act_attached->left));
|
|
|
|
oxr_action_cache_teardown(&(act_attached->right));
|
|
|
|
oxr_action_cache_teardown(&(act_attached->gamepad));
|
2020-06-15 23:05:42 +00:00
|
|
|
// Unref this action's refcounted data
|
|
|
|
oxr_refcounted_unref(&act_attached->act_ref->base);
|
2020-06-15 21:46:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* Set up an action attachment struct.
|
|
|
|
*
|
|
|
|
* @public @memberof oxr_action_attachment
|
2020-06-15 19:16:38 +00:00
|
|
|
*/
|
2019-05-07 12:47:18 +00:00
|
|
|
static XrResult
|
2020-06-15 21:46:21 +00:00
|
|
|
oxr_action_attachment_init(struct oxr_logger *log,
|
|
|
|
struct oxr_action_set_attachment *act_set_attached,
|
|
|
|
struct oxr_action_attachment *act_attached,
|
|
|
|
struct oxr_action *act)
|
|
|
|
{
|
|
|
|
struct oxr_session *sess = act_set_attached->sess;
|
|
|
|
act_attached->sess = sess;
|
|
|
|
act_attached->act_set_attached = act_set_attached;
|
2020-06-15 22:05:32 +00:00
|
|
|
u_hashmap_int_insert(sess->act_attachments_by_key, act->act_key,
|
2020-06-15 21:46:21 +00:00
|
|
|
act_attached);
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
// Reference this action's refcounted data
|
|
|
|
act_attached->act_ref = act->data;
|
|
|
|
oxr_refcounted_ref(&act_attached->act_ref->base);
|
|
|
|
|
|
|
|
// Copy this for efficiency.
|
2020-06-15 22:05:32 +00:00
|
|
|
act_attached->act_key = act->act_key;
|
2020-06-15 21:46:21 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Action set attachment functions
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*!
|
|
|
|
* @public @memberof oxr_action_set_attachment
|
|
|
|
*/
|
|
|
|
static XrResult
|
|
|
|
oxr_action_set_attachment_init(
|
|
|
|
struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_action_set *act_set,
|
|
|
|
struct oxr_action_set_attachment *act_set_attached)
|
|
|
|
{
|
|
|
|
act_set_attached->sess = sess;
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
// Reference this action set's refcounted data
|
|
|
|
act_set_attached->act_set_ref = act_set->data;
|
|
|
|
oxr_refcounted_ref(&act_set_attached->act_set_ref->base);
|
|
|
|
|
2020-06-15 22:05:32 +00:00
|
|
|
u_hashmap_int_insert(sess->act_sets_attachments_by_key,
|
|
|
|
act_set->act_set_key, act_set_attached);
|
2020-06-15 21:46:21 +00:00
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
// Copy this for efficiency.
|
2020-06-15 22:05:32 +00:00
|
|
|
act_set_attached->act_set_key = act_set->act_set_key;
|
2020-06-15 21:46:21 +00:00
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
oxr_action_set_attachment_teardown(
|
|
|
|
struct oxr_action_set_attachment *act_set_attached)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < act_set_attached->num_action_attachments; ++i) {
|
|
|
|
oxr_action_attachment_teardown(
|
|
|
|
&(act_set_attached->act_attachments[i]));
|
|
|
|
}
|
|
|
|
free(act_set_attached->act_attachments);
|
|
|
|
act_set_attached->act_attachments = NULL;
|
|
|
|
act_set_attached->num_action_attachments = 0;
|
|
|
|
|
|
|
|
struct oxr_session *sess = act_set_attached->sess;
|
|
|
|
u_hashmap_int_erase(sess->act_sets_attachments_by_key,
|
2020-06-15 22:05:32 +00:00
|
|
|
act_set_attached->act_set_key);
|
2020-06-15 23:05:42 +00:00
|
|
|
|
|
|
|
// Unref this action set's refcounted data
|
|
|
|
oxr_refcounted_unref(&act_set_attached->act_set_ref->base);
|
2020-06-15 21:46:21 +00:00
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Action set functions
|
|
|
|
*
|
|
|
|
*/
|
2020-06-15 23:05:42 +00:00
|
|
|
static void
|
|
|
|
oxr_action_set_ref_destroy_cb(struct oxr_refcounted *orc)
|
|
|
|
{
|
|
|
|
struct oxr_action_set_ref *act_set_ref =
|
|
|
|
(struct oxr_action_set_ref *)orc;
|
|
|
|
|
|
|
|
u_hashset_destroy(&act_set_ref->actions.name_store);
|
|
|
|
u_hashset_destroy(&act_set_ref->actions.loc_store);
|
|
|
|
|
|
|
|
free(act_set_ref);
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
static XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_set_destroy_cb(struct oxr_logger *log, struct oxr_handle_base *hb)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_action_set *act_set = (struct oxr_action_set *)hb;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
oxr_refcounted_unref(&act_set->data->base);
|
|
|
|
act_set->data = NULL;
|
|
|
|
|
2020-05-30 22:44:03 +00:00
|
|
|
if (act_set->name_item != NULL) {
|
|
|
|
u_hashset_erase_item(act_set->inst->action_sets.name_store,
|
|
|
|
act_set->name_item);
|
|
|
|
free(act_set->name_item);
|
|
|
|
act_set->name_item = NULL;
|
|
|
|
}
|
|
|
|
if (act_set->loc_item != NULL) {
|
|
|
|
u_hashset_erase_item(act_set->inst->action_sets.loc_store,
|
|
|
|
act_set->loc_item);
|
|
|
|
free(act_set->loc_item);
|
|
|
|
act_set->loc_item = NULL;
|
|
|
|
}
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
free(act_set);
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_set_create(struct oxr_logger *log,
|
|
|
|
struct oxr_instance *inst,
|
|
|
|
const XrActionSetCreateInfo *createInfo,
|
|
|
|
struct oxr_action_set **out_act_set)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-05-07 12:47:18 +00:00
|
|
|
// Mod music for all!
|
2019-09-02 19:40:06 +00:00
|
|
|
static uint32_t key_gen = 1;
|
2020-05-30 22:44:03 +00:00
|
|
|
int h_ret;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_action_set *act_set = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
OXR_ALLOCATE_HANDLE_OR_RETURN(log, act_set, OXR_XR_DEBUG_ACTIONSET,
|
2019-07-13 16:17:57 +00:00
|
|
|
oxr_action_set_destroy_cb, &inst->handle);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
struct oxr_action_set_ref *act_set_ref =
|
|
|
|
U_TYPED_CALLOC(struct oxr_action_set_ref);
|
|
|
|
act_set_ref->base.destroy = oxr_action_set_ref_destroy_cb;
|
|
|
|
oxr_refcounted_ref(&act_set_ref->base);
|
|
|
|
act_set->data = act_set_ref;
|
|
|
|
|
|
|
|
act_set_ref->act_set_key = key_gen++;
|
|
|
|
act_set->act_set_key = act_set_ref->act_set_key;
|
|
|
|
|
|
|
|
act_set->inst = inst;
|
|
|
|
|
|
|
|
h_ret = u_hashset_create(&act_set_ref->actions.name_store);
|
2020-05-30 22:44:03 +00:00
|
|
|
if (h_ret != 0) {
|
|
|
|
oxr_handle_destroy(log, &act_set->handle);
|
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"Failed to create name_store hashset");
|
|
|
|
}
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
h_ret = u_hashset_create(&act_set_ref->actions.loc_store);
|
2020-05-30 22:44:03 +00:00
|
|
|
if (h_ret != 0) {
|
|
|
|
oxr_handle_destroy(log, &act_set->handle);
|
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"Failed to create loc_store hashset");
|
|
|
|
}
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
strncpy(act_set_ref->name, createInfo->actionSetName,
|
|
|
|
sizeof(act_set_ref->name));
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-05-30 22:44:03 +00:00
|
|
|
u_hashset_create_and_insert_str_c(inst->action_sets.name_store,
|
|
|
|
createInfo->actionSetName,
|
|
|
|
&act_set->name_item);
|
|
|
|
u_hashset_create_and_insert_str_c(inst->action_sets.loc_store,
|
|
|
|
createInfo->localizedActionSetName,
|
|
|
|
&act_set->loc_item);
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
*out_act_set = act_set;
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Action functions
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
static void
|
|
|
|
oxr_action_ref_destroy_cb(struct oxr_refcounted *orc)
|
|
|
|
{
|
|
|
|
struct oxr_action_ref *act_ref = (struct oxr_action_ref *)orc;
|
|
|
|
free(act_ref);
|
|
|
|
}
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
static XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_destroy_cb(struct oxr_logger *log, struct oxr_handle_base *hb)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_action *act = (struct oxr_action *)hb;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
oxr_refcounted_unref(&act->data->base);
|
|
|
|
act->data = NULL;
|
|
|
|
|
2020-05-30 22:44:03 +00:00
|
|
|
if (act->name_item != NULL) {
|
2020-06-15 23:05:42 +00:00
|
|
|
u_hashset_erase_item(act->act_set->data->actions.name_store,
|
2020-05-30 22:44:03 +00:00
|
|
|
act->name_item);
|
|
|
|
free(act->name_item);
|
|
|
|
act->name_item = NULL;
|
|
|
|
}
|
|
|
|
if (act->loc_item != NULL) {
|
2020-06-15 23:05:42 +00:00
|
|
|
u_hashset_erase_item(act->act_set->data->actions.loc_store,
|
2020-05-30 22:44:03 +00:00
|
|
|
act->loc_item);
|
|
|
|
free(act->loc_item);
|
|
|
|
act->loc_item = NULL;
|
|
|
|
}
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
free(act);
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_create(struct oxr_logger *log,
|
|
|
|
struct oxr_action_set *act_set,
|
|
|
|
const XrActionCreateInfo *createInfo,
|
|
|
|
struct oxr_action **out_act)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_instance *inst = act_set->inst;
|
2019-05-07 12:47:18 +00:00
|
|
|
struct oxr_sub_paths sub_paths = {0};
|
|
|
|
|
|
|
|
// Mod music for all!
|
2019-09-02 19:40:06 +00:00
|
|
|
static uint32_t key_gen = 1;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
if (!oxr_classify_sub_action_paths(
|
|
|
|
log, inst, createInfo->countSubactionPaths,
|
|
|
|
createInfo->subactionPaths, &sub_paths)) {
|
|
|
|
return XR_ERROR_PATH_UNSUPPORTED;
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_action *act = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
OXR_ALLOCATE_HANDLE_OR_RETURN(log, act, OXR_XR_DEBUG_ACTION,
|
|
|
|
oxr_action_destroy_cb, &act_set->handle);
|
2020-06-15 23:05:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
struct oxr_action_ref *act_ref = U_TYPED_CALLOC(struct oxr_action_ref);
|
|
|
|
act_ref->base.destroy = oxr_action_ref_destroy_cb;
|
|
|
|
oxr_refcounted_ref(&act_ref->base);
|
|
|
|
act->data = act_ref;
|
|
|
|
|
|
|
|
act_ref->act_key = key_gen++;
|
|
|
|
act->act_key = act_ref->act_key;
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
act->act_set = act_set;
|
2020-06-15 23:05:42 +00:00
|
|
|
act_ref->sub_paths = sub_paths;
|
|
|
|
act_ref->action_type = createInfo->actionType;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
strncpy(act_ref->name, createInfo->actionName, sizeof(act_ref->name));
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
u_hashset_create_and_insert_str_c(act_set->data->actions.name_store,
|
2020-05-30 22:44:03 +00:00
|
|
|
createInfo->actionName,
|
|
|
|
&act->name_item);
|
2020-06-15 23:05:42 +00:00
|
|
|
u_hashset_create_and_insert_str_c(act_set->data->actions.loc_store,
|
2020-05-30 22:44:03 +00:00
|
|
|
createInfo->localizedActionName,
|
|
|
|
&act->loc_item);
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
*out_act = act;
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
/*
|
|
|
|
*
|
2020-06-12 21:51:27 +00:00
|
|
|
* "Exported" helper functions.
|
2019-05-07 12:47:18 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
bool
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_classify_sub_action_paths(struct oxr_logger *log,
|
|
|
|
struct oxr_instance *inst,
|
2019-05-07 12:47:18 +00:00
|
|
|
uint32_t num_subaction_paths,
|
2019-09-29 10:43:45 +00:00
|
|
|
const XrPath *subaction_paths,
|
|
|
|
struct oxr_sub_paths *sub_paths)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
const char *str = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
size_t length = 0;
|
2020-06-15 19:16:38 +00:00
|
|
|
bool ret = true;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
// Reset the sub_paths completely.
|
2019-06-18 20:32:08 +00:00
|
|
|
U_ZERO(sub_paths);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
if (num_subaction_paths == 0) {
|
|
|
|
sub_paths->any = true;
|
2020-06-15 19:16:38 +00:00
|
|
|
return ret;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < num_subaction_paths; i++) {
|
|
|
|
XrPath path = subaction_paths[i];
|
|
|
|
|
|
|
|
if (path == XR_NULL_PATH) {
|
|
|
|
sub_paths->any = true;
|
|
|
|
} else if (path == inst->path_cache.user) {
|
|
|
|
sub_paths->user = true;
|
|
|
|
} else if (path == inst->path_cache.head) {
|
|
|
|
sub_paths->head = true;
|
|
|
|
} else if (path == inst->path_cache.left) {
|
|
|
|
sub_paths->left = true;
|
|
|
|
} else if (path == inst->path_cache.right) {
|
|
|
|
sub_paths->right = true;
|
|
|
|
} else if (path == inst->path_cache.gamepad) {
|
|
|
|
sub_paths->gamepad = true;
|
2020-06-15 19:53:23 +00:00
|
|
|
} else if (path == inst->path_cache.treadmill) {
|
|
|
|
sub_paths->treadmill = true;
|
2019-05-07 12:47:18 +00:00
|
|
|
} else {
|
|
|
|
oxr_path_get_string(log, inst, path, &str, &length);
|
|
|
|
|
|
|
|
oxr_warn(log, " unrecognized sub action path '%s'",
|
|
|
|
str);
|
2020-06-15 19:16:38 +00:00
|
|
|
ret = false;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
return ret;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_get_pose_input(struct oxr_logger *log,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_session *sess,
|
2019-05-07 12:47:18 +00:00
|
|
|
uint32_t act_key,
|
2019-09-29 10:43:45 +00:00
|
|
|
const struct oxr_sub_paths *sub_paths,
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_input **out_input)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_attachment *act_attached = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_session_get_action_attachment(sess, act_key, &act_attached);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached == NULL) {
|
2019-05-07 12:47:18 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Priority of inputs.
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->head.current.active &&
|
|
|
|
(sub_paths->head || sub_paths->any)) {
|
|
|
|
*out_input = act_attached->head.inputs;
|
2019-05-07 12:47:18 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->left.current.active &&
|
|
|
|
(sub_paths->left || sub_paths->any)) {
|
|
|
|
*out_input = act_attached->left.inputs;
|
2019-05-07 12:47:18 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->right.current.active &&
|
|
|
|
(sub_paths->right || sub_paths->any)) {
|
|
|
|
*out_input = act_attached->right.inputs;
|
2019-05-07 12:47:18 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->gamepad.current.active &&
|
2019-05-07 12:47:18 +00:00
|
|
|
(sub_paths->gamepad || sub_paths->any)) {
|
2020-06-15 19:16:38 +00:00
|
|
|
*out_input = act_attached->gamepad.inputs;
|
2019-05-07 12:47:18 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->user.current.active &&
|
|
|
|
(sub_paths->user || sub_paths->any)) {
|
|
|
|
*out_input = act_attached->user.inputs;
|
2019-05-07 12:47:18 +00:00
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
2019-09-02 21:04:13 +00:00
|
|
|
* Not so hack functions.
|
2019-05-07 12:47:18 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
static bool
|
2019-09-29 10:43:45 +00:00
|
|
|
do_inputs(struct oxr_binding *bind,
|
|
|
|
struct xrt_device *xdev,
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_input inputs[16],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_inputs)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
struct xrt_input *input = NULL;
|
2019-09-02 21:04:13 +00:00
|
|
|
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
|
2019-09-29 10:43:45 +00:00
|
|
|
do_outputs(struct oxr_binding *bind,
|
|
|
|
struct xrt_device *xdev,
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_output outputs[16],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_outputs)
|
2019-09-02 21:04:13 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
struct xrt_output *output = NULL;
|
2019-09-02 21:04:13 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-06-12 21:51:27 +00:00
|
|
|
/*!
|
|
|
|
* Delegate to @ref do_outputs or @ref do_inputs depending on whether the action
|
|
|
|
* is output or input.
|
|
|
|
*/
|
2019-09-02 21:04:13 +00:00
|
|
|
static bool
|
2019-09-29 10:43:45 +00:00
|
|
|
do_io_bindings(struct oxr_binding *b,
|
|
|
|
struct oxr_action *act,
|
|
|
|
struct xrt_device *xdev,
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_input inputs[16],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_inputs,
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_output outputs[16],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_outputs)
|
2019-09-02 21:04:13 +00:00
|
|
|
{
|
|
|
|
bool found = false;
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
if (act->data->action_type == XR_ACTION_TYPE_VIBRATION_OUTPUT) {
|
2019-09-02 21:04:13 +00:00
|
|
|
found |= do_outputs(b, xdev, outputs, num_outputs);
|
|
|
|
} else {
|
|
|
|
found |= do_inputs(b, xdev, inputs, num_inputs);
|
|
|
|
}
|
|
|
|
|
|
|
|
return found;
|
|
|
|
}
|
|
|
|
|
2020-05-04 15:22:15 +00:00
|
|
|
static XrPath
|
|
|
|
get_matched_xrpath(struct oxr_binding *b, struct oxr_action *act)
|
|
|
|
{
|
|
|
|
XrPath preferred_path = XR_NULL_PATH;
|
|
|
|
for (uint32_t i = 0; i < b->num_keys; i++) {
|
2020-06-15 22:05:32 +00:00
|
|
|
if (b->keys[i] == act->act_key) {
|
2020-05-04 15:22:15 +00:00
|
|
|
uint32_t preferred_path_index = XR_NULL_PATH;
|
|
|
|
preferred_path_index =
|
|
|
|
b->preferred_binding_path_index[i];
|
|
|
|
preferred_path = b->paths[preferred_path_index];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return preferred_path;
|
|
|
|
}
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
static void
|
2019-09-29 10:43:45 +00:00
|
|
|
get_binding(struct oxr_logger *log,
|
|
|
|
struct oxr_sink_logger *slog,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_action *act,
|
|
|
|
struct oxr_interaction_profile *profile,
|
2019-09-02 21:04:13 +00:00
|
|
|
enum oxr_sub_action_path sub_path,
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_input inputs[16],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_inputs,
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_output outputs[16],
|
2020-04-29 03:27:20 +00:00
|
|
|
uint32_t *num_outputs,
|
|
|
|
XrPath *bound_path)
|
2019-09-02 21:04:13 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
struct xrt_device *xdev = NULL;
|
|
|
|
struct oxr_binding *bindings[32];
|
|
|
|
const char *profile_str;
|
|
|
|
const char *user_path_str;
|
2019-09-02 21:04:13 +00:00
|
|
|
size_t length;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
//! @todo This probably falls on its head if the application doesn't use
|
|
|
|
//! sub action paths.
|
2019-05-07 12:47:18 +00:00
|
|
|
switch (sub_path) {
|
2019-09-02 21:04:13 +00:00
|
|
|
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;
|
2019-05-07 12:47:18 +00:00
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
oxr_slog(slog, "\tFor: %s\n", user_path_str);
|
|
|
|
|
|
|
|
if (xdev == NULL) {
|
|
|
|
oxr_slog(slog, "\t\tNo xdev!\n");
|
|
|
|
return;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
if (profile == NULL) {
|
|
|
|
oxr_slog(slog, "\t\tNo profile!\n");
|
|
|
|
return;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
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;
|
2020-06-15 22:05:32 +00:00
|
|
|
oxr_binding_find_bindings_from_key(log, profile, act->act_key, bindings,
|
2019-09-02 21:04:13 +00:00
|
|
|
&num);
|
|
|
|
if (num == 0) {
|
|
|
|
oxr_slog(slog, "\t\tNo bindings\n");
|
|
|
|
return;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2019-08-16 15:52:15 +00:00
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
for (size_t i = 0; i < num; i++) {
|
2019-09-29 10:43:45 +00:00
|
|
|
const char *str = NULL;
|
|
|
|
struct oxr_binding *b = bindings[i];
|
2019-09-02 21:04:13 +00:00
|
|
|
|
2020-05-04 15:22:15 +00:00
|
|
|
XrPath matched_path = get_matched_xrpath(b, act);
|
2020-04-29 03:27:20 +00:00
|
|
|
|
2020-05-04 15:22:15 +00:00
|
|
|
oxr_path_get_string(log, sess->sys->inst, matched_path, &str,
|
2019-09-02 21:04:13 +00:00
|
|
|
&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) {
|
2020-05-04 15:22:15 +00:00
|
|
|
*bound_path = matched_path;
|
2019-09-02 21:04:13 +00:00
|
|
|
oxr_slog(slog, "\t\t\t\tBound!\n");
|
|
|
|
} else {
|
|
|
|
oxr_slog(slog, "\t\t\t\tRejected! (NO XDEV MAPPING)\n");
|
|
|
|
}
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2020-06-15 15:47:11 +00:00
|
|
|
/*!
|
2020-06-15 21:46:21 +00:00
|
|
|
* @public @memberof oxr_action_attachment
|
2020-06-15 15:47:11 +00:00
|
|
|
*/
|
2019-05-07 12:47:18 +00:00
|
|
|
static XrResult
|
2020-06-15 21:46:21 +00:00
|
|
|
oxr_action_attachment_bind(struct oxr_logger *log,
|
|
|
|
struct oxr_action_attachment *act_attached,
|
|
|
|
struct oxr_action *act,
|
|
|
|
struct oxr_interaction_profile *head,
|
|
|
|
struct oxr_interaction_profile *left,
|
|
|
|
struct oxr_interaction_profile *right,
|
|
|
|
struct oxr_interaction_profile *gamepad)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-02 21:04:13 +00:00
|
|
|
struct oxr_sink_logger slog = {0};
|
2020-06-15 23:05:42 +00:00
|
|
|
struct oxr_action_ref *act_ref = act->data;
|
2020-06-15 21:46:21 +00:00
|
|
|
struct oxr_session *sess = act_attached->sess;
|
2019-10-28 14:57:35 +00:00
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
// Start logging into a single buffer.
|
2020-06-15 23:05:42 +00:00
|
|
|
oxr_slog(&slog, ": Binding %s/%s\n", act->act_set->data->name,
|
|
|
|
act_ref->name);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
if (act_ref->sub_paths.user || act_ref->sub_paths.any) {
|
2019-09-02 21:04:13 +00:00
|
|
|
#if 0
|
2020-06-15 15:58:48 +00:00
|
|
|
oxr_action_bind_inputs(log, &slog, sess, act,
|
|
|
|
&act_attached->user, user,
|
2019-05-07 12:47:18 +00:00
|
|
|
OXR_SUB_ACTION_PATH_USER);
|
2019-09-02 21:04:13 +00:00
|
|
|
#endif
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
if (act_ref->sub_paths.head || act_ref->sub_paths.any) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_bind_inputs(log, &slog, sess, act,
|
2020-06-15 19:16:38 +00:00
|
|
|
&act_attached->head, head,
|
2019-05-07 12:47:18 +00:00
|
|
|
OXR_SUB_ACTION_PATH_HEAD);
|
|
|
|
}
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
if (act_ref->sub_paths.left || act_ref->sub_paths.any) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_bind_inputs(log, &slog, sess, act,
|
2020-06-15 19:16:38 +00:00
|
|
|
&act_attached->left, left,
|
2019-05-07 12:47:18 +00:00
|
|
|
OXR_SUB_ACTION_PATH_LEFT);
|
|
|
|
}
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
if (act_ref->sub_paths.right || act_ref->sub_paths.any) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_bind_inputs(log, &slog, sess, act,
|
2020-06-15 19:16:38 +00:00
|
|
|
&act_attached->right, right,
|
|
|
|
OXR_SUB_ACTION_PATH_RIGHT);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
if (act_ref->sub_paths.gamepad || act_ref->sub_paths.any) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_bind_inputs(log, &slog, sess, act,
|
2020-06-15 19:16:38 +00:00
|
|
|
&act_attached->gamepad, gamepad,
|
|
|
|
OXR_SUB_ACTION_PATH_GAMEPAD);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
oxr_slog(&slog, "\tDone");
|
|
|
|
|
|
|
|
// Also frees all data.
|
2019-10-22 10:47:25 +00:00
|
|
|
if (sess->sys->inst->debug_bindings) {
|
|
|
|
oxr_log_slog(log, &slog);
|
|
|
|
} else {
|
|
|
|
oxr_slog_abort(&slog);
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
return XR_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_stop_output(struct oxr_logger *log,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_session *sess,
|
2020-06-16 21:31:29 +00:00
|
|
|
struct oxr_action_cache *cache)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
|
|
|
// Set this as stopped.
|
|
|
|
cache->stop_output_time = 0;
|
|
|
|
|
|
|
|
union xrt_output_value value = {0};
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < cache->num_outputs; i++) {
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_output *output = &cache->outputs[i];
|
2019-09-29 10:43:45 +00:00
|
|
|
struct xrt_device *xdev = output->xdev;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-04-16 12:23:12 +00:00
|
|
|
xrt_device_set_output(xdev, output->name, &value);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 15:58:48 +00:00
|
|
|
/*!
|
|
|
|
* Called during xrSyncActions.
|
|
|
|
*
|
|
|
|
* @private @memberof oxr_action_cache
|
|
|
|
*/
|
2019-05-07 12:47:18 +00:00
|
|
|
static void
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_update(struct oxr_logger *log,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_session *sess,
|
2020-06-16 21:31:29 +00:00
|
|
|
struct oxr_action_cache *cache,
|
2019-05-07 12:47:18 +00:00
|
|
|
int64_t time,
|
|
|
|
bool selected)
|
|
|
|
{
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_state last = cache->current;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
if (!selected) {
|
|
|
|
if (cache->stop_output_time > 0) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_stop_output(log, sess, cache);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2019-06-18 19:03:42 +00:00
|
|
|
U_ZERO(&cache->current);
|
2019-05-07 12:47:18 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-01-09 01:11:34 +00:00
|
|
|
if (cache->num_outputs > 0) {
|
|
|
|
cache->current.active = true;
|
|
|
|
if (cache->stop_output_time < time) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_stop_output(log, sess, cache);
|
2020-01-09 01:11:34 +00:00
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (cache->num_inputs > 0) {
|
2019-12-25 14:17:48 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* @todo This logic should be a lot more smarter.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// If the input is not active signal that.
|
|
|
|
if (!cache->inputs[0].input->active) {
|
|
|
|
// Reset all state.
|
|
|
|
U_ZERO(&cache->current);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Signal that the input is active, always set just to be sure.
|
2020-01-08 17:46:10 +00:00
|
|
|
cache->current.active = true;
|
|
|
|
|
2019-10-24 13:29:23 +00:00
|
|
|
/*!
|
2020-06-15 15:58:48 +00:00
|
|
|
* @todo Combine multiple sources for a single subaction path.
|
2019-10-24 13:29:23 +00:00
|
|
|
*/
|
2020-06-15 15:58:48 +00:00
|
|
|
struct oxr_action_input *action_input = &(cache->inputs[0]);
|
|
|
|
struct xrt_input *input = action_input->input;
|
|
|
|
struct oxr_input_value_tagged raw_input = {
|
|
|
|
.type = XRT_GET_INPUT_TYPE(input->name),
|
|
|
|
.value = input->value,
|
|
|
|
};
|
|
|
|
struct oxr_input_value_tagged transformed = {0};
|
|
|
|
if (!oxr_input_transform_process(action_input->transforms,
|
|
|
|
action_input->num_transforms,
|
|
|
|
&raw_input, &transformed)) {
|
|
|
|
// We couldn't transform, how strange. Reset all state.
|
|
|
|
// At this level we don't know what action this is, etc.
|
|
|
|
// so a warning message isn't very helpful.
|
|
|
|
U_ZERO(&cache->current);
|
|
|
|
return;
|
|
|
|
}
|
2019-10-24 13:29:23 +00:00
|
|
|
int64_t timestamp = input->timestamp;
|
|
|
|
bool changed = false;
|
2020-06-15 15:58:48 +00:00
|
|
|
switch (transformed.type) {
|
2019-10-24 13:29:23 +00:00
|
|
|
case XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE:
|
|
|
|
case XRT_INPUT_TYPE_VEC1_MINUS_ONE_TO_ONE: {
|
2020-06-15 15:58:48 +00:00
|
|
|
changed =
|
|
|
|
(transformed.value.vec1.x != last.value.vec1.x);
|
|
|
|
cache->current.value.vec1.x = transformed.value.vec1.x;
|
2019-10-24 13:29:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE: {
|
2020-06-15 15:58:48 +00:00
|
|
|
changed =
|
|
|
|
(transformed.value.vec2.x != last.value.vec2.x) ||
|
|
|
|
(transformed.value.vec2.y != last.value.vec2.y);
|
|
|
|
cache->current.value.vec2.x = transformed.value.vec2.x;
|
|
|
|
cache->current.value.vec2.y = transformed.value.vec2.y;
|
2019-10-24 13:29:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
case XRT_INPUT_TYPE_VEC3_MINUS_ONE_TO_ONE: {
|
2020-06-15 15:58:48 +00:00
|
|
|
changed = (transformed.value.vec3.x != last.vec3.x) ||
|
|
|
|
(transformed.value.vec3.y != last.vec3.y) ||
|
|
|
|
(transformed.value.vec3.z != last.vec3.z);
|
|
|
|
cache->current.vec3.x = transformed.value.vec3.x;
|
|
|
|
cache->current.vec3.y = transformed.value.vec3.y;
|
|
|
|
cache->current.vec3.z = transformed.value.vec3.z;
|
2019-10-24 13:29:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
case XRT_INPUT_TYPE_BOOLEAN: {
|
2020-06-17 10:48:27 +00:00
|
|
|
changed =
|
|
|
|
(transformed.value.boolean != last.value.boolean);
|
|
|
|
cache->current.value.boolean =
|
|
|
|
transformed.value.boolean;
|
2019-10-24 13:29:23 +00:00
|
|
|
break;
|
|
|
|
}
|
2019-10-28 14:57:35 +00:00
|
|
|
case XRT_INPUT_TYPE_POSE: return;
|
2019-10-28 10:56:45 +00:00
|
|
|
default:
|
|
|
|
// Should not end up here.
|
|
|
|
assert(false);
|
2019-10-24 13:29:23 +00:00
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
if (last.active && changed) {
|
2020-06-17 22:27:59 +00:00
|
|
|
// We were active last sync, and we've changed since
|
|
|
|
// then
|
2019-05-07 12:47:18 +00:00
|
|
|
cache->current.timestamp = timestamp;
|
|
|
|
cache->current.changed = true;
|
|
|
|
} else if (last.active) {
|
2020-06-17 22:27:59 +00:00
|
|
|
// We were active last sync, but we haven't changed
|
|
|
|
// since then.
|
2019-05-07 12:47:18 +00:00
|
|
|
cache->current.timestamp = last.timestamp;
|
|
|
|
cache->current.changed = false;
|
|
|
|
} else {
|
2020-06-17 22:27:59 +00:00
|
|
|
// We are active now but weren't active last time.
|
2019-05-07 12:47:18 +00:00
|
|
|
cache->current.timestamp = timestamp;
|
|
|
|
cache->current.changed = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-28 10:56:45 +00:00
|
|
|
#define BOOL_CHECK(NAME) \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->NAME.current.active) { \
|
2019-10-28 10:56:45 +00:00
|
|
|
active |= true; \
|
2020-06-15 19:16:38 +00:00
|
|
|
value |= act_attached->NAME.current.value.boolean; \
|
|
|
|
timestamp = act_attached->NAME.current.timestamp; \
|
2019-10-28 10:56:45 +00:00
|
|
|
}
|
|
|
|
#define VEC1_CHECK(NAME) \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->NAME.current.active) { \
|
2019-10-28 10:56:45 +00:00
|
|
|
active |= true; \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (value < act_attached->NAME.current.value.vec1.x) { \
|
|
|
|
value = act_attached->NAME.current.value.vec1.x; \
|
|
|
|
timestamp = act_attached->NAME.current.timestamp; \
|
2019-10-28 10:56:45 +00:00
|
|
|
} \
|
|
|
|
}
|
|
|
|
#define VEC2_CHECK(NAME) \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->NAME.current.active) { \
|
2019-10-28 10:56:45 +00:00
|
|
|
active |= true; \
|
2020-06-15 19:16:38 +00:00
|
|
|
float curr_x = act_attached->NAME.current.value.vec2.x; \
|
|
|
|
float curr_y = act_attached->NAME.current.value.vec2.y; \
|
2019-10-28 10:56:45 +00:00
|
|
|
float curr_d = curr_x * curr_x + curr_y * curr_y; \
|
|
|
|
if (distance < curr_d) { \
|
|
|
|
x = curr_x; \
|
|
|
|
y = curr_y; \
|
|
|
|
distance = curr_d; \
|
2020-06-15 19:16:38 +00:00
|
|
|
timestamp = act_attached->NAME.current.timestamp; \
|
2019-10-28 10:56:45 +00:00
|
|
|
} \
|
|
|
|
}
|
|
|
|
|
2020-06-15 15:58:48 +00:00
|
|
|
/*!
|
|
|
|
* Called during each xrSyncActions.
|
|
|
|
*
|
|
|
|
* @private @memberof oxr_action_attachment
|
|
|
|
*/
|
2019-05-07 12:47:18 +00:00
|
|
|
static void
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_action_attachment_update(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_action_attachment *act_attached,
|
|
|
|
int64_t time,
|
|
|
|
struct oxr_sub_paths sub_paths)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-02 21:04:13 +00:00
|
|
|
// This really shouldn't be happening.
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached == NULL) {
|
2019-05-07 12:47:18 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-28 10:56:45 +00:00
|
|
|
//! @todo "/user" sub-action path.
|
|
|
|
|
|
|
|
bool select_any = sub_paths.any;
|
2019-05-07 12:47:18 +00:00
|
|
|
bool select_head = sub_paths.head || sub_paths.any;
|
|
|
|
bool select_left = sub_paths.left || sub_paths.any;
|
|
|
|
bool select_right = sub_paths.right || sub_paths.any;
|
|
|
|
bool select_gamepad = sub_paths.gamepad || sub_paths.any;
|
|
|
|
|
2019-10-28 10:56:45 +00:00
|
|
|
// clang-format off
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_update(log, sess, &act_attached->head, time, select_head);
|
|
|
|
oxr_action_cache_update(log, sess, &act_attached->left, time, select_left);
|
|
|
|
oxr_action_cache_update(log, sess, &act_attached->right, time, select_right);
|
|
|
|
oxr_action_cache_update(log, sess, &act_attached->gamepad, time, select_gamepad);
|
2019-10-28 10:56:45 +00:00
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
if (!select_any) {
|
2020-06-15 19:16:38 +00:00
|
|
|
U_ZERO(&act_attached->any_state);
|
2019-10-28 10:56:45 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Any state.
|
|
|
|
*/
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_state last = act_attached->any_state;
|
2019-10-28 10:56:45 +00:00
|
|
|
bool active = false;
|
|
|
|
bool changed = false;
|
|
|
|
XrTime timestamp = 0;
|
|
|
|
|
2020-06-15 23:05:42 +00:00
|
|
|
switch (act_attached->act_ref->action_type) {
|
2019-10-28 10:56:45 +00:00
|
|
|
case XR_ACTION_TYPE_BOOLEAN_INPUT: {
|
|
|
|
bool value = false;
|
|
|
|
BOOL_CHECK(user);
|
|
|
|
BOOL_CHECK(head);
|
|
|
|
BOOL_CHECK(left);
|
|
|
|
BOOL_CHECK(right);
|
|
|
|
BOOL_CHECK(gamepad);
|
|
|
|
|
2020-06-15 18:46:22 +00:00
|
|
|
changed = (last.value.boolean != value);
|
2020-06-15 19:16:38 +00:00
|
|
|
act_attached->any_state.value.boolean = value;
|
2019-10-28 10:56:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XR_ACTION_TYPE_FLOAT_INPUT: {
|
|
|
|
float value = -2.0;
|
|
|
|
VEC1_CHECK(user);
|
|
|
|
VEC1_CHECK(head);
|
|
|
|
VEC1_CHECK(left);
|
|
|
|
VEC1_CHECK(right);
|
|
|
|
VEC1_CHECK(gamepad);
|
|
|
|
|
2020-06-15 18:46:22 +00:00
|
|
|
changed = last.value.vec1.x != value;
|
2020-06-15 19:16:38 +00:00
|
|
|
act_attached->any_state.value.vec1.x = value;
|
2019-10-28 10:56:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
case XR_ACTION_TYPE_VECTOR2F_INPUT: {
|
|
|
|
float x = 0.0;
|
|
|
|
float y = 0.0;
|
|
|
|
float distance = -1.0;
|
|
|
|
VEC2_CHECK(user);
|
|
|
|
VEC2_CHECK(head);
|
|
|
|
VEC2_CHECK(left);
|
|
|
|
VEC2_CHECK(right);
|
|
|
|
VEC2_CHECK(gamepad);
|
|
|
|
|
2020-06-15 18:46:22 +00:00
|
|
|
changed = (last.value.vec2.x != x) || (last.value.vec2.y != y);
|
2020-06-15 19:16:38 +00:00
|
|
|
act_attached->any_state.value.vec2.x = x;
|
|
|
|
act_attached->any_state.value.vec2.y = y;
|
2019-10-28 10:56:45 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
case XR_ACTION_TYPE_POSE_INPUT:
|
|
|
|
case XR_ACTION_TYPE_VIBRATION_OUTPUT:
|
|
|
|
// Nothing to do
|
|
|
|
//! @todo You sure?
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!active) {
|
2020-06-15 19:16:38 +00:00
|
|
|
U_ZERO(&act_attached->any_state);
|
2019-10-28 10:56:45 +00:00
|
|
|
} else if (last.active && changed) {
|
2020-06-15 19:16:38 +00:00
|
|
|
act_attached->any_state.timestamp = timestamp;
|
|
|
|
act_attached->any_state.changed = true;
|
|
|
|
act_attached->any_state.active = true;
|
2019-10-28 10:56:45 +00:00
|
|
|
} else if (last.active) {
|
2020-06-15 19:16:38 +00:00
|
|
|
act_attached->any_state.timestamp = last.timestamp;
|
|
|
|
act_attached->any_state.changed = false;
|
|
|
|
act_attached->any_state.active = true;
|
2019-10-28 10:56:45 +00:00
|
|
|
} else {
|
2020-06-15 19:16:38 +00:00
|
|
|
act_attached->any_state.timestamp = timestamp;
|
|
|
|
act_attached->any_state.changed = false;
|
|
|
|
act_attached->any_state.active = true;
|
2019-10-28 10:56:45 +00:00
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-06-15 15:58:48 +00:00
|
|
|
/*!
|
|
|
|
* Try to produce a transform chain to convert the available input into the
|
|
|
|
* desired input type.
|
|
|
|
*
|
|
|
|
* Populates @p action_input->transforms and @p action_input->num_transforms on
|
|
|
|
* success.
|
|
|
|
*
|
|
|
|
* @returns false if it could not, true if it could
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
oxr_action_populate_input_transform(struct oxr_logger *log,
|
|
|
|
struct oxr_sink_logger *slog,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_action *act,
|
|
|
|
struct oxr_action_input *action_input,
|
|
|
|
XrPath bound_path)
|
|
|
|
{
|
|
|
|
assert(action_input->transforms == NULL);
|
|
|
|
assert(action_input->num_transforms == 0);
|
|
|
|
const char *str;
|
|
|
|
size_t length;
|
|
|
|
oxr_path_get_string(log, sess->sys->inst, bound_path, &str, &length);
|
|
|
|
|
|
|
|
enum xrt_input_type t = XRT_GET_INPUT_TYPE(action_input->input->name);
|
|
|
|
|
|
|
|
return oxr_input_transform_create_chain(
|
|
|
|
log, slog, t, act->data->action_type, act->data->name, str,
|
|
|
|
&action_input->transforms, &action_input->num_transforms);
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
static void
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_bind_inputs(struct oxr_logger *log,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_sink_logger *slog,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_action *act,
|
2020-06-16 21:31:29 +00:00
|
|
|
struct oxr_action_cache *cache,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_interaction_profile *profile,
|
2019-09-02 21:04:13 +00:00
|
|
|
enum oxr_sub_action_path sub_path)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_input inputs[16] = {0};
|
2019-05-07 12:47:18 +00:00
|
|
|
uint32_t num_inputs = 0;
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_output outputs[16] = {0};
|
2019-05-07 12:47:18 +00:00
|
|
|
uint32_t num_outputs = 0;
|
|
|
|
|
2020-06-15 15:58:48 +00:00
|
|
|
//! @todo Should this be asserted to be non-null?
|
2020-05-04 17:05:13 +00:00
|
|
|
XrPath bound_path = XR_NULL_PATH;
|
2019-09-02 21:04:13 +00:00
|
|
|
get_binding(log, slog, sess, act, profile, sub_path, inputs,
|
2020-04-29 03:27:20 +00:00
|
|
|
&num_inputs, outputs, &num_outputs, &bound_path);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
cache->current.active = false;
|
|
|
|
|
|
|
|
if (num_inputs > 0) {
|
|
|
|
cache->current.active = true;
|
|
|
|
cache->inputs =
|
2020-06-15 19:16:38 +00:00
|
|
|
U_TYPED_ARRAY_CALLOC(struct oxr_action_input, num_inputs);
|
2019-05-07 12:47:18 +00:00
|
|
|
for (uint32_t i = 0; i < num_inputs; i++) {
|
2020-06-15 15:58:48 +00:00
|
|
|
if (!oxr_action_populate_input_transform(
|
|
|
|
log, slog, sess, act, &(inputs[i]),
|
|
|
|
bound_path)) {
|
|
|
|
/*!
|
|
|
|
* @todo de-populate this element if we couldn't
|
|
|
|
* get a transform?
|
|
|
|
*/
|
|
|
|
oxr_slog(
|
|
|
|
slog,
|
|
|
|
"Could not populate a transform for %s "
|
|
|
|
"despite it being bound!\n",
|
|
|
|
act->data->name);
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
cache->inputs[i] = inputs[i];
|
|
|
|
}
|
|
|
|
cache->num_inputs = num_inputs;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (num_outputs > 0) {
|
|
|
|
cache->current.active = true;
|
|
|
|
cache->outputs =
|
2020-06-15 19:16:38 +00:00
|
|
|
U_TYPED_ARRAY_CALLOC(struct oxr_action_output, num_outputs);
|
2019-05-07 12:47:18 +00:00
|
|
|
for (uint32_t i = 0; i < num_outputs; i++) {
|
|
|
|
cache->outputs[i] = outputs[i];
|
|
|
|
}
|
|
|
|
cache->num_outputs = num_outputs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Session functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
/*!
|
|
|
|
* Given an Action Set handle, return the @ref oxr_action_set and the associated
|
|
|
|
* @ref oxr_action_set_attachment in the given Session.
|
|
|
|
*
|
|
|
|
* @private @memberof oxr_session
|
|
|
|
*/
|
2019-05-07 12:47:18 +00:00
|
|
|
static void
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_session_get_action_set_attachment(
|
|
|
|
struct oxr_session *sess,
|
|
|
|
XrActionSet actionSet,
|
|
|
|
struct oxr_action_set_attachment **act_set_attached,
|
|
|
|
struct oxr_action_set **act_set)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
void *ptr = NULL;
|
2020-04-28 22:51:39 +00:00
|
|
|
*act_set =
|
|
|
|
XRT_CAST_OXR_HANDLE_TO_PTR(struct oxr_action_set *, actionSet);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
int ret = u_hashmap_int_find(sess->act_sets_attachments_by_key,
|
2020-06-15 22:05:32 +00:00
|
|
|
(*act_set)->act_set_key, &ptr);
|
2019-05-07 12:47:18 +00:00
|
|
|
if (ret == 0) {
|
2020-06-15 19:16:38 +00:00
|
|
|
*act_set_attached = (struct oxr_action_set_attachment *)ptr;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
/*!
|
2020-06-15 22:05:32 +00:00
|
|
|
* Given an action act_key, look up the @ref oxr_action_attachment of the
|
|
|
|
* associated action in the given Session.
|
2020-06-15 19:16:38 +00:00
|
|
|
*
|
|
|
|
* @private @memberof oxr_session
|
|
|
|
*/
|
2019-05-07 12:47:18 +00:00
|
|
|
static void
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_session_get_action_attachment(
|
|
|
|
struct oxr_session *sess,
|
|
|
|
uint32_t act_key,
|
|
|
|
struct oxr_action_attachment **out_act_attached)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
void *ptr = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
int ret =
|
|
|
|
u_hashmap_int_find(sess->act_attachments_by_key, act_key, &ptr);
|
2019-05-07 12:47:18 +00:00
|
|
|
if (ret == 0) {
|
2020-06-15 19:16:38 +00:00
|
|
|
*out_act_attached = (struct oxr_action_attachment *)ptr;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
static inline size_t
|
|
|
|
oxr_handle_base_get_num_children(struct oxr_handle_base *hb)
|
|
|
|
{
|
|
|
|
size_t ret = 0;
|
|
|
|
for (uint32_t i = 0; i < XRT_MAX_HANDLE_CHILDREN; ++i) {
|
|
|
|
if (hb->children[i] != NULL) {
|
|
|
|
++ret;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_session_attach_action_sets(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
const XrSessionActionSetsAttachInfo *bindInfo)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
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;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
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);
|
2020-06-15 21:46:21 +00:00
|
|
|
//! @todo add other subaction paths here
|
|
|
|
|
|
|
|
// Before allocating, make sure nothing has been attached yet.
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
for (uint32_t i = 0; i < bindInfo->countActionSets; i++) {
|
2020-06-15 21:46:21 +00:00
|
|
|
struct oxr_action_set *act_set = XRT_CAST_OXR_HANDLE_TO_PTR(
|
|
|
|
struct oxr_action_set *, bindInfo->actionSets[i]);
|
2020-06-15 23:05:42 +00:00
|
|
|
if (act_set->data->attached) {
|
2020-06-15 21:46:21 +00:00
|
|
|
return XR_ERROR_ACTIONSETS_ALREADY_ATTACHED;
|
|
|
|
}
|
|
|
|
}
|
2019-09-02 21:04:13 +00:00
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
// Allocate room for list.
|
|
|
|
sess->num_action_set_attachments = bindInfo->countActionSets;
|
|
|
|
sess->act_set_attachments = U_TYPED_ARRAY_CALLOC(
|
|
|
|
struct oxr_action_set_attachment, sess->num_action_set_attachments);
|
2019-09-02 21:04:13 +00:00
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
// Set up the per-session data for these action sets.
|
|
|
|
for (uint32_t i = 0; i < sess->num_action_set_attachments; i++) {
|
|
|
|
struct oxr_action_set *act_set = XRT_CAST_OXR_HANDLE_TO_PTR(
|
|
|
|
struct oxr_action_set *, bindInfo->actionSets[i]);
|
2020-06-15 23:05:42 +00:00
|
|
|
struct oxr_action_set_ref *act_set_ref = act_set->data;
|
|
|
|
act_set_ref->attached = true;
|
2020-06-15 21:46:21 +00:00
|
|
|
struct oxr_action_set_attachment *act_set_attached =
|
|
|
|
&sess->act_set_attachments[i];
|
|
|
|
oxr_action_set_attachment_init(log, sess, act_set,
|
|
|
|
act_set_attached);
|
|
|
|
|
|
|
|
// Allocate the action attachments for this set.
|
|
|
|
act_set_attached->num_action_attachments =
|
|
|
|
oxr_handle_base_get_num_children(&act_set->handle);
|
|
|
|
act_set_attached->act_attachments = U_TYPED_ARRAY_CALLOC(
|
|
|
|
struct oxr_action_attachment,
|
|
|
|
act_set_attached->num_action_attachments);
|
|
|
|
|
|
|
|
// Set up the per-session data for the actions.
|
|
|
|
uint32_t child_index = 0;
|
2019-09-02 21:04:13 +00:00
|
|
|
for (uint32_t k = 0; k < XRT_MAX_HANDLE_CHILDREN; k++) {
|
2020-06-15 21:46:21 +00:00
|
|
|
struct oxr_action *act =
|
|
|
|
(struct oxr_action *)act_set->handle.children[k];
|
2019-09-02 21:04:13 +00:00
|
|
|
if (act == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
struct oxr_action_attachment *act_attached =
|
|
|
|
&act_set_attached->act_attachments[child_index];
|
|
|
|
oxr_action_attachment_init(log, act_set_attached,
|
|
|
|
act_attached, act);
|
|
|
|
oxr_action_attachment_bind(log, act_attached, act, head,
|
|
|
|
left, right, NULL);
|
|
|
|
++child_index;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
if (head != NULL) {
|
|
|
|
sess->head = head->path;
|
|
|
|
}
|
|
|
|
if (left != NULL) {
|
|
|
|
sess->left = left->path;
|
|
|
|
}
|
|
|
|
if (right != NULL) {
|
|
|
|
sess->right = right->path;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
sess->actionsAttached = true;
|
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-07-13 16:17:57 +00:00
|
|
|
}
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_sync_data(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
2019-05-07 12:47:18 +00:00
|
|
|
uint32_t countActionSets,
|
2019-09-29 10:43:45 +00:00
|
|
|
const XrActiveActionSet *actionSets)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_action_set *act_set = NULL;
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_set_attachment *act_set_attached = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
// Check that all action sets has been attached.
|
2019-05-07 12:47:18 +00:00
|
|
|
for (uint32_t i = 0; i < countActionSets; i++) {
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_session_get_action_set_attachment(
|
|
|
|
sess, actionSets[i].actionSet, &act_set_attached, &act_set);
|
|
|
|
if (act_set_attached == NULL) {
|
2019-09-02 21:04:13 +00:00
|
|
|
return oxr_error(
|
|
|
|
log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
2020-05-31 12:45:30 +00:00
|
|
|
"(actionSets[%i].actionSet) action set '%s' has "
|
|
|
|
"not been attached to this session",
|
2020-06-15 23:05:42 +00:00
|
|
|
i, act_set != NULL ? act_set->data->name : "NULL");
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
// Synchronize outputs to this time.
|
|
|
|
int64_t now = time_state_get_now(sess->sys->inst->timekeeping);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
// Loop over all xdev devices.
|
|
|
|
for (size_t i = 0; i < sess->sys->num_xdevs; i++) {
|
2020-04-16 12:23:12 +00:00
|
|
|
oxr_xdev_update(sess->sys->xdevs[i]);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
// Reset all action set attachments.
|
|
|
|
for (size_t i = 0; i < sess->num_action_set_attachments; ++i) {
|
|
|
|
act_set_attached = &sess->act_set_attachments[i];
|
2020-06-15 19:16:38 +00:00
|
|
|
U_ZERO(&act_set_attached->requested_sub_paths);
|
2019-10-28 14:57:35 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
// Go over all requested action sets and update their attachment.
|
|
|
|
//! @todo can be listed more than once with different paths!
|
2019-05-07 12:47:18 +00:00
|
|
|
for (uint32_t i = 0; i < countActionSets; i++) {
|
|
|
|
struct oxr_sub_paths sub_paths;
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_session_get_action_set_attachment(
|
|
|
|
sess, actionSets[i].actionSet, &act_set_attached, &act_set);
|
|
|
|
assert(act_set_attached != NULL);
|
|
|
|
|
|
|
|
if (!oxr_classify_sub_action_paths(log, sess->sys->inst, 1,
|
|
|
|
&actionSets[i].subactionPath,
|
|
|
|
&sub_paths)) {
|
|
|
|
return XR_ERROR_PATH_UNSUPPORTED;
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
act_set_attached->requested_sub_paths.any |= sub_paths.any;
|
|
|
|
act_set_attached->requested_sub_paths.user |= sub_paths.user;
|
|
|
|
act_set_attached->requested_sub_paths.head |= sub_paths.head;
|
|
|
|
act_set_attached->requested_sub_paths.left |= sub_paths.left;
|
|
|
|
act_set_attached->requested_sub_paths.right |= sub_paths.right;
|
|
|
|
act_set_attached->requested_sub_paths.gamepad |=
|
|
|
|
sub_paths.gamepad;
|
2019-10-28 14:57:35 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
// Now, update all action attachments
|
|
|
|
for (size_t i = 0; i < sess->num_action_set_attachments; ++i) {
|
|
|
|
act_set_attached = &sess->act_set_attachments[i];
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_sub_paths sub_paths =
|
|
|
|
act_set_attached->requested_sub_paths;
|
2019-10-28 14:57:35 +00:00
|
|
|
|
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
for (uint32_t k = 0;
|
|
|
|
k < act_set_attached->num_action_attachments; k++) {
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_attachment *act_attached =
|
2020-06-15 21:46:21 +00:00
|
|
|
&act_set_attached->act_attachments[k];
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached == NULL) {
|
2019-05-07 12:47:18 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_action_attachment_update(log, sess, act_attached,
|
|
|
|
now, sub_paths);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-10-28 14:57:35 +00:00
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_focused_result(sess);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Action get functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2020-06-17 22:27:59 +00:00
|
|
|
#define OXR_ACTION_GET_XR_STATE_FROM_ACTION_STATE_COMMON(ACTION_STATE, DATA) \
|
|
|
|
do { \
|
2020-06-25 17:18:55 +00:00
|
|
|
DATA->lastChangeTime = time_state_monotonic_to_ts_ns( \
|
|
|
|
inst->timekeeping, ACTION_STATE->timestamp); \
|
2020-06-17 22:27:59 +00:00
|
|
|
DATA->changedSinceLastSync = ACTION_STATE->changed; \
|
|
|
|
DATA->isActive = XR_TRUE; \
|
|
|
|
} while (0)
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
static void
|
2020-06-25 17:18:55 +00:00
|
|
|
get_xr_state_from_action_state_bool(struct oxr_instance *inst,
|
|
|
|
struct oxr_action_state *state,
|
2020-06-17 22:27:59 +00:00
|
|
|
XrActionStateBoolean *data)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-17 22:27:59 +00:00
|
|
|
/* only get here if the action is active! */
|
|
|
|
assert(state->active);
|
|
|
|
OXR_ACTION_GET_XR_STATE_FROM_ACTION_STATE_COMMON(state, data);
|
2020-06-15 18:46:22 +00:00
|
|
|
data->currentState = state->value.boolean;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-06-25 17:18:55 +00:00
|
|
|
get_xr_state_from_action_state_vec1(struct oxr_instance *inst,
|
|
|
|
struct oxr_action_state *state,
|
2020-06-17 22:27:59 +00:00
|
|
|
XrActionStateFloat *data)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-17 22:27:59 +00:00
|
|
|
/* only get here if the action is active! */
|
|
|
|
assert(state->active);
|
|
|
|
OXR_ACTION_GET_XR_STATE_FROM_ACTION_STATE_COMMON(state, data);
|
2020-06-15 15:58:48 +00:00
|
|
|
data->currentState = state->value.vec1.x;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2020-06-25 17:18:55 +00:00
|
|
|
get_xr_state_from_action_state_vec2(struct oxr_instance *inst,
|
|
|
|
struct oxr_action_state *state,
|
2020-06-17 22:27:59 +00:00
|
|
|
XrActionStateVector2f *data)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-17 22:27:59 +00:00
|
|
|
/* only get here if the action is active! */
|
|
|
|
assert(state->active);
|
|
|
|
OXR_ACTION_GET_XR_STATE_FROM_ACTION_STATE_COMMON(state, data);
|
2020-06-15 18:46:22 +00:00
|
|
|
data->currentState.x = state->value.vec2.x;
|
|
|
|
data->currentState.y = state->value.vec2.y;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#define OXR_ACTION_GET_FILLER(TYPE) \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (sub_paths.any && act_attached->any_state.active) { \
|
2020-06-17 22:27:59 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE( \
|
2020-06-25 17:18:55 +00:00
|
|
|
sess->sys->inst, &act_attached->any_state, data); \
|
2019-10-28 10:56:45 +00:00
|
|
|
} \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (sub_paths.user && act_attached->user.current.active) { \
|
2020-06-17 22:27:59 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE( \
|
2020-06-25 17:18:55 +00:00
|
|
|
sess->sys->inst, &act_attached->user.current, data); \
|
2019-05-07 12:47:18 +00:00
|
|
|
} \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (sub_paths.head && act_attached->head.current.active) { \
|
2020-06-17 22:27:59 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE( \
|
2020-06-25 17:18:55 +00:00
|
|
|
sess->sys->inst, &act_attached->head.current, data); \
|
2019-05-07 12:47:18 +00:00
|
|
|
} \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (sub_paths.left && act_attached->left.current.active) { \
|
2020-06-17 22:27:59 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE( \
|
2020-06-25 17:18:55 +00:00
|
|
|
sess->sys->inst, &act_attached->left.current, data); \
|
2019-05-07 12:47:18 +00:00
|
|
|
} \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (sub_paths.right && act_attached->right.current.active) { \
|
2020-06-17 22:27:59 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE( \
|
2020-06-25 17:18:55 +00:00
|
|
|
sess->sys->inst, &act_attached->right.current, data); \
|
2019-05-07 12:47:18 +00:00
|
|
|
} \
|
2020-06-15 19:16:38 +00:00
|
|
|
if (sub_paths.gamepad && act_attached->gamepad.current.active) { \
|
2020-06-17 22:27:59 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE( \
|
2020-06-25 17:18:55 +00:00
|
|
|
sess->sys->inst, &act_attached->gamepad.current, data); \
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2020-06-17 22:27:59 +00:00
|
|
|
/*!
|
|
|
|
* Clear the actual data members of the XrActionState* types, to have the
|
|
|
|
* correct return value in case of the action being not active
|
|
|
|
*/
|
|
|
|
#define OXR_ACTION_RESET_XR_ACTION_STATE(data) \
|
|
|
|
do { \
|
|
|
|
data->isActive = XR_FALSE; \
|
|
|
|
data->changedSinceLastSync = XR_FALSE; \
|
|
|
|
data->lastChangeTime = 0; \
|
|
|
|
U_ZERO(&data->currentState); \
|
|
|
|
} while (0)
|
2019-10-28 10:56:45 +00:00
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_get_boolean(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
2020-06-15 22:05:32 +00:00
|
|
|
uint32_t act_key,
|
2019-05-07 12:47:18 +00:00
|
|
|
struct oxr_sub_paths sub_paths,
|
2019-09-29 10:43:45 +00:00
|
|
|
XrActionStateBoolean *data)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_attachment *act_attached = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 22:05:32 +00:00
|
|
|
oxr_session_get_action_attachment(sess, act_key, &act_attached);
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached == NULL) {
|
2020-05-31 12:45:30 +00:00
|
|
|
return oxr_error(
|
|
|
|
log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
|
|
|
"Action has not been attached to this session");
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-17 22:27:59 +00:00
|
|
|
OXR_ACTION_RESET_XR_ACTION_STATE(data);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
OXR_ACTION_GET_FILLER(bool);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_get_vector1f(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
2020-06-15 22:05:32 +00:00
|
|
|
uint32_t act_key,
|
2019-05-07 12:47:18 +00:00
|
|
|
struct oxr_sub_paths sub_paths,
|
2019-09-29 10:43:45 +00:00
|
|
|
XrActionStateFloat *data)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_attachment *act_attached = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 22:05:32 +00:00
|
|
|
oxr_session_get_action_attachment(sess, act_key, &act_attached);
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached == NULL) {
|
2020-05-31 12:45:30 +00:00
|
|
|
return oxr_error(
|
|
|
|
log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
|
|
|
"Action has not been attached to this session");
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-17 22:27:59 +00:00
|
|
|
OXR_ACTION_RESET_XR_ACTION_STATE(data);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
OXR_ACTION_GET_FILLER(vec1);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_get_vector2f(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
2020-06-15 22:05:32 +00:00
|
|
|
uint32_t act_key,
|
2019-05-07 12:47:18 +00:00
|
|
|
struct oxr_sub_paths sub_paths,
|
2019-09-29 10:43:45 +00:00
|
|
|
XrActionStateVector2f *data)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_attachment *act_attached = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 22:05:32 +00:00
|
|
|
oxr_session_get_action_attachment(sess, act_key, &act_attached);
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached == NULL) {
|
2020-05-31 12:45:30 +00:00
|
|
|
return oxr_error(
|
|
|
|
log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
|
|
|
"Action has not been attached to this session");
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-17 22:27:59 +00:00
|
|
|
OXR_ACTION_RESET_XR_ACTION_STATE(data);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
OXR_ACTION_GET_FILLER(vec2);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_get_pose(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
2020-06-15 22:05:32 +00:00
|
|
|
uint32_t act_key,
|
2019-05-07 12:47:18 +00:00
|
|
|
struct oxr_sub_paths sub_paths,
|
2019-09-29 10:43:45 +00:00
|
|
|
XrActionStatePose *data)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_attachment *act_attached = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 22:05:32 +00:00
|
|
|
oxr_session_get_action_attachment(sess, act_key, &act_attached);
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached == NULL) {
|
2020-05-31 12:45:30 +00:00
|
|
|
return oxr_error(
|
|
|
|
log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
|
|
|
"Action has not been attached to this session");
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2020-05-31 12:45:30 +00:00
|
|
|
data->isActive = XR_FALSE;
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
if (sub_paths.user || sub_paths.any) {
|
2020-06-15 19:16:38 +00:00
|
|
|
data->isActive |= act_attached->user.current.active;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
if (sub_paths.head || sub_paths.any) {
|
2020-06-15 19:16:38 +00:00
|
|
|
data->isActive |= act_attached->head.current.active;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
if (sub_paths.left || sub_paths.any) {
|
2020-06-15 19:16:38 +00:00
|
|
|
data->isActive |= act_attached->left.current.active;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
if (sub_paths.right || sub_paths.any) {
|
2020-06-15 19:16:38 +00:00
|
|
|
data->isActive |= act_attached->right.current.active;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
if (sub_paths.gamepad || sub_paths.any) {
|
2020-06-15 19:16:38 +00:00
|
|
|
data->isActive |= act_attached->gamepad.current.active;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Haptic feedback functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
static void
|
2020-06-15 19:16:38 +00:00
|
|
|
set_action_output_vibration(struct oxr_session *sess,
|
2020-06-16 21:31:29 +00:00
|
|
|
struct oxr_action_cache *cache,
|
2019-05-07 12:47:18 +00:00
|
|
|
int64_t stop,
|
2019-09-29 10:43:45 +00:00
|
|
|
const XrHapticVibration *data)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
|
|
|
cache->stop_output_time = stop;
|
|
|
|
|
|
|
|
union xrt_output_value value = {0};
|
|
|
|
value.vibration.frequency = data->frequency;
|
|
|
|
value.vibration.amplitude = data->amplitude;
|
2020-04-19 22:13:37 +00:00
|
|
|
value.vibration.duration = data->duration;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
for (uint32_t i = 0; i < cache->num_outputs; i++) {
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_output *output = &cache->outputs[i];
|
2019-09-29 10:43:45 +00:00
|
|
|
struct xrt_device *xdev = output->xdev;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-04-16 12:23:12 +00:00
|
|
|
xrt_device_set_output(xdev, output->name, &value);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-07-13 16:17:57 +00:00
|
|
|
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_apply_haptic_feedback(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
2020-06-15 22:05:32 +00:00
|
|
|
uint32_t act_key,
|
2019-07-13 16:17:57 +00:00
|
|
|
struct oxr_sub_paths sub_paths,
|
2019-09-29 10:43:45 +00:00
|
|
|
const XrHapticBaseHeader *hapticEvent)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_attachment *act_attached = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 22:05:32 +00:00
|
|
|
oxr_session_get_action_attachment(sess, act_key, &act_attached);
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached == NULL) {
|
2020-05-31 12:45:30 +00:00
|
|
|
return oxr_error(
|
|
|
|
log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
|
|
|
"Action has not been attached to this session");
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2019-09-29 10:43:45 +00:00
|
|
|
const XrHapticVibration *data = (const XrHapticVibration *)hapticEvent;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
int64_t now = time_state_get_now(sess->sys->inst->timekeeping);
|
|
|
|
int64_t stop = data->duration <= 0 ? now : now + data->duration;
|
|
|
|
|
|
|
|
// clang-format off
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->user.current.active && (sub_paths.user || sub_paths.any)) {
|
|
|
|
set_action_output_vibration(sess, &act_attached->user, stop, data);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->head.current.active && (sub_paths.head || sub_paths.any)) {
|
|
|
|
set_action_output_vibration(sess, &act_attached->head, stop, data);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->left.current.active && (sub_paths.left || sub_paths.any)) {
|
|
|
|
set_action_output_vibration(sess, &act_attached->left, stop, data);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->right.current.active && (sub_paths.right || sub_paths.any)) {
|
|
|
|
set_action_output_vibration(sess, &act_attached->right, stop, data);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->gamepad.current.active && (sub_paths.gamepad || sub_paths.any)) {
|
|
|
|
set_action_output_vibration(sess, &act_attached->gamepad, stop, data);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
// clang-format on
|
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
XrResult
|
2019-09-29 10:43:45 +00:00
|
|
|
oxr_action_stop_haptic_feedback(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
2020-06-15 22:05:32 +00:00
|
|
|
uint32_t act_key,
|
2019-07-13 16:17:57 +00:00
|
|
|
struct oxr_sub_paths sub_paths)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-06-15 19:16:38 +00:00
|
|
|
struct oxr_action_attachment *act_attached = NULL;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-06-15 22:05:32 +00:00
|
|
|
oxr_session_get_action_attachment(sess, act_key, &act_attached);
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached == NULL) {
|
2020-05-31 12:45:30 +00:00
|
|
|
return oxr_error(
|
|
|
|
log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
|
|
|
"Action has not been attached to this session");
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// clang-format off
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->user.current.active && (sub_paths.user || sub_paths.any)) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_stop_output(log, sess, &act_attached->user);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->head.current.active && (sub_paths.head || sub_paths.any)) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_stop_output(log, sess, &act_attached->head);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->left.current.active && (sub_paths.left || sub_paths.any)) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_stop_output(log, sess, &act_attached->left);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->right.current.active && (sub_paths.right || sub_paths.any)) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_stop_output(log, sess, &act_attached->right);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_attached->gamepad.current.active && (sub_paths.gamepad || sub_paths.any)) {
|
2020-06-16 21:31:29 +00:00
|
|
|
oxr_action_cache_stop_output(log, sess, &act_attached->gamepad);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
// clang-format on
|
|
|
|
|
2019-09-26 20:25:05 +00:00
|
|
|
return oxr_session_success_result(sess);
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|