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-07-21 13:57:21 +00:00
|
|
|
#include "oxr_two_call.h"
|
2020-06-15 15:58:48 +00:00
|
|
|
#include "oxr_input_transform.h"
|
2020-07-20 19:53:52 +00:00
|
|
|
#include "oxr_subaction.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-07-28 13:29:31 +00:00
|
|
|
uint32_t countActionSets,
|
|
|
|
const XrActiveActionSet *actionSets,
|
|
|
|
struct oxr_action_attachment *act_attached,
|
2020-06-16 21:31:29 +00:00
|
|
|
struct oxr_action_cache *cache,
|
2019-05-07 12:47:18 +00:00
|
|
|
int64_t time,
|
2020-07-28 13:29:31 +00:00
|
|
|
struct oxr_sub_paths *sub_path,
|
2019-05-07 12:47:18 +00:00
|
|
|
bool select);
|
|
|
|
|
|
|
|
static void
|
2020-06-15 19:16:38 +00:00
|
|
|
oxr_action_attachment_update(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
2020-07-28 13:29:31 +00:00
|
|
|
uint32_t countActionSets,
|
|
|
|
const XrActiveActionSet *actionSets,
|
2020-06-15 19:16:38 +00:00
|
|
|
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-08-18 15:11:15 +00:00
|
|
|
oxr_action_bind_io(struct oxr_logger *log,
|
|
|
|
struct oxr_sink_logger *slog,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_action *act,
|
|
|
|
struct oxr_action_cache *cache,
|
|
|
|
struct oxr_interaction_profile *profile,
|
|
|
|
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-07-22 21:25:49 +00:00
|
|
|
|
|
|
|
#define CACHE_TEARDOWN(X) oxr_action_cache_teardown(&(act_attached->X));
|
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(CACHE_TEARDOWN)
|
|
|
|
#undef CACHE_TEARDOWN
|
|
|
|
|
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);
|
|
|
|
|
2020-07-28 13:29:31 +00:00
|
|
|
act_set_ref->priority = createInfo->priority;
|
|
|
|
|
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];
|
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
#define IDENTIFY_PATH(X) \
|
|
|
|
else if (path == inst->path_cache.X) \
|
|
|
|
{ \
|
|
|
|
sub_paths->X = true; \
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
if (path == XR_NULL_PATH) {
|
|
|
|
sub_paths->any = true;
|
2020-07-20 19:53:52 +00:00
|
|
|
}
|
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(IDENTIFY_PATH) else
|
|
|
|
{
|
2019-05-07 12:47:18 +00:00
|
|
|
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-07-20 19:53:52 +00:00
|
|
|
#undef IDENTIFY_PATH
|
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,
|
2020-08-27 13:01:49 +00:00
|
|
|
const struct oxr_sub_paths *sub_paths_ptr,
|
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;
|
|
|
|
}
|
|
|
|
|
2020-08-27 13:01:49 +00:00
|
|
|
struct oxr_sub_paths sub_paths = *sub_paths_ptr;
|
|
|
|
if (sub_paths.any) {
|
|
|
|
sub_paths = act_attached->any_pose_sub_path;
|
|
|
|
}
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
// Priority of inputs.
|
2020-07-22 21:25:49 +00:00
|
|
|
#define GET_POSE_INPUT(X) \
|
2020-08-27 13:01:49 +00:00
|
|
|
if (act_attached->X.current.active && sub_paths.X) { \
|
2020-07-22 21:25:49 +00:00
|
|
|
*out_input = act_attached->X.inputs; \
|
|
|
|
return XR_SUCCESS; \
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-07-22 21:25:49 +00:00
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(GET_POSE_INPUT)
|
|
|
|
|
|
|
|
// plus a fallback invocation for user
|
|
|
|
GET_POSE_INPUT(user)
|
|
|
|
#undef GET_POSE_INPUT
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
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
|
2020-11-03 19:33:52 +00:00
|
|
|
do_inputs(struct oxr_binding *binding_point,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct xrt_device *xdev,
|
2020-11-03 19:33:52 +00:00
|
|
|
struct xrt_binding_profile *xbp,
|
2020-07-21 22:21:28 +00:00
|
|
|
XrPath matched_path,
|
|
|
|
struct oxr_action_input inputs[OXR_MAX_BINDINGS_PER_ACTION],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_inputs)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-11-03 19:33:52 +00:00
|
|
|
enum xrt_input_name name = 0;
|
|
|
|
if (xbp == NULL) {
|
|
|
|
name = binding_point->input;
|
|
|
|
} else {
|
|
|
|
for (size_t i = 0; i < xbp->num_inputs; i++) {
|
|
|
|
if (binding_point->input != xbp->inputs[i].from) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have found a device mapping.
|
|
|
|
name = xbp->inputs[i].device;
|
|
|
|
break;
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
2020-11-03 19:33:52 +00:00
|
|
|
|
|
|
|
// Didn't find a mapping.
|
|
|
|
if (name == 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
struct xrt_input *input = NULL;
|
|
|
|
if (oxr_xdev_find_input(xdev, name, &input)) {
|
|
|
|
uint32_t index = (*num_inputs)++;
|
|
|
|
inputs[index].input = input;
|
|
|
|
inputs[index].xdev = xdev;
|
|
|
|
inputs[index].bound_path = matched_path;
|
|
|
|
return true;
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
|
|
|
|
2020-11-03 19:33:52 +00:00
|
|
|
return false;
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2020-11-03 19:33:52 +00:00
|
|
|
do_outputs(struct oxr_binding *binding_point,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct xrt_device *xdev,
|
2020-11-03 19:33:52 +00:00
|
|
|
struct xrt_binding_profile *xbp,
|
2020-07-21 22:21:28 +00:00
|
|
|
XrPath matched_path,
|
|
|
|
struct oxr_action_output outputs[OXR_MAX_BINDINGS_PER_ACTION],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_outputs)
|
2019-09-02 21:04:13 +00:00
|
|
|
{
|
2020-11-03 19:33:52 +00:00
|
|
|
enum xrt_output_name name = 0;
|
|
|
|
if (xbp == NULL) {
|
|
|
|
name = binding_point->output;
|
|
|
|
} else {
|
|
|
|
for (size_t i = 0; i < xbp->num_outputs; i++) {
|
|
|
|
if (binding_point->output != xbp->outputs[i].from) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// We have found a device mapping.
|
|
|
|
name = xbp->outputs[i].device;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Didn't find a mapping.
|
|
|
|
if (name == 0) {
|
|
|
|
return false;
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-03 19:33:52 +00:00
|
|
|
struct xrt_output *output = NULL;
|
|
|
|
if (oxr_xdev_find_output(xdev, name, &output)) {
|
|
|
|
uint32_t index = (*num_outputs)++;
|
|
|
|
outputs[index].name = name;
|
|
|
|
outputs[index].xdev = xdev;
|
|
|
|
outputs[index].bound_path = matched_path;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
|
|
|
|
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
|
2020-11-03 19:33:52 +00:00
|
|
|
do_io_bindings(struct oxr_binding *binding_point,
|
2019-09-29 10:43:45 +00:00
|
|
|
struct oxr_action *act,
|
|
|
|
struct xrt_device *xdev,
|
2020-11-03 19:33:52 +00:00
|
|
|
struct xrt_binding_profile *xbp,
|
2020-07-21 22:21:28 +00:00
|
|
|
XrPath matched_path,
|
|
|
|
struct oxr_action_input inputs[OXR_MAX_BINDINGS_PER_ACTION],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_inputs,
|
2020-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_output outputs[OXR_MAX_BINDINGS_PER_ACTION],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_outputs)
|
2019-09-02 21:04:13 +00:00
|
|
|
{
|
2020-06-15 23:05:42 +00:00
|
|
|
if (act->data->action_type == XR_ACTION_TYPE_VIBRATION_OUTPUT) {
|
2020-11-03 19:33:52 +00:00
|
|
|
return do_outputs( //
|
|
|
|
binding_point, //
|
|
|
|
xdev, //
|
|
|
|
xbp, //
|
|
|
|
matched_path, //
|
|
|
|
outputs, //
|
|
|
|
num_outputs); //
|
2019-09-02 21:04:13 +00:00
|
|
|
} else {
|
2020-11-03 19:33:52 +00:00
|
|
|
return do_inputs( //
|
|
|
|
binding_point, //
|
|
|
|
xdev, //
|
|
|
|
xbp, //
|
|
|
|
matched_path, //
|
|
|
|
inputs, //
|
|
|
|
num_inputs); //
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct xrt_binding_profile *
|
|
|
|
get_matching_binding_profile(struct oxr_interaction_profile *profile,
|
|
|
|
struct xrt_device *xdev)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < xdev->num_binding_profiles; i++) {
|
|
|
|
if (xdev->binding_profiles[i].name == profile->xname) {
|
|
|
|
return &xdev->binding_profiles[i];
|
|
|
|
}
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
|
|
|
|
2020-11-03 19:33:52 +00:00
|
|
|
return NULL;
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
|
|
|
|
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-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_input inputs[OXR_MAX_BINDINGS_PER_ACTION],
|
2019-09-29 10:43:45 +00:00
|
|
|
uint32_t *num_inputs,
|
2020-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_output outputs[OXR_MAX_BINDINGS_PER_ACTION],
|
|
|
|
uint32_t *num_outputs)
|
2019-09-02 21:04:13 +00:00
|
|
|
{
|
2019-09-29 10:43:45 +00:00
|
|
|
struct xrt_device *xdev = NULL;
|
2020-11-03 19:33:52 +00:00
|
|
|
struct oxr_binding *binding_points[OXR_MAX_BINDINGS_PER_ACTION];
|
2019-09-29 10:43:45 +00:00
|
|
|
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) {
|
2020-07-22 21:25:49 +00:00
|
|
|
#define PATH_CASE(NAME, NAMECAPS, PATH) \
|
|
|
|
case OXR_SUB_ACTION_PATH_##NAMECAPS: \
|
|
|
|
user_path_str = PATH; \
|
|
|
|
xdev = GET_XDEV_BY_ROLE(sess->sys, NAME); \
|
|
|
|
break;
|
|
|
|
|
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH_DETAILED(PATH_CASE)
|
|
|
|
#undef PATH_CASE
|
|
|
|
|
|
|
|
// Manually-coded fallback for not-really-valid /user
|
2019-09-02 21:04:13 +00:00
|
|
|
case OXR_SUB_ACTION_PATH_USER:
|
|
|
|
user_path_str = "/user";
|
|
|
|
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);
|
|
|
|
|
2020-11-03 19:33:52 +00:00
|
|
|
/*!
|
|
|
|
* Lookup device binding that matches the interactive profile, this
|
|
|
|
* is used as a fallback should the device not match the interactive
|
|
|
|
* profile. This allows the device to provide a mapping from one device
|
|
|
|
* to itself.
|
|
|
|
*/
|
|
|
|
struct xrt_binding_profile *xbp =
|
|
|
|
get_matching_binding_profile(profile, xdev);
|
|
|
|
|
|
|
|
// No point in proceeding here without either.
|
|
|
|
if (profile->xname != xdev->name && xbp == NULL) {
|
|
|
|
oxr_slog(slog,
|
|
|
|
"\t\t\tProfile not for device and no xbp fallback!\n");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
size_t num = 0;
|
2020-11-03 19:33:52 +00:00
|
|
|
oxr_binding_find_bindings_from_key(log, profile, act->act_key,
|
|
|
|
binding_points, &num);
|
2019-09-02 21:04:13 +00:00
|
|
|
if (num == 0) {
|
2020-11-03 19:33:52 +00:00
|
|
|
oxr_slog(slog, "\t\t\tNo bindings!\n");
|
2019-09-02 21:04:13 +00:00
|
|
|
return;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-11-03 19:33:52 +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;
|
2020-11-03 19:33:52 +00:00
|
|
|
struct oxr_binding *binding_point = binding_points[i];
|
2019-09-02 21:04:13 +00:00
|
|
|
|
2020-11-03 19:33:52 +00:00
|
|
|
XrPath matched_path = get_matched_xrpath(binding_point, 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);
|
|
|
|
|
2020-11-03 19:33:52 +00:00
|
|
|
if (binding_point->sub_path != sub_path) {
|
2019-09-02 21:04:13 +00:00
|
|
|
oxr_slog(slog, "\t\t\t\tRejected! (SUB PATH)\n");
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-11-03 19:33:52 +00:00
|
|
|
bool found = do_io_bindings( //
|
|
|
|
binding_point, //
|
|
|
|
act, //
|
|
|
|
xdev, //
|
|
|
|
xbp, //
|
|
|
|
matched_path, //
|
|
|
|
inputs, //
|
|
|
|
num_inputs, //
|
|
|
|
outputs, //
|
|
|
|
num_outputs); //
|
2019-09-02 21:04:13 +00:00
|
|
|
|
|
|
|
if (found) {
|
2020-11-03 19:33:52 +00:00
|
|
|
if (xbp == NULL) {
|
|
|
|
oxr_slog(slog, "\t\t\t\tBound (xdev)!\n");
|
|
|
|
} else {
|
|
|
|
oxr_slog(slog, "\t\t\t\tBound (xbp)!\n");
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (xbp == NULL) {
|
|
|
|
oxr_slog(slog, "\t\t\t\tRejected! (NO XDEV NAME)\n");
|
2019-09-02 21:04:13 +00:00
|
|
|
} else {
|
2020-11-03 19:33:52 +00:00
|
|
|
oxr_slog(slog, "\t\t\t\tRejected! (NO XBINDING)\n");
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-07-22 21:25:49 +00:00
|
|
|
struct oxr_profiles_per_subaction
|
|
|
|
{
|
|
|
|
#define PROFILE_MEMBER(X) struct oxr_interaction_profile *X;
|
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(PROFILE_MEMBER)
|
|
|
|
#undef PROFILE_MEMBER
|
|
|
|
};
|
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,
|
2020-07-22 21:25:49 +00:00
|
|
|
const struct oxr_profiles_per_subaction *profiles)
|
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-08-18 15:11:15 +00:00
|
|
|
oxr_action_bind_io(log, &slog, sess, act, &act_attached->user,
|
|
|
|
user, OXR_SUB_ACTION_PATH_USER);
|
2019-09-02 21:04:13 +00:00
|
|
|
#endif
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
#define BIND_SUBACTION(NAME, NAME_CAPS, PATH) \
|
|
|
|
if (act_ref->sub_paths.NAME || act_ref->sub_paths.any) { \
|
2020-08-18 15:11:15 +00:00
|
|
|
oxr_action_bind_io(log, &slog, sess, act, &act_attached->NAME, \
|
|
|
|
profiles->NAME, \
|
|
|
|
OXR_SUB_ACTION_PATH_##NAME_CAPS); \
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-07-20 19:53:52 +00:00
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH_DETAILED(BIND_SUBACTION)
|
|
|
|
#undef BIND_SUBACTION
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-08-27 13:01:49 +00:00
|
|
|
|
|
|
|
/*!
|
|
|
|
* The any sub path is special cased for poses, it binds to one sub path
|
|
|
|
* and sticks with it.
|
|
|
|
*/
|
|
|
|
if (act_ref->action_type == XR_ACTION_TYPE_POSE_INPUT) {
|
|
|
|
|
2020-10-14 23:07:42 +00:00
|
|
|
#define POSE_ANY(NAME) \
|
|
|
|
if ((act_ref->sub_paths.NAME || act_ref->sub_paths.any) && \
|
|
|
|
act_attached->NAME.num_inputs > 0) { \
|
|
|
|
act_attached->any_pose_sub_path.NAME = true; \
|
|
|
|
oxr_slog(&slog, "\tFor: <any>\n\t\tBinding any pose to " #NAME \
|
|
|
|
".\n"); \
|
2020-08-27 13:01:49 +00:00
|
|
|
} else
|
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(POSE_ANY)
|
|
|
|
#undef POSE_ANY
|
|
|
|
|
|
|
|
{
|
|
|
|
oxr_slog(&slog,
|
|
|
|
"\tFor: <any>\n\t\tNo active sub paths for "
|
|
|
|
"the any pose!\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-07-21 17:36:17 +00:00
|
|
|
static bool
|
2020-07-28 13:29:31 +00:00
|
|
|
oxr_input_is_input_for_cache(struct oxr_action_input *action_input,
|
|
|
|
struct oxr_action_cache *cache)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < cache->num_inputs; i++) {
|
|
|
|
if (action_input->bound_path == cache->inputs[i].bound_path) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
oxr_input_is_bound_in_act_set(
|
|
|
|
struct oxr_action_input *action_input,
|
|
|
|
struct oxr_action_set_attachment *act_set_attached)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < act_set_attached->num_action_attachments; i++) {
|
|
|
|
struct oxr_action_attachment *act_attached =
|
|
|
|
&act_set_attached->act_attachments[i];
|
|
|
|
|
|
|
|
#define ACCUMULATE_PATHS(X) \
|
|
|
|
if (oxr_input_is_input_for_cache(action_input, &act_attached->X)) { \
|
|
|
|
return true; \
|
|
|
|
}
|
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_PATHS)
|
|
|
|
#undef ACCUMULATE_PATHS
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
oxr_input_supressed(struct oxr_session *sess,
|
|
|
|
uint32_t countActionSets,
|
|
|
|
const XrActiveActionSet *actionSets,
|
|
|
|
struct oxr_sub_paths *sub_path,
|
|
|
|
struct oxr_action_attachment *act_attached,
|
|
|
|
struct oxr_action_input *action_input)
|
|
|
|
{
|
|
|
|
struct oxr_action_set_ref *act_set_ref =
|
|
|
|
act_attached->act_set_attached->act_set_ref;
|
|
|
|
uint32_t priority = act_set_ref->priority;
|
|
|
|
|
|
|
|
// find sources that are bound to an action in a set with higher prio
|
|
|
|
for (uint32_t i = 0; i < countActionSets; i++) {
|
|
|
|
XrActionSet set = actionSets[i].actionSet;
|
|
|
|
|
|
|
|
struct oxr_action_set *other_act_set = NULL;
|
|
|
|
struct oxr_action_set_attachment *other_act_set_attached = NULL;
|
|
|
|
oxr_session_get_action_set_attachment(
|
|
|
|
sess, set, &other_act_set_attached, &other_act_set);
|
|
|
|
|
|
|
|
if (other_act_set_attached == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* skip the action set that the current action is in */
|
|
|
|
if (other_act_set_attached->act_set_ref == act_set_ref) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* input may be suppressed by action set with higher prio */
|
|
|
|
if (other_act_set_attached->act_set_ref->priority <= priority) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Currently updated input source with subpath X can be
|
|
|
|
* suppressed, if input source also occurs in action set with
|
|
|
|
* higher priority if
|
|
|
|
* - high prio set syncs w/ ANY subpath or
|
|
|
|
* - high prio set syncs w/ subpath matching this input subpath
|
|
|
|
*/
|
|
|
|
bool relevant_subpath =
|
|
|
|
other_act_set_attached->requested_sub_paths.any;
|
|
|
|
|
|
|
|
#define ACCUMULATE_PATHS(X) \
|
|
|
|
relevant_subpath |= \
|
|
|
|
(other_act_set_attached->requested_sub_paths.X && sub_path->X);
|
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_PATHS)
|
|
|
|
#undef ACCUMULATE_PATHS
|
|
|
|
|
|
|
|
if (!relevant_subpath) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oxr_input_is_bound_in_act_set(action_input,
|
|
|
|
other_act_set_attached)) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
|
|
|
oxr_input_combine_input(struct oxr_session *sess,
|
|
|
|
uint32_t countActionSets,
|
|
|
|
const XrActiveActionSet *actionSets,
|
|
|
|
struct oxr_action_attachment *act_attached,
|
|
|
|
struct oxr_sub_paths *sub_path,
|
|
|
|
struct oxr_action_cache *cache,
|
2020-07-21 17:36:17 +00:00
|
|
|
struct oxr_input_value_tagged *out_input,
|
|
|
|
int64_t *timestamp,
|
|
|
|
bool *is_active)
|
|
|
|
{
|
2020-07-28 13:29:31 +00:00
|
|
|
struct oxr_action_input *inputs = cache->inputs;
|
|
|
|
size_t num_inputs = cache->num_inputs;
|
|
|
|
|
2020-07-21 17:36:17 +00:00
|
|
|
if (num_inputs == 0) {
|
|
|
|
*is_active = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool any_active = false;
|
|
|
|
struct oxr_input_value_tagged res = {0};
|
|
|
|
int64_t res_timestamp = inputs[0].input->timestamp;
|
|
|
|
|
|
|
|
for (size_t i = 0; i < num_inputs; i++) {
|
|
|
|
struct oxr_action_input *action_input = &(inputs[i]);
|
|
|
|
struct xrt_input *input = action_input->input;
|
|
|
|
|
2020-07-28 13:29:31 +00:00
|
|
|
// suppress input if it is also bound to action in set with
|
|
|
|
// higher priority
|
|
|
|
if (oxr_input_supressed(sess, countActionSets, actionSets,
|
|
|
|
sub_path, act_attached, action_input)) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-07-21 17:36:17 +00:00
|
|
|
if (input->active) {
|
|
|
|
any_active = true;
|
|
|
|
} else {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// at this stage type should be "compatible" to action
|
|
|
|
res.type = transformed.type;
|
|
|
|
|
|
|
|
switch (transformed.type) {
|
|
|
|
case XRT_INPUT_TYPE_BOOLEAN:
|
|
|
|
res.value.boolean |= transformed.value.boolean;
|
|
|
|
|
|
|
|
/* Special case bool: all bool inputs are combined with
|
|
|
|
* OR. The action only changes to true on the earliest
|
|
|
|
* input that sets it to true, and to false on the
|
|
|
|
* latest input that is false. */
|
|
|
|
if (res.value.boolean && transformed.value.boolean &&
|
|
|
|
input->timestamp < res_timestamp) {
|
|
|
|
res_timestamp = input->timestamp;
|
|
|
|
} else if (!res.value.boolean &&
|
|
|
|
!transformed.value.boolean &&
|
|
|
|
input->timestamp > res_timestamp) {
|
|
|
|
res_timestamp = input->timestamp;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XRT_INPUT_TYPE_VEC1_MINUS_ONE_TO_ONE:
|
|
|
|
case XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE:
|
2020-08-06 14:29:37 +00:00
|
|
|
if (fabsf(transformed.value.vec1.x) >
|
|
|
|
fabsf(res.value.vec1.x)) {
|
2020-07-21 17:36:17 +00:00
|
|
|
res.value.vec1.x = transformed.value.vec1.x;
|
|
|
|
res_timestamp = input->timestamp;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE: {
|
|
|
|
float res_sq = res.value.vec2.x * res.value.vec2.x +
|
|
|
|
res.value.vec2.y * res.value.vec2.y;
|
|
|
|
float trans_sq =
|
|
|
|
transformed.value.vec2.x *
|
|
|
|
transformed.value.vec2.x +
|
|
|
|
transformed.value.vec2.y * transformed.value.vec2.y;
|
|
|
|
if (trans_sq > res_sq) {
|
|
|
|
res.value.vec2 = transformed.value.vec2;
|
|
|
|
res_timestamp = input->timestamp;
|
|
|
|
}
|
|
|
|
} break;
|
2020-08-06 14:29:37 +00:00
|
|
|
case XRT_INPUT_TYPE_VEC3_MINUS_ONE_TO_ONE:
|
|
|
|
// OpenXR has no vec3 right now.
|
|
|
|
break;
|
2020-07-21 17:36:17 +00:00
|
|
|
case XRT_INPUT_TYPE_POSE:
|
|
|
|
// shouldn't be possible to get here
|
|
|
|
break;
|
2020-10-12 00:09:19 +00:00
|
|
|
case XRT_INPUT_TYPE_HAND_TRACKING:
|
|
|
|
// shouldn't be possible to get here
|
|
|
|
break;
|
2020-07-21 17:36:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*is_active = any_active;
|
|
|
|
*out_input = res;
|
|
|
|
*timestamp = res_timestamp;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
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-07-28 13:29:31 +00:00
|
|
|
uint32_t countActionSets,
|
|
|
|
const XrActiveActionSet *actionSets,
|
|
|
|
struct oxr_action_attachment *act_attached,
|
2020-06-16 21:31:29 +00:00
|
|
|
struct oxr_action_cache *cache,
|
2019-05-07 12:47:18 +00:00
|
|
|
int64_t time,
|
2020-07-28 13:29:31 +00:00
|
|
|
struct oxr_sub_paths *sub_path,
|
2019-05-07 12:47:18 +00:00
|
|
|
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-07-21 22:39:55 +00:00
|
|
|
struct oxr_input_value_tagged combined;
|
|
|
|
int64_t timestamp;
|
|
|
|
bool is_active;
|
|
|
|
|
|
|
|
/* a cache can only have outputs or inputs, not both */
|
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
|
|
|
}
|
2020-07-28 13:29:31 +00:00
|
|
|
} else if (cache->num_inputs > 0) {
|
|
|
|
|
|
|
|
if (!oxr_input_combine_input(
|
|
|
|
sess, countActionSets, actionSets, act_attached,
|
|
|
|
sub_path, cache, &combined, ×tamp, &is_active)) {
|
2020-08-18 15:11:39 +00:00
|
|
|
oxr_log(log, "Failed to get/combine input values '%s'",
|
|
|
|
act_attached->act_ref->name);
|
2020-07-28 13:29:31 +00:00
|
|
|
return;
|
|
|
|
}
|
2019-12-25 14:17:48 +00:00
|
|
|
|
|
|
|
// If the input is not active signal that.
|
2020-07-21 17:36:17 +00:00
|
|
|
if (!is_active) {
|
2019-12-25 14:17:48 +00:00
|
|
|
// 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
|
|
|
bool changed = false;
|
2020-07-21 17:36:17 +00:00
|
|
|
switch (combined.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-07-21 17:36:17 +00:00
|
|
|
changed = (combined.value.vec1.x != last.value.vec1.x);
|
|
|
|
cache->current.value.vec1.x = combined.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 =
|
2020-07-21 17:36:17 +00:00
|
|
|
(combined.value.vec2.x != last.value.vec2.x) ||
|
|
|
|
(combined.value.vec2.y != last.value.vec2.y);
|
|
|
|
cache->current.value.vec2.x = combined.value.vec2.x;
|
|
|
|
cache->current.value.vec2.y = combined.value.vec2.y;
|
2019-10-24 13:29:23 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
#if 0
|
|
|
|
case XRT_INPUT_TYPE_VEC3_MINUS_ONE_TO_ONE: {
|
2020-07-21 17:36:17 +00:00
|
|
|
changed = (combined.value.vec3.x != last.vec3.x) ||
|
|
|
|
(combined.value.vec3.y != last.vec3.y) ||
|
|
|
|
(combined.value.vec3.z != last.vec3.z);
|
|
|
|
cache->current.vec3.x = combined.value.vec3.x;
|
|
|
|
cache->current.vec3.y = combined.value.vec3.y;
|
|
|
|
cache->current.vec3.z = combined.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 =
|
2020-07-21 17:36:17 +00:00
|
|
|
(combined.value.boolean != last.value.boolean);
|
|
|
|
cache->current.value.boolean = combined.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,
|
2020-07-28 13:29:31 +00:00
|
|
|
uint32_t countActionSets,
|
|
|
|
const XrActiveActionSet *actionSets,
|
2020-06-15 19:16:38 +00:00
|
|
|
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.
|
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
#define UPDATE_SELECT(X) \
|
2020-07-28 13:29:31 +00:00
|
|
|
struct oxr_sub_paths sub_paths_##X = {0}; \
|
|
|
|
sub_paths_##X.X = true; \
|
2020-07-20 19:53:52 +00:00
|
|
|
bool select_##X = sub_paths.X || sub_paths.any; \
|
2020-07-28 13:29:31 +00:00
|
|
|
oxr_action_cache_update(log, sess, countActionSets, actionSets, \
|
|
|
|
act_attached, &act_attached->X, time, \
|
|
|
|
&sub_paths_##X, select_##X);
|
2020-07-20 19:53:52 +00:00
|
|
|
|
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(UPDATE_SELECT)
|
|
|
|
#undef UPDATE_SELECT
|
2019-10-28 10:56:45 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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;
|
2020-07-22 21:25:49 +00:00
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(BOOL_CHECK)
|
2019-10-28 10:56:45 +00:00
|
|
|
|
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: {
|
2020-08-06 14:29:37 +00:00
|
|
|
// Smaller than any possible real value
|
|
|
|
float value = -2.0f; // NOLINT
|
2020-07-22 21:25:49 +00:00
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(VEC1_CHECK)
|
2019-10-28 10:56:45 +00:00
|
|
|
|
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: {
|
2020-08-06 14:29:37 +00:00
|
|
|
float x = 0.0f;
|
|
|
|
float y = 0.0f;
|
|
|
|
float distance = -1.0f;
|
2020-07-22 21:25:49 +00:00
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(VEC2_CHECK)
|
2019-10-28 10:56:45 +00:00
|
|
|
|
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,
|
2020-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_input *action_input)
|
2020-06-15 15:58:48 +00:00
|
|
|
{
|
|
|
|
assert(action_input->transforms == NULL);
|
|
|
|
assert(action_input->num_transforms == 0);
|
|
|
|
const char *str;
|
|
|
|
size_t length;
|
2020-07-21 22:21:28 +00:00
|
|
|
oxr_path_get_string(log, sess->sys->inst, action_input->bound_path,
|
|
|
|
&str, &length);
|
2020-06-15 15:58:48 +00:00
|
|
|
|
|
|
|
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-08-18 15:11:15 +00:00
|
|
|
oxr_action_bind_io(struct oxr_logger *log,
|
|
|
|
struct oxr_sink_logger *slog,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
struct oxr_action *act,
|
|
|
|
struct oxr_action_cache *cache,
|
|
|
|
struct oxr_interaction_profile *profile,
|
|
|
|
enum oxr_sub_action_path sub_path)
|
2019-05-07 12:47:18 +00:00
|
|
|
{
|
2020-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_input inputs[OXR_MAX_BINDINGS_PER_ACTION] = {0};
|
2019-05-07 12:47:18 +00:00
|
|
|
uint32_t num_inputs = 0;
|
2020-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_output outputs[OXR_MAX_BINDINGS_PER_ACTION] = {0};
|
2019-05-07 12:47:18 +00:00
|
|
|
uint32_t num_outputs = 0;
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
get_binding(log, slog, sess, act, profile, sub_path, inputs,
|
2020-07-21 22:21:28 +00:00
|
|
|
&num_inputs, outputs, &num_outputs);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
cache->current.active = false;
|
|
|
|
|
|
|
|
if (num_inputs > 0) {
|
2020-08-18 15:11:15 +00:00
|
|
|
uint32_t count = 0;
|
2019-05-07 12:47:18 +00:00
|
|
|
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-08-18 15:11:15 +00:00
|
|
|
|
|
|
|
// Only add the input if we can find a transform.
|
|
|
|
if (oxr_action_populate_input_transform(
|
2020-07-21 22:21:28 +00:00
|
|
|
log, slog, sess, act, &(inputs[i]))) {
|
2020-08-18 15:11:15 +00:00
|
|
|
cache->inputs[count++] = inputs[i];
|
|
|
|
continue;
|
2020-06-15 15:58:48 +00:00
|
|
|
}
|
2020-08-18 15:11:15 +00:00
|
|
|
|
|
|
|
oxr_slog(slog, "\t\t\t\tRejected! (NO TRANSFORM)\n");
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-08-18 15:11:15 +00:00
|
|
|
|
|
|
|
// No inputs found, prented we never bound it.
|
|
|
|
if (count == 0) {
|
|
|
|
free(cache->inputs);
|
|
|
|
cache->inputs = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
cache->num_inputs = count;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2020-07-06 18:58:17 +00:00
|
|
|
*act_set_attached = NULL;
|
|
|
|
|
|
|
|
// In case no action_sets have been attached.
|
|
|
|
if (sess->act_sets_attachments_by_key == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
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;
|
2020-07-22 21:25:49 +00:00
|
|
|
struct oxr_profiles_per_subaction profiles = {0};
|
|
|
|
#define FIND_PROFILE(X) \
|
|
|
|
oxr_find_profile_for_device(log, inst, GET_XDEV_BY_ROLE(sess->sys, X), \
|
|
|
|
&profiles.X);
|
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(FIND_PROFILE)
|
|
|
|
#undef FIND_PROFILE
|
2020-06-15 21:46:21 +00:00
|
|
|
|
2020-07-06 18:58:17 +00:00
|
|
|
// Allocate room for list. No need to check if anything has been
|
|
|
|
// attached the API function does that.
|
2020-06-15 21:46:21 +00:00
|
|
|
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;
|
2020-07-06 18:58:17 +00:00
|
|
|
act_set_ref->ever_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);
|
2020-07-22 21:25:49 +00:00
|
|
|
oxr_action_attachment_bind(log, act_attached, act,
|
|
|
|
&profiles);
|
2020-06-15 21:46:21 +00:00
|
|
|
++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
|
|
|
|
2020-07-22 21:25:49 +00:00
|
|
|
#define POPULATE_PROFILE(X) \
|
|
|
|
if (profiles.X != NULL) { \
|
|
|
|
sess->X = profiles.X->path; \
|
|
|
|
oxr_event_push_XrEventDataInteractionProfileChanged(log, \
|
|
|
|
sess); \
|
2019-09-02 21:04:13 +00:00
|
|
|
}
|
2020-07-22 21:25:49 +00:00
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(POPULATE_PROFILE)
|
|
|
|
#undef POPULATE_PROFILE
|
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;
|
2020-07-20 19:53:52 +00:00
|
|
|
|
2020-07-31 00:48:04 +00:00
|
|
|
/* never error when requesting any subpath */
|
|
|
|
bool any_action_with_subpath = sub_paths.any;
|
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
#define ACCUMULATE_REQUESTED(X) \
|
|
|
|
act_set_attached->requested_sub_paths.X |= sub_paths.X;
|
|
|
|
|
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_REQUESTED)
|
|
|
|
#undef ACCUMULATE_REQUESTED
|
2020-07-31 00:48:04 +00:00
|
|
|
|
|
|
|
/* check if we have at least one action for requested subpath */
|
|
|
|
for (uint32_t k = 0;
|
|
|
|
k < act_set_attached->num_action_attachments; k++) {
|
|
|
|
struct oxr_action_attachment *act_attached =
|
|
|
|
&act_set_attached->act_attachments[k];
|
|
|
|
|
|
|
|
if (act_attached == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define ACCUMULATE_REQUESTED(X) \
|
|
|
|
any_action_with_subpath |= \
|
|
|
|
sub_paths.X && act_attached->act_ref->sub_paths.X;
|
|
|
|
|
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_REQUESTED)
|
|
|
|
#undef ACCUMULATE_REQUESTED
|
|
|
|
}
|
|
|
|
if (!any_action_with_subpath) {
|
|
|
|
return oxr_error(
|
|
|
|
log, XR_ERROR_PATH_UNSUPPORTED,
|
|
|
|
"No action with specified subpath in actionset");
|
|
|
|
}
|
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-07-28 13:29:31 +00:00
|
|
|
oxr_action_attachment_update(log, sess, countActionSets,
|
|
|
|
actionSets, act_attached,
|
2020-06-15 19:16:38 +00:00
|
|
|
now, sub_paths);
|
2019-05-07 12:47:18 +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
|
|
|
}
|
|
|
|
|
2020-07-21 22:21:28 +00:00
|
|
|
static void
|
|
|
|
add_path_to_set(XrPath path_set[OXR_MAX_BINDINGS_PER_ACTION],
|
|
|
|
XrPath new_path,
|
|
|
|
uint32_t *inout_num_paths)
|
|
|
|
{
|
|
|
|
const uint32_t n = *inout_num_paths;
|
|
|
|
|
|
|
|
// Shouldn't be full
|
|
|
|
assert(n < OXR_MAX_BINDINGS_PER_ACTION);
|
|
|
|
|
|
|
|
for (uint32_t i = 0; i < n; ++i) {
|
|
|
|
if (new_path == path_set[i]) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Should have no gaps
|
|
|
|
assert(path_set[i] != 0);
|
|
|
|
}
|
|
|
|
path_set[n] = new_path;
|
|
|
|
(*inout_num_paths)++;
|
|
|
|
}
|
|
|
|
|
2020-07-21 13:57:21 +00:00
|
|
|
XrResult
|
|
|
|
oxr_action_enumerate_bound_sources(struct oxr_logger *log,
|
|
|
|
struct oxr_session *sess,
|
|
|
|
uint32_t act_key,
|
|
|
|
uint32_t sourceCapacityInput,
|
|
|
|
uint32_t *sourceCountOutput,
|
|
|
|
XrPath *sources)
|
|
|
|
{
|
|
|
|
struct oxr_action_attachment *act_attached = NULL;
|
2020-07-21 22:21:28 +00:00
|
|
|
uint32_t num_paths = 0;
|
|
|
|
XrPath temp[OXR_MAX_BINDINGS_PER_ACTION] = {0};
|
2020-07-21 13:57:21 +00:00
|
|
|
|
|
|
|
oxr_session_get_action_attachment(sess, act_key, &act_attached);
|
|
|
|
if (act_attached == NULL) {
|
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE,
|
|
|
|
"act_key did not find any action");
|
|
|
|
}
|
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
#define ACCUMULATE_PATHS(X) \
|
2020-07-21 22:21:28 +00:00
|
|
|
if (act_attached->X.num_inputs > 0) { \
|
|
|
|
for (uint32_t i = 0; i < act_attached->X.num_inputs; i++) { \
|
|
|
|
add_path_to_set(temp, \
|
|
|
|
act_attached->X.inputs[i].bound_path, \
|
|
|
|
&num_paths); \
|
|
|
|
} \
|
2020-07-21 13:57:21 +00:00
|
|
|
}
|
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_PATHS)
|
|
|
|
#undef ACCUMULATE_PATHS
|
|
|
|
|
2020-07-21 13:57:21 +00:00
|
|
|
OXR_TWO_CALL_HELPER(log, sourceCapacityInput, sourceCountOutput,
|
|
|
|
sources, num_paths, temp,
|
|
|
|
oxr_session_success_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
|
|
|
}
|
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
/*!
|
|
|
|
* This populates the internals of action get state functions.
|
|
|
|
*
|
|
|
|
* @note Keep this synchronized with OXR_FOR_EACH_SUBACTION_PATH!
|
|
|
|
*/
|
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-08-27 13:01:49 +00:00
|
|
|
// For poses on the any path we select a single path.
|
|
|
|
if (sub_paths.any) {
|
|
|
|
sub_paths = act_attached->any_pose_sub_path;
|
|
|
|
}
|
|
|
|
|
2020-05-31 12:45:30 +00:00
|
|
|
data->isActive = XR_FALSE;
|
|
|
|
|
2020-08-27 13:01:49 +00:00
|
|
|
/*
|
|
|
|
* The sub path any is used as a catch all here to see if any
|
|
|
|
*/
|
2020-07-20 19:53:52 +00:00
|
|
|
#define COMPUTE_ACTIVE(X) \
|
2020-08-27 13:01:49 +00:00
|
|
|
if (sub_paths.X) { \
|
2020-07-20 19:53:52 +00:00
|
|
|
data->isActive |= act_attached->X.current.active; \
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2020-07-22 21:25:49 +00:00
|
|
|
OXR_FOR_EACH_VALID_SUBACTION_PATH(COMPUTE_ACTIVE)
|
2020-07-20 19:53:52 +00:00
|
|
|
#undef COMPUTE_ACTIVE
|
2020-08-27 13:01:49 +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-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
|
|
|
|
2020-10-24 00:31:52 +00:00
|
|
|
// This should all be moved into the drivers.
|
|
|
|
const int64_t min_pulse_time_ns = time_s_to_ns(0.1);
|
|
|
|
int64_t now_ns = time_state_get_now(sess->sys->inst->timekeeping);
|
|
|
|
int64_t stop_ns = 0;
|
|
|
|
if (data->duration <= 0) {
|
|
|
|
stop_ns = now_ns + min_pulse_time_ns;
|
|
|
|
} else {
|
|
|
|
stop_ns = now_ns + data->duration;
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
#define SET_OUT_VIBRATION(X) \
|
|
|
|
if (act_attached->X.current.active && \
|
|
|
|
(sub_paths.X || sub_paths.any)) { \
|
2020-10-24 00:31:52 +00:00
|
|
|
set_action_output_vibration(sess, &act_attached->X, stop_ns, \
|
2020-07-20 19:53:52 +00:00
|
|
|
data); \
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(SET_OUT_VIBRATION)
|
|
|
|
#undef SET_OUT_VIBRATION
|
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
|
|
|
}
|
|
|
|
|
2020-07-20 19:53:52 +00:00
|
|
|
#define STOP_VIBRATION(X) \
|
|
|
|
if (act_attached->X.current.active && \
|
|
|
|
(sub_paths.X || sub_paths.any)) { \
|
|
|
|
oxr_action_cache_stop_output(log, sess, &act_attached->X); \
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
2020-07-20 19:53:52 +00:00
|
|
|
|
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(STOP_VIBRATION)
|
|
|
|
#undef STOP_VIBRATION
|
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
|
|
|
}
|