2022-04-10 13:28:33 +00:00
|
|
|
// Copyright 2018-2022, 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
|
2021-01-14 14:13:48 +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
|
2021-01-14 14:13:48 +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-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths *subaction_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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_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,
|
2020-10-23 12:39:59 +00:00
|
|
|
enum oxr_subaction_path subaction_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
|
2021-11-08 21:02:03 +00:00
|
|
|
for (uint32_t i = 0; i < cache->input_count; i++) {
|
2020-06-15 15:58:48 +00:00
|
|
|
struct oxr_action_input *action_input = &cache->inputs[i];
|
|
|
|
oxr_input_transform_destroy(&(action_input->transforms));
|
2021-11-08 21:29:21 +00:00
|
|
|
action_input->transform_count = 0;
|
2020-06-15 15:58:48 +00:00
|
|
|
}
|
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;
|
2021-01-14 14:13:48 +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;
|
2021-01-14 14:13:48 +00:00
|
|
|
u_hashmap_int_insert(sess->act_attachments_by_key, act->act_key, act_attached);
|
2020-06-15 21:46:21 +00:00
|
|
|
|
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
|
2021-01-14 14:13:48 +00:00
|
|
|
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)
|
2020-06-15 21:46:21 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
2021-01-14 14:13:48 +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
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_action_set_attachment_teardown(struct oxr_action_set_attachment *act_set_attached)
|
2020-06-15 21:46:21 +00:00
|
|
|
{
|
2021-11-08 21:29:21 +00:00
|
|
|
for (size_t i = 0; i < act_set_attached->action_attachment_count; ++i) {
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_action_attachment_teardown(&(act_set_attached->act_attachments[i]));
|
2020-06-15 21:46:21 +00:00
|
|
|
}
|
|
|
|
free(act_set_attached->act_attachments);
|
|
|
|
act_set_attached->act_attachments = NULL;
|
2021-11-08 21:29:21 +00:00
|
|
|
act_set_attached->action_attachment_count = 0;
|
2020-06-15 21:46:21 +00:00
|
|
|
|
|
|
|
struct oxr_session *sess = act_set_attached->sess;
|
2021-01-14 14:13:48 +00:00
|
|
|
u_hashmap_int_erase(sess->act_sets_attachments_by_key, 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)
|
|
|
|
{
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_action_set_ref *act_set_ref = (struct oxr_action_set_ref *)orc;
|
2020-06-15 23:05:42 +00:00
|
|
|
|
|
|
|
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) {
|
2021-01-14 14:13:48 +00:00
|
|
|
u_hashset_erase_item(act_set->inst->action_sets.name_store, act_set->name_item);
|
2020-05-30 22:44:03 +00:00
|
|
|
free(act_set->name_item);
|
|
|
|
act_set->name_item = NULL;
|
|
|
|
}
|
|
|
|
if (act_set->loc_item != NULL) {
|
2021-01-14 14:13:48 +00:00
|
|
|
u_hashset_erase_item(act_set->inst->action_sets.loc_store, act_set->loc_item);
|
2020-05-30 22:44:03 +00:00
|
|
|
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;
|
2021-01-14 14:13:48 +00:00
|
|
|
OXR_ALLOCATE_HANDLE_OR_RETURN(log, act_set, OXR_XR_DEBUG_ACTIONSET, oxr_action_set_destroy_cb, &inst->handle);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_action_set_ref *act_set_ref = U_TYPED_CALLOC(struct oxr_action_set_ref);
|
2020-06-15 23:05:42 +00:00
|
|
|
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);
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to create name_store hashset");
|
2020-05-30 22:44:03 +00:00
|
|
|
}
|
|
|
|
|
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);
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "Failed to create loc_store hashset");
|
2020-05-30 22:44:03 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
strncpy(act_set_ref->name, createInfo->actionSetName, sizeof(act_set_ref->name));
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2021-01-14 14:13:48 +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,
|
2020-05-30 22:44:03 +00:00
|
|
|
&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) {
|
2021-01-14 14:13:48 +00:00
|
|
|
u_hashset_erase_item(act->act_set->data->actions.name_store, act->name_item);
|
2020-05-30 22:44:03 +00:00
|
|
|
free(act->name_item);
|
|
|
|
act->name_item = NULL;
|
|
|
|
}
|
|
|
|
if (act->loc_item != NULL) {
|
2021-01-14 14:13:48 +00:00
|
|
|
u_hashset_erase_item(act->act_set->data->actions.loc_store, act->loc_item);
|
2020-05-30 22:44:03 +00:00
|
|
|
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;
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_paths = {0};
|
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;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
if (!oxr_classify_sub_action_paths(log, inst, createInfo->countSubactionPaths, createInfo->subactionPaths,
|
2020-10-23 12:39:59 +00:00
|
|
|
&subaction_paths)) {
|
2020-06-15 19:16:38 +00:00
|
|
|
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;
|
2021-01-14 14:13:48 +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-10-23 12:39:59 +00:00
|
|
|
act_ref->subaction_paths = subaction_paths;
|
2020-06-15 23:05:42 +00:00
|
|
|
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
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
u_hashset_create_and_insert_str_c(act_set->data->actions.name_store, createInfo->actionName, &act->name_item);
|
|
|
|
u_hashset_create_and_insert_str_c(act_set->data->actions.loc_store, createInfo->localizedActionName,
|
2020-05-30 22:44:03 +00:00
|
|
|
&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,
|
2021-11-08 21:29:21 +00:00
|
|
|
uint32_t subaction_path_count,
|
2019-09-29 10:43:45 +00:00
|
|
|
const XrPath *subaction_paths,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths *subaction_paths_out)
|
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
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
// Reset the subaction_paths completely.
|
|
|
|
U_ZERO(subaction_paths_out);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2021-11-08 21:29:21 +00:00
|
|
|
if (subaction_path_count == 0) {
|
2020-10-23 12:39:59 +00:00
|
|
|
subaction_paths_out->any = true;
|
2020-06-15 19:16:38 +00:00
|
|
|
return ret;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2021-11-08 21:29:21 +00:00
|
|
|
for (uint32_t i = 0; i < subaction_path_count; i++) {
|
2019-05-07 12:47:18 +00:00
|
|
|
XrPath path = subaction_paths[i];
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define IDENTIFY_PATH(X) \
|
|
|
|
else if (path == inst->path_cache.X) \
|
|
|
|
{ \
|
2020-10-23 12:39:59 +00:00
|
|
|
subaction_paths_out->X = true; \
|
2020-07-20 19:53:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
if (path == XR_NULL_PATH) {
|
2020-10-23 12:39:59 +00:00
|
|
|
subaction_paths_out->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);
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
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
|
2022-04-10 13:28:33 +00:00
|
|
|
oxr_action_get_pose_input(struct oxr_session *sess,
|
2019-05-07 12:47:18 +00:00
|
|
|
uint32_t act_key,
|
2020-10-23 12:39:59 +00:00
|
|
|
const struct oxr_subaction_paths *subaction_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-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_paths = *subaction_paths_ptr;
|
|
|
|
if (subaction_paths.any) {
|
|
|
|
subaction_paths = act_attached->any_pose_subaction_path;
|
2020-08-27 13:01:49 +00:00
|
|
|
}
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
// Priority of inputs.
|
2021-01-14 14:13:48 +00:00
|
|
|
#define GET_POSE_INPUT(X) \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (act_attached->X.current.active && subaction_paths.X) { \
|
2021-01-14 14:13:48 +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],
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t *input_count)
|
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 {
|
2021-11-08 21:02:03 +00:00
|
|
|
for (size_t i = 0; i < xbp->input_count; i++) {
|
2020-11-03 19:33:52 +00:00
|
|
|
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)) {
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t index = (*input_count)++;
|
2020-11-03 19:33:52 +00:00
|
|
|
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],
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t *output_count)
|
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 {
|
2021-11-08 21:02:03 +00:00
|
|
|
for (size_t i = 0; i < xbp->output_count; i++) {
|
2020-11-03 19:33:52 +00:00
|
|
|
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)) {
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t index = (*output_count)++;
|
2020-11-03 19:33:52 +00:00
|
|
|
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],
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t *input_count,
|
2020-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_output outputs[OXR_MAX_BINDINGS_PER_ACTION],
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t *output_count)
|
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, //
|
2021-11-08 21:02:03 +00:00
|
|
|
output_count); //
|
2020-11-03 19:33:52 +00:00
|
|
|
}
|
2022-04-12 21:20:11 +00:00
|
|
|
return do_inputs( //
|
|
|
|
binding_point, //
|
|
|
|
xdev, //
|
|
|
|
xbp, //
|
|
|
|
matched_path, //
|
|
|
|
inputs, //
|
|
|
|
input_count); //
|
2020-11-03 19:33:52 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static struct xrt_binding_profile *
|
2021-01-14 14:13:48 +00:00
|
|
|
get_matching_binding_profile(struct oxr_interaction_profile *profile, struct xrt_device *xdev)
|
2020-11-03 19:33:52 +00:00
|
|
|
{
|
2021-11-08 21:02:03 +00:00
|
|
|
for (size_t i = 0; i < xdev->binding_profile_count; i++) {
|
2020-11-03 19:33:52 +00:00
|
|
|
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;
|
2021-11-08 21:29:21 +00:00
|
|
|
for (uint32_t i = 0; i < b->key_count; 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;
|
2021-01-14 14:13:48 +00:00
|
|
|
preferred_path_index = b->preferred_binding_path_index[i];
|
2020-05-04 15:22:15 +00:00
|
|
|
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,
|
2020-10-23 12:39:59 +00:00
|
|
|
enum oxr_subaction_path subaction_path,
|
2020-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_input inputs[OXR_MAX_BINDINGS_PER_ACTION],
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t *input_count,
|
2020-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_output outputs[OXR_MAX_BINDINGS_PER_ACTION],
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t *output_count)
|
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.
|
2020-10-23 12:39:59 +00:00
|
|
|
switch (subaction_path) {
|
2021-01-14 14:13:48 +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); \
|
2020-07-22 21:25:49 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_path_get_string(log, sess->sys->inst, profile->path, &profile_str, &length);
|
2019-09-02 21:04:13 +00:00
|
|
|
|
|
|
|
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.
|
|
|
|
*/
|
2021-01-14 14:13:48 +00:00
|
|
|
struct xrt_binding_profile *xbp = get_matching_binding_profile(profile, xdev);
|
2020-11-03 19:33:52 +00:00
|
|
|
|
|
|
|
// No point in proceeding here without either.
|
|
|
|
if (profile->xname != xdev->name && xbp == NULL) {
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_slog(slog, "\t\t\tProfile not for device and no xbp fallback!\n");
|
2020-11-03 19:33:52 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-09-02 21:04:13 +00:00
|
|
|
size_t num = 0;
|
2021-01-14 14:13:48 +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
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_path_get_string(log, sess->sys->inst, matched_path, &str, &length);
|
2019-09-02 21:04:13 +00:00
|
|
|
oxr_slog(slog, "\t\t\tBinding: %s\n", str);
|
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
if (binding_point->subaction_path != subaction_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, //
|
2021-11-08 21:02:03 +00:00
|
|
|
input_count, //
|
2020-11-03 19:33:52 +00:00
|
|
|
outputs, //
|
2021-11-08 21:02:03 +00:00
|
|
|
output_count); //
|
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.
|
2021-01-14 14:13:48 +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-10-23 12:39:59 +00:00
|
|
|
if (act_ref->subaction_paths.user || act_ref->subaction_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
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define BIND_SUBACTION(NAME, NAME_CAPS, PATH) \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (act_ref->subaction_paths.NAME || act_ref->subaction_paths.any) { \
|
2021-01-14 14:13:48 +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) {
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define POSE_ANY(NAME) \
|
2021-11-08 21:02:03 +00:00
|
|
|
if ((act_ref->subaction_paths.NAME || act_ref->subaction_paths.any) && act_attached->NAME.input_count > 0) { \
|
2020-10-23 12:39:59 +00:00
|
|
|
act_attached->any_pose_subaction_path.NAME = true; \
|
2021-01-14 14:13:48 +00:00
|
|
|
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
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_action_cache_stop_output(struct oxr_logger *log, struct oxr_session *sess, 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};
|
|
|
|
|
2021-11-08 21:02:03 +00:00
|
|
|
for (uint32_t i = 0; i < cache->output_count; 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
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_input_is_input_for_cache(struct oxr_action_input *action_input, struct oxr_action_cache *cache)
|
2020-07-28 13:29:31 +00:00
|
|
|
{
|
2021-11-08 21:02:03 +00:00
|
|
|
for (size_t i = 0; i < cache->input_count; i++) {
|
2020-07-28 13:29:31 +00:00
|
|
|
if (action_input->bound_path == cache->inputs[i].bound_path) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_input_is_bound_in_act_set(struct oxr_action_input *action_input, struct oxr_action_set_attachment *act_set_attached)
|
2020-07-28 13:29:31 +00:00
|
|
|
{
|
2021-11-08 21:29:21 +00:00
|
|
|
for (size_t i = 0; i < act_set_attached->action_attachment_count; i++) {
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_action_attachment *act_attached = &act_set_attached->act_attachments[i];
|
2020-07-28 13:29:31 +00:00
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define ACCUMULATE_PATHS(X) \
|
|
|
|
if (oxr_input_is_input_for_cache(action_input, &act_attached->X)) { \
|
|
|
|
return true; \
|
2020-07-28 13:29:31 +00:00
|
|
|
}
|
|
|
|
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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths *subaction_path,
|
2020-07-28 13:29:31 +00:00
|
|
|
struct oxr_action_attachment *act_attached,
|
|
|
|
struct oxr_action_input *action_input)
|
|
|
|
{
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_action_set_ref *act_set_ref = act_attached->act_set_attached->act_set_ref;
|
2020-07-28 13:29:31 +00:00
|
|
|
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;
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_get_action_set_attachment(sess, set, &other_act_set_attached, &other_act_set);
|
2020-07-28 13:29:31 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
/* Currently updated input source with subactionpath X can be
|
2020-07-28 13:29:31 +00:00
|
|
|
* suppressed, if input source also occurs in action set with
|
|
|
|
* higher priority if
|
2020-10-23 12:39:59 +00:00
|
|
|
* - high prio set syncs w/ ANY subactionpath or
|
|
|
|
* - high prio set syncs w/ subactionpath matching this input
|
|
|
|
* subactionpath
|
2020-07-28 13:29:31 +00:00
|
|
|
*/
|
2020-10-23 12:39:59 +00:00
|
|
|
bool relevant_subactionpath = other_act_set_attached->requested_subaction_paths.any;
|
2020-07-28 13:29:31 +00:00
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
#define ACCUMULATE_PATHS(X) \
|
|
|
|
relevant_subactionpath |= (other_act_set_attached->requested_subaction_paths.X && subaction_path->X);
|
2020-07-28 13:29:31 +00:00
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_PATHS)
|
|
|
|
#undef ACCUMULATE_PATHS
|
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
if (!relevant_subactionpath) {
|
2020-07-28 13:29:31 +00:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
if (oxr_input_is_bound_in_act_set(action_input, other_act_set_attached)) {
|
2020-07-28 13:29:31 +00:00
|
|
|
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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths *subaction_path,
|
2020-07-28 13:29:31 +00:00
|
|
|
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;
|
2021-11-08 21:02:03 +00:00
|
|
|
size_t input_count = cache->input_count;
|
2020-07-28 13:29:31 +00:00
|
|
|
|
2021-11-08 21:02:03 +00:00
|
|
|
if (input_count == 0) {
|
2020-07-21 17:36:17 +00:00
|
|
|
*is_active = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool any_active = false;
|
|
|
|
struct oxr_input_value_tagged res = {0};
|
|
|
|
int64_t res_timestamp = inputs[0].input->timestamp;
|
|
|
|
|
2021-11-08 21:02:03 +00:00
|
|
|
for (size_t i = 0; i < input_count; i++) {
|
2020-07-21 17:36:17 +00:00
|
|
|
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
|
2020-10-23 12:39:59 +00:00
|
|
|
if (oxr_input_supressed(sess, countActionSets, actionSets, subaction_path, act_attached,
|
|
|
|
action_input)) {
|
2020-07-28 13:29:31 +00:00
|
|
|
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};
|
2021-11-08 21:29:21 +00:00
|
|
|
if (!oxr_input_transform_process(action_input->transforms, action_input->transform_count, &raw_input,
|
2021-01-14 14:13:48 +00:00
|
|
|
&transformed)) {
|
2020-07-21 17:36:17 +00:00
|
|
|
// 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. */
|
2021-01-14 14:13:48 +00:00
|
|
|
if (res.value.boolean && transformed.value.boolean && input->timestamp < res_timestamp) {
|
2020-07-21 17:36:17 +00:00
|
|
|
res_timestamp = input->timestamp;
|
2021-01-14 14:13:48 +00:00
|
|
|
} else if (!res.value.boolean && !transformed.value.boolean &&
|
2020-07-21 17:36:17 +00:00
|
|
|
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:
|
2021-01-14 14:13:48 +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: {
|
2021-01-14 14:13:48 +00:00
|
|
|
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;
|
2020-07-21 17:36:17 +00:00
|
|
|
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-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths *subaction_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 */
|
2021-11-08 21:02:03 +00:00
|
|
|
if (cache->output_count > 0) {
|
2020-01-09 01:11:34 +00:00
|
|
|
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
|
|
|
}
|
2021-11-08 21:02:03 +00:00
|
|
|
} else if (cache->input_count > 0) {
|
2020-07-28 13:29:31 +00:00
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
if (!oxr_input_combine_input(sess, countActionSets, actionSets, act_attached, subaction_path, cache,
|
2021-01-14 14:13:48 +00:00
|
|
|
&combined, ×tamp, &is_active)) {
|
|
|
|
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: {
|
2021-01-14 14:13:48 +00:00
|
|
|
changed = (combined.value.vec2.x != last.value.vec2.x) ||
|
|
|
|
(combined.value.vec2.y != last.value.vec2.y);
|
2020-07-21 17:36:17 +00:00
|
|
|
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
|
2021-01-22 13:51:08 +00:00
|
|
|
// Untested, we have no VEC3 input.
|
2019-10-24 13:29:23 +00:00
|
|
|
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: {
|
2021-01-14 14:13:48 +00:00
|
|
|
changed = (combined.value.boolean != last.value.boolean);
|
2020-07-21 17:36:17 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define BOOL_CHECK(NAME) \
|
|
|
|
if (act_attached->NAME.current.active) { \
|
|
|
|
active |= true; \
|
|
|
|
value |= act_attached->NAME.current.value.boolean; \
|
|
|
|
timestamp = act_attached->NAME.current.timestamp; \
|
|
|
|
}
|
|
|
|
#define VEC1_CHECK(NAME) \
|
|
|
|
if (act_attached->NAME.current.active) { \
|
|
|
|
active |= true; \
|
|
|
|
if (value < act_attached->NAME.current.value.vec1.x) { \
|
|
|
|
value = act_attached->NAME.current.value.vec1.x; \
|
|
|
|
timestamp = act_attached->NAME.current.timestamp; \
|
|
|
|
} \
|
|
|
|
}
|
|
|
|
#define VEC2_CHECK(NAME) \
|
|
|
|
if (act_attached->NAME.current.active) { \
|
|
|
|
active |= true; \
|
|
|
|
float curr_x = act_attached->NAME.current.value.vec2.x; \
|
|
|
|
float curr_y = act_attached->NAME.current.value.vec2.y; \
|
|
|
|
float curr_d = curr_x * curr_x + curr_y * curr_y; \
|
|
|
|
if (distance < curr_d) { \
|
|
|
|
x = curr_x; \
|
|
|
|
y = curr_y; \
|
|
|
|
distance = curr_d; \
|
|
|
|
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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_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.
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define UPDATE_SELECT(X) \
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_paths_##X = {0}; \
|
|
|
|
subaction_paths_##X.X = true; \
|
|
|
|
bool select_##X = subaction_paths.X || subaction_paths.any; \
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_action_cache_update(log, sess, countActionSets, actionSets, act_attached, &act_attached->X, time, \
|
2020-10-23 12:39:59 +00:00
|
|
|
&subaction_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.
|
|
|
|
*
|
2021-11-08 21:29:21 +00:00
|
|
|
* Populates @p action_input->transforms and @p action_input->transform_count on
|
2020-06-15 15:58:48 +00:00
|
|
|
* 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);
|
2021-11-08 21:29:21 +00:00
|
|
|
assert(action_input->transform_count == 0);
|
2020-06-15 15:58:48 +00:00
|
|
|
const char *str;
|
|
|
|
size_t length;
|
2021-01-14 14:13:48 +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);
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_input_transform_create_chain(log, slog, t, act->data->action_type, act->data->name, str,
|
2021-11-08 21:29:21 +00:00
|
|
|
&action_input->transforms, &action_input->transform_count);
|
2020-06-15 15:58:48 +00:00
|
|
|
}
|
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,
|
2020-10-23 12:39:59 +00:00
|
|
|
enum oxr_subaction_path subaction_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};
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t input_count = 0;
|
2020-07-21 22:21:28 +00:00
|
|
|
struct oxr_action_output outputs[OXR_MAX_BINDINGS_PER_ACTION] = {0};
|
2021-11-08 21:02:03 +00:00
|
|
|
uint32_t output_count = 0;
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2021-11-08 21:02:03 +00:00
|
|
|
get_binding(log, slog, sess, act, profile, subaction_path, inputs, &input_count, outputs, &output_count);
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
cache->current.active = false;
|
|
|
|
|
2021-11-08 21:02:03 +00:00
|
|
|
if (input_count > 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;
|
2021-11-08 21:02:03 +00:00
|
|
|
cache->inputs = U_TYPED_ARRAY_CALLOC(struct oxr_action_input, input_count);
|
|
|
|
for (uint32_t i = 0; i < input_count; i++) {
|
2020-08-18 15:11:15 +00:00
|
|
|
|
|
|
|
// Only add the input if we can find a transform.
|
2021-01-14 14:13:48 +00:00
|
|
|
if (oxr_action_populate_input_transform(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;
|
|
|
|
}
|
|
|
|
|
2021-11-08 21:02:03 +00:00
|
|
|
cache->input_count = count;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
|
2021-11-08 21:02:03 +00:00
|
|
|
if (output_count > 0) {
|
2019-05-07 12:47:18 +00:00
|
|
|
cache->current.active = true;
|
2021-11-08 21:02:03 +00:00
|
|
|
cache->outputs = U_TYPED_ARRAY_CALLOC(struct oxr_action_output, output_count);
|
|
|
|
for (uint32_t i = 0; i < output_count; i++) {
|
2019-05-07 12:47:18 +00:00
|
|
|
cache->outputs[i] = outputs[i];
|
|
|
|
}
|
2021-11-08 21:02:03 +00:00
|
|
|
cache->output_count = output_count;
|
2019-05-07 12:47:18 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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
|
2021-01-14 14:13:48 +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;
|
2021-01-14 14:13:48 +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
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
int ret = u_hashmap_int_find(sess->act_sets_attachments_by_key, (*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
|
2021-01-14 14:13:48 +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
|
|
|
|
2021-01-14 14:13:48 +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};
|
2021-01-14 14:13:48 +00:00
|
|
|
#define FIND_PROFILE(X) oxr_find_profile_for_device(log, inst, GET_XDEV_BY_ROLE(sess->sys, X), &profiles.X);
|
2020-07-22 21:25:49 +00:00
|
|
|
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.
|
2021-11-08 21:29:21 +00:00
|
|
|
sess->action_set_attachment_count = bindInfo->countActionSets;
|
2021-01-14 14:13:48 +00:00
|
|
|
sess->act_set_attachments =
|
2021-11-08 21:29:21 +00:00
|
|
|
U_TYPED_ARRAY_CALLOC(struct oxr_action_set_attachment, sess->action_set_attachment_count);
|
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.
|
2021-11-08 21:29:21 +00:00
|
|
|
for (uint32_t i = 0; i < sess->action_set_attachment_count; i++) {
|
2021-01-14 14:13:48 +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
|
|
|
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;
|
2021-01-14 14:13:48 +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);
|
2020-06-15 21:46:21 +00:00
|
|
|
|
|
|
|
// Allocate the action attachments for this set.
|
2021-11-08 21:29:21 +00:00
|
|
|
act_set_attached->action_attachment_count = oxr_handle_base_get_num_children(&act_set->handle);
|
2021-01-14 14:13:48 +00:00
|
|
|
act_set_attached->act_attachments =
|
2021-11-08 21:29:21 +00:00
|
|
|
U_TYPED_ARRAY_CALLOC(struct oxr_action_attachment, act_set_attached->action_attachment_count);
|
2020-06-15 21:46:21 +00:00
|
|
|
|
|
|
|
// 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++) {
|
2021-01-14 14:13:48 +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;
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +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, &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
|
|
|
|
2021-01-14 14:13:48 +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++) {
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_get_action_set_attachment(sess, actionSets[i].actionSet, &act_set_attached, &act_set);
|
2020-06-15 19:16:38 +00:00
|
|
|
if (act_set_attached == NULL) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_ACTIONSET_NOT_ATTACHED,
|
|
|
|
"(actionSets[%i].actionSet) action set '%s' has "
|
|
|
|
"not been attached to this session",
|
|
|
|
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.
|
2021-11-08 21:29:21 +00:00
|
|
|
for (size_t i = 0; i < sess->sys->xdev_count; 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.
|
2021-11-08 21:29:21 +00:00
|
|
|
for (size_t i = 0; i < sess->action_set_attachment_count; ++i) {
|
2020-06-15 21:46:21 +00:00
|
|
|
act_set_attached = &sess->act_set_attachments[i];
|
2020-10-23 12:39:59 +00:00
|
|
|
U_ZERO(&act_set_attached->requested_subaction_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++) {
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_paths;
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_session_get_action_set_attachment(sess, actionSets[i].actionSet, &act_set_attached, &act_set);
|
2020-06-15 19:16:38 +00:00
|
|
|
assert(act_set_attached != NULL);
|
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
if (!oxr_classify_sub_action_paths(log, sess->sys->inst, 1, &actionSets[i].subactionPath,
|
|
|
|
&subaction_paths)) {
|
2020-06-15 19:16:38 +00:00
|
|
|
return XR_ERROR_PATH_UNSUPPORTED;
|
|
|
|
}
|
2019-05-07 12:47:18 +00:00
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
act_set_attached->requested_subaction_paths.any |= subaction_paths.any;
|
2020-07-20 19:53:52 +00:00
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
/* never error when requesting any subactionpath */
|
|
|
|
bool any_action_with_subactionpath = subaction_paths.any;
|
2020-07-31 00:48:04 +00:00
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
#define ACCUMULATE_REQUESTED(X) act_set_attached->requested_subaction_paths.X |= subaction_paths.X;
|
2020-07-20 19:53:52 +00:00
|
|
|
|
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_REQUESTED)
|
|
|
|
#undef ACCUMULATE_REQUESTED
|
2020-07-31 00:48:04 +00:00
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
/* check if we have at least one action for requested subactionpath */
|
2021-11-08 21:29:21 +00:00
|
|
|
for (uint32_t k = 0; k < act_set_attached->action_attachment_count; k++) {
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_action_attachment *act_attached = &act_set_attached->act_attachments[k];
|
2020-07-31 00:48:04 +00:00
|
|
|
|
|
|
|
if (act_attached == NULL) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2020-10-23 12:39:59 +00:00
|
|
|
#define ACCUMULATE_REQUESTED(X) \
|
|
|
|
any_action_with_subactionpath |= subaction_paths.X && act_attached->act_ref->subaction_paths.X;
|
2020-07-31 00:48:04 +00:00
|
|
|
OXR_FOR_EACH_SUBACTION_PATH(ACCUMULATE_REQUESTED)
|
|
|
|
#undef ACCUMULATE_REQUESTED
|
|
|
|
}
|
2020-10-23 12:39:59 +00:00
|
|
|
if (!any_action_with_subactionpath) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_PATH_UNSUPPORTED,
|
2020-10-23 12:39:59 +00:00
|
|
|
"No action with specified subactionpath in actionset");
|
2020-07-31 00:48:04 +00:00
|
|
|
}
|
2019-10-28 14:57:35 +00:00
|
|
|
}
|
|
|
|
|
2020-06-15 21:46:21 +00:00
|
|
|
// Now, update all action attachments
|
2021-11-08 21:29:21 +00:00
|
|
|
for (size_t i = 0; i < sess->action_set_attachment_count; ++i) {
|
2020-06-15 21:46:21 +00:00
|
|
|
act_set_attached = &sess->act_set_attachments[i];
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_paths = act_set_attached->requested_subaction_paths;
|
2019-10-28 14:57:35 +00:00
|
|
|
|
|
|
|
|
2021-11-08 21:29:21 +00:00
|
|
|
for (uint32_t k = 0; k < act_set_attached->action_attachment_count; k++) {
|
2021-01-14 14:13:48 +00:00
|
|
|
struct oxr_action_attachment *act_attached = &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;
|
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
oxr_action_attachment_update(log, sess, countActionSets, actionSets, act_attached, now,
|
2020-10-23 12:39:59 +00:00
|
|
|
subaction_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
|
2021-11-08 21:29:21 +00:00
|
|
|
add_path_to_set(XrPath path_set[OXR_MAX_BINDINGS_PER_ACTION], XrPath new_path, uint32_t *inout_path_count)
|
2020-07-21 22:21:28 +00:00
|
|
|
{
|
2021-11-08 21:29:21 +00:00
|
|
|
const uint32_t n = *inout_path_count;
|
2020-07-21 22:21:28 +00:00
|
|
|
|
|
|
|
// 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;
|
2021-11-08 21:29:21 +00:00
|
|
|
(*inout_path_count)++;
|
2020-07-21 22:21:28 +00:00
|
|
|
}
|
|
|
|
|
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;
|
2021-11-08 21:29:21 +00:00
|
|
|
uint32_t path_count = 0;
|
2020-07-21 22:21:28 +00:00
|
|
|
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) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_RUNTIME_FAILURE, "act_key did not find any action");
|
2020-07-21 13:57:21 +00:00
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define ACCUMULATE_PATHS(X) \
|
2021-11-08 21:02:03 +00:00
|
|
|
if (act_attached->X.input_count > 0) { \
|
|
|
|
for (uint32_t i = 0; i < act_attached->X.input_count; i++) { \
|
2021-11-08 21:29:21 +00:00
|
|
|
add_path_to_set(temp, act_attached->X.inputs[i].bound_path, &path_count); \
|
2021-01-14 14:13:48 +00:00
|
|
|
} \
|
2021-09-19 22:27:51 +00:00
|
|
|
} \
|
2021-11-08 21:02:03 +00:00
|
|
|
if (act_attached->X.output_count > 0) { \
|
|
|
|
for (uint32_t i = 0; i < act_attached->X.output_count; i++) { \
|
2021-11-08 21:29:21 +00:00
|
|
|
add_path_to_set(temp, act_attached->X.outputs[i].bound_path, &path_count); \
|
2021-09-19 22:27:51 +00:00
|
|
|
} \
|
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
|
|
|
|
|
2021-11-08 21:29:21 +00:00
|
|
|
OXR_TWO_CALL_HELPER(log, sourceCapacityInput, sourceCountOutput, sources, path_count, temp,
|
2020-07-21 13:57:21 +00:00
|
|
|
oxr_session_success_result(sess));
|
|
|
|
}
|
|
|
|
|
2019-05-07 12:47:18 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
*
|
|
|
|
* Action get functions.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define OXR_ACTION_GET_XR_STATE_FROM_ACTION_STATE_COMMON(ACTION_STATE, DATA) \
|
|
|
|
do { \
|
|
|
|
DATA->lastChangeTime = time_state_monotonic_to_ts_ns(inst->timekeeping, ACTION_STATE->timestamp); \
|
|
|
|
DATA->changedSinceLastSync = ACTION_STATE->changed; \
|
|
|
|
DATA->isActive = XR_TRUE; \
|
2020-06-17 22:27:59 +00:00
|
|
|
} 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
|
2021-01-14 14:13:48 +00:00
|
|
|
get_xr_state_from_action_state_vec1(struct oxr_instance *inst, struct oxr_action_state *state, 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!
|
|
|
|
*/
|
2021-01-14 14:13:48 +00:00
|
|
|
#define OXR_ACTION_GET_FILLER(TYPE) \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (subaction_paths.any && act_attached->any_state.active) { \
|
2021-01-14 14:13:48 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE(sess->sys->inst, &act_attached->any_state, data); \
|
|
|
|
} \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (subaction_paths.user && act_attached->user.current.active) { \
|
2021-01-14 14:13:48 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE(sess->sys->inst, &act_attached->user.current, data); \
|
|
|
|
} \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (subaction_paths.head && act_attached->head.current.active) { \
|
2021-01-14 14:13:48 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE(sess->sys->inst, &act_attached->head.current, data); \
|
|
|
|
} \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (subaction_paths.left && act_attached->left.current.active) { \
|
2021-01-14 14:13:48 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE(sess->sys->inst, &act_attached->left.current, data); \
|
|
|
|
} \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (subaction_paths.right && act_attached->right.current.active) { \
|
2021-01-14 14:13:48 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE(sess->sys->inst, &act_attached->right.current, data); \
|
|
|
|
} \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (subaction_paths.gamepad && act_attached->gamepad.current.active) { \
|
2021-01-14 14:13:48 +00:00
|
|
|
get_xr_state_from_action_state_##TYPE(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
|
|
|
|
*/
|
2021-01-14 14:13:48 +00:00
|
|
|
#define OXR_ACTION_RESET_XR_ACTION_STATE(data) \
|
|
|
|
do { \
|
|
|
|
data->isActive = XR_FALSE; \
|
|
|
|
data->changedSinceLastSync = XR_FALSE; \
|
|
|
|
data->lastChangeTime = 0; \
|
|
|
|
U_ZERO(&data->currentState); \
|
2020-06-17 22:27:59 +00:00
|
|
|
} 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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_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) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_ACTIONSET_NOT_ATTACHED, "Action has not been attached to this session");
|
2020-05-31 12:45:30 +00:00
|
|
|
}
|
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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_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) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_ACTIONSET_NOT_ATTACHED, "Action has not been attached to this session");
|
2020-05-31 12:45:30 +00:00
|
|
|
}
|
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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_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) {
|
2021-01-14 14:13:48 +00:00
|
|
|
return oxr_error(log, XR_ERROR_ACTIONSET_NOT_ATTACHED, "Action has not been attached to this session");
|
2020-05-31 12:45:30 +00:00
|
|
|
}
|
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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_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) {
|
2021-01-14 14:13:48 +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.
|
2020-10-23 12:39:59 +00:00
|
|
|
if (subaction_paths.any) {
|
|
|
|
subaction_paths = act_attached->any_pose_subaction_path;
|
2020-08-27 13:01:49 +00:00
|
|
|
}
|
|
|
|
|
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
|
|
|
|
*/
|
2021-01-14 14:13:48 +00:00
|
|
|
#define COMPUTE_ACTIVE(X) \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (subaction_paths.X) { \
|
2021-01-14 14:13:48 +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
|
|
|
|
2021-11-08 21:02:03 +00:00
|
|
|
for (uint32_t i = 0; i < cache->output_count; 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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_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) {
|
2021-01-14 14:13:48 +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
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define SET_OUT_VIBRATION(X) \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (act_attached->X.current.active && (subaction_paths.X || subaction_paths.any)) { \
|
2021-01-14 14:13:48 +00:00
|
|
|
set_action_output_vibration(sess, &act_attached->X, stop_ns, 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,
|
2020-10-23 12:39:59 +00:00
|
|
|
struct oxr_subaction_paths subaction_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) {
|
2021-01-14 14:13:48 +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
|
|
|
}
|
|
|
|
|
2021-01-14 14:13:48 +00:00
|
|
|
#define STOP_VIBRATION(X) \
|
2020-10-23 12:39:59 +00:00
|
|
|
if (act_attached->X.current.active && (subaction_paths.X || subaction_paths.any)) { \
|
2021-01-14 14:13:48 +00:00
|
|
|
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
|
|
|
}
|