XR: Action Binding Improvements
Provides several important improvements to the runtime action bindings operation and internal API. Moves input-specific action data (input thresholds, input regions, pose offsets/spaces) from actions to more granular action bindings. This allows a single action to be mapped to a variety of inputs, without having to share a single input threshold, region, or space. Also removes the need for action space creation API, as spaces for pose actions will be automatically created with the bindings. The correct action data for the current inputs is set by calling xrGetCurrentInteractionProfile() to get the current profile and then retrieving the corresponding mapped data. Does not bring about any changes for users since only internal runtime functionality is currently affected. Reviewed By: Julian Eisel Differential Revision: http://developer.blender.org/D12077
This commit is contained in:
@@ -1066,22 +1066,6 @@ void GHOST_XrDestroyActions(GHOST_XrContextHandle xr_context,
|
|||||||
uint32_t count,
|
uint32_t count,
|
||||||
const char *const *action_names);
|
const char *const *action_names);
|
||||||
|
|
||||||
/**
|
|
||||||
* Create spaces for pose-based OpenXR actions.
|
|
||||||
*/
|
|
||||||
int GHOST_XrCreateActionSpaces(GHOST_XrContextHandle xr_context,
|
|
||||||
const char *action_set_name,
|
|
||||||
uint32_t count,
|
|
||||||
const GHOST_XrActionSpaceInfo *infos);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Destroy previously created spaces for OpenXR actions.
|
|
||||||
*/
|
|
||||||
void GHOST_XrDestroyActionSpaces(GHOST_XrContextHandle xr_context,
|
|
||||||
const char *action_set_name,
|
|
||||||
uint32_t count,
|
|
||||||
const GHOST_XrActionSpaceInfo *infos);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create input/output path bindings for OpenXR actions.
|
* Create input/output path bindings for OpenXR actions.
|
||||||
*/
|
*/
|
||||||
@@ -1096,7 +1080,8 @@ int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_context,
|
|||||||
void GHOST_XrDestroyActionBindings(GHOST_XrContextHandle xr_context,
|
void GHOST_XrDestroyActionBindings(GHOST_XrContextHandle xr_context,
|
||||||
const char *action_set_name,
|
const char *action_set_name,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
const GHOST_XrActionProfileInfo *infos);
|
const char *const *action_names,
|
||||||
|
const char *const *profile_paths);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach all created action sets to the current OpenXR session.
|
* Attach all created action sets to the current OpenXR session.
|
||||||
|
|||||||
@@ -719,29 +719,27 @@ typedef struct GHOST_XrActionInfo {
|
|||||||
const char **subaction_paths;
|
const char **subaction_paths;
|
||||||
/** States for each subaction path. */
|
/** States for each subaction path. */
|
||||||
void *states;
|
void *states;
|
||||||
|
/** Input thresholds/regions for each subaction path. */
|
||||||
|
float *float_thresholds;
|
||||||
|
int16_t *axis_flags;
|
||||||
|
|
||||||
GHOST_XrCustomdataFreeFn customdata_free_fn;
|
GHOST_XrCustomdataFreeFn customdata_free_fn;
|
||||||
void *customdata; /* wmXrAction */
|
void *customdata; /* wmXrAction */
|
||||||
} GHOST_XrActionInfo;
|
} GHOST_XrActionInfo;
|
||||||
|
|
||||||
typedef struct GHOST_XrActionSpaceInfo {
|
|
||||||
const char *action_name;
|
|
||||||
uint32_t count_subaction_paths;
|
|
||||||
const char **subaction_paths;
|
|
||||||
/** Poses for each subaction path. */
|
|
||||||
const GHOST_XrPose *poses;
|
|
||||||
} GHOST_XrActionSpaceInfo;
|
|
||||||
|
|
||||||
typedef struct GHOST_XrActionBindingInfo {
|
typedef struct GHOST_XrActionBindingInfo {
|
||||||
const char *action_name;
|
const char *component_path;
|
||||||
uint32_t count_interaction_paths;
|
float float_threshold;
|
||||||
/** Interaction path: User (sub-action) path + component path. */
|
int16_t axis_flag;
|
||||||
const char **interaction_paths;
|
GHOST_XrPose pose;
|
||||||
} GHOST_XrActionBindingInfo;
|
} GHOST_XrActionBindingInfo;
|
||||||
|
|
||||||
typedef struct GHOST_XrActionProfileInfo {
|
typedef struct GHOST_XrActionProfileInfo {
|
||||||
|
const char *action_name;
|
||||||
const char *profile_path;
|
const char *profile_path;
|
||||||
uint32_t count_bindings;
|
uint32_t count_subaction_paths;
|
||||||
|
const char **subaction_paths;
|
||||||
|
/* Bindings for each subaction path. */
|
||||||
const GHOST_XrActionBindingInfo *bindings;
|
const GHOST_XrActionBindingInfo *bindings;
|
||||||
} GHOST_XrActionProfileInfo;
|
} GHOST_XrActionProfileInfo;
|
||||||
|
|
||||||
|
|||||||
@@ -961,28 +961,6 @@ void GHOST_XrDestroyActions(GHOST_XrContextHandle xr_contexthandle,
|
|||||||
GHOST_XR_CAPI_CALL(xr_session->destroyActions(action_set_name, count, action_names), xr_context);
|
GHOST_XR_CAPI_CALL(xr_session->destroyActions(action_set_name, count, action_names), xr_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GHOST_XrCreateActionSpaces(GHOST_XrContextHandle xr_contexthandle,
|
|
||||||
const char *action_set_name,
|
|
||||||
uint32_t count,
|
|
||||||
const GHOST_XrActionSpaceInfo *infos)
|
|
||||||
{
|
|
||||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
|
||||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
|
||||||
GHOST_XR_CAPI_CALL_RET(xr_session->createActionSpaces(action_set_name, count, infos),
|
|
||||||
xr_context);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GHOST_XrDestroyActionSpaces(GHOST_XrContextHandle xr_contexthandle,
|
|
||||||
const char *action_set_name,
|
|
||||||
uint32_t count,
|
|
||||||
const GHOST_XrActionSpaceInfo *infos)
|
|
||||||
{
|
|
||||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
|
||||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
|
||||||
GHOST_XR_CAPI_CALL(xr_session->destroyActionSpaces(action_set_name, count, infos), xr_context);
|
|
||||||
}
|
|
||||||
|
|
||||||
int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_contexthandle,
|
int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_contexthandle,
|
||||||
const char *action_set_name,
|
const char *action_set_name,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
@@ -998,11 +976,14 @@ int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_contexthandle,
|
|||||||
void GHOST_XrDestroyActionBindings(GHOST_XrContextHandle xr_contexthandle,
|
void GHOST_XrDestroyActionBindings(GHOST_XrContextHandle xr_contexthandle,
|
||||||
const char *action_set_name,
|
const char *action_set_name,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
const GHOST_XrActionProfileInfo *infos)
|
const char *const *action_names,
|
||||||
|
const char *const *profile_paths)
|
||||||
{
|
{
|
||||||
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
|
||||||
GHOST_XrSession *xr_session = xr_context->getSession();
|
GHOST_XrSession *xr_session = xr_context->getSession();
|
||||||
GHOST_XR_CAPI_CALL(xr_session->destroyActionBindings(action_set_name, count, infos), xr_context);
|
GHOST_XR_CAPI_CALL(
|
||||||
|
xr_session->destroyActionBindings(action_set_name, count, action_names, profile_paths),
|
||||||
|
xr_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
int GHOST_XrAttachActionSets(GHOST_XrContextHandle xr_contexthandle)
|
int GHOST_XrAttachActionSets(GHOST_XrContextHandle xr_contexthandle)
|
||||||
|
|||||||
@@ -33,24 +33,22 @@
|
|||||||
*
|
*
|
||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
GHOST_XrActionSpace::GHOST_XrActionSpace(XrInstance instance,
|
GHOST_XrActionSpace::GHOST_XrActionSpace(XrSession session,
|
||||||
XrSession session,
|
|
||||||
XrAction action,
|
XrAction action,
|
||||||
const GHOST_XrActionSpaceInfo &info,
|
const char *action_name,
|
||||||
uint32_t subaction_idx)
|
const char *profile_path,
|
||||||
|
XrPath subaction_path,
|
||||||
|
const char *subaction_path_str,
|
||||||
|
const GHOST_XrPose &pose)
|
||||||
{
|
{
|
||||||
const char *subaction_path = info.subaction_paths[subaction_idx];
|
|
||||||
CHECK_XR(xrStringToPath(instance, subaction_path, &m_subaction_path),
|
|
||||||
(std::string("Failed to get user path \"") + subaction_path + "\".").data());
|
|
||||||
|
|
||||||
XrActionSpaceCreateInfo action_space_info{XR_TYPE_ACTION_SPACE_CREATE_INFO};
|
XrActionSpaceCreateInfo action_space_info{XR_TYPE_ACTION_SPACE_CREATE_INFO};
|
||||||
action_space_info.action = action;
|
action_space_info.action = action;
|
||||||
action_space_info.subactionPath = m_subaction_path;
|
action_space_info.subactionPath = subaction_path;
|
||||||
copy_ghost_pose_to_openxr_pose(info.poses[subaction_idx], action_space_info.poseInActionSpace);
|
copy_ghost_pose_to_openxr_pose(pose, action_space_info.poseInActionSpace);
|
||||||
|
|
||||||
CHECK_XR(xrCreateActionSpace(session, &action_space_info, &m_space),
|
CHECK_XR(xrCreateActionSpace(session, &action_space_info, &m_space),
|
||||||
(std::string("Failed to create space \"") + subaction_path + "\" for action \"" +
|
(std::string("Failed to create space \"") + subaction_path_str + "\" for action \"" +
|
||||||
info.action_name + "\".")
|
action_name + "\" and profile \"" + profile_path + "\".")
|
||||||
.data());
|
.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,11 +64,6 @@ XrSpace GHOST_XrActionSpace::getSpace() const
|
|||||||
return m_space;
|
return m_space;
|
||||||
}
|
}
|
||||||
|
|
||||||
const XrPath &GHOST_XrActionSpace::getSubactionPath() const
|
|
||||||
{
|
|
||||||
return m_subaction_path;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** \} */
|
/** \} */
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
@@ -79,13 +72,19 @@ const XrPath &GHOST_XrActionSpace::getSubactionPath() const
|
|||||||
* \{ */
|
* \{ */
|
||||||
|
|
||||||
GHOST_XrActionProfile::GHOST_XrActionProfile(XrInstance instance,
|
GHOST_XrActionProfile::GHOST_XrActionProfile(XrInstance instance,
|
||||||
|
XrSession session,
|
||||||
XrAction action,
|
XrAction action,
|
||||||
const char *profile_path,
|
GHOST_XrActionType type,
|
||||||
const GHOST_XrActionBindingInfo &info)
|
const GHOST_XrActionProfileInfo &info)
|
||||||
{
|
{
|
||||||
CHECK_XR(
|
CHECK_XR(xrStringToPath(instance, info.profile_path, &m_profile),
|
||||||
xrStringToPath(instance, profile_path, &m_profile),
|
(std::string("Failed to get interaction profile path \"") + info.profile_path + "\".")
|
||||||
(std::string("Failed to get interaction profile path \"") + profile_path + "\".").data());
|
.data());
|
||||||
|
|
||||||
|
const bool is_float_action = (type == GHOST_kXrActionTypeFloatInput ||
|
||||||
|
type == GHOST_kXrActionTypeVector2fInput);
|
||||||
|
const bool is_button_action = (is_float_action || type == GHOST_kXrActionTypeBooleanInput);
|
||||||
|
const bool is_pose_action = (type == GHOST_kXrActionTypePoseInput);
|
||||||
|
|
||||||
/* Create bindings. */
|
/* Create bindings. */
|
||||||
XrInteractionProfileSuggestedBinding bindings_info{
|
XrInteractionProfileSuggestedBinding bindings_info{
|
||||||
@@ -93,29 +92,78 @@ GHOST_XrActionProfile::GHOST_XrActionProfile(XrInstance instance,
|
|||||||
bindings_info.interactionProfile = m_profile;
|
bindings_info.interactionProfile = m_profile;
|
||||||
bindings_info.countSuggestedBindings = 1;
|
bindings_info.countSuggestedBindings = 1;
|
||||||
|
|
||||||
for (uint32_t interaction_idx = 0; interaction_idx < info.count_interaction_paths;
|
for (uint32_t subaction_idx = 0; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
|
||||||
++interaction_idx) {
|
const char *subaction_path_str = info.subaction_paths[subaction_idx];
|
||||||
const char *interaction_path = info.interaction_paths[interaction_idx];
|
const GHOST_XrActionBindingInfo &binding_info = info.bindings[subaction_idx];
|
||||||
|
|
||||||
|
const std::string interaction_path = std::string(subaction_path_str) +
|
||||||
|
binding_info.component_path;
|
||||||
if (m_bindings.find(interaction_path) != m_bindings.end()) {
|
if (m_bindings.find(interaction_path) != m_bindings.end()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
XrActionSuggestedBinding sbinding;
|
XrActionSuggestedBinding sbinding;
|
||||||
sbinding.action = action;
|
sbinding.action = action;
|
||||||
CHECK_XR(xrStringToPath(instance, interaction_path, &sbinding.binding),
|
CHECK_XR(xrStringToPath(instance, interaction_path.data(), &sbinding.binding),
|
||||||
(std::string("Failed to get interaction path \"") + interaction_path + "\".").data());
|
(std::string("Failed to get interaction path \"") + interaction_path + "\".").data());
|
||||||
bindings_info.suggestedBindings = &sbinding;
|
bindings_info.suggestedBindings = &sbinding;
|
||||||
|
|
||||||
/* Although the bindings will be re-suggested in GHOST_XrSession::attachActionSets(), it
|
/* Although the bindings will be re-suggested in GHOST_XrSession::attachActionSets(), it
|
||||||
* greatly improves error checking to suggest them here first. */
|
* greatly improves error checking to suggest them here first. */
|
||||||
CHECK_XR(xrSuggestInteractionProfileBindings(instance, &bindings_info),
|
CHECK_XR(xrSuggestInteractionProfileBindings(instance, &bindings_info),
|
||||||
(std::string("Failed to create binding for profile \"") + profile_path +
|
(std::string("Failed to create binding for action \"") + info.action_name +
|
||||||
"\" and action \"" + info.action_name +
|
"\" and profile \"" + info.profile_path +
|
||||||
"\". Are the profile and action paths correct?")
|
"\". Are the action and profile paths correct?")
|
||||||
.data());
|
.data());
|
||||||
|
|
||||||
m_bindings.insert({interaction_path, sbinding.binding});
|
m_bindings.insert({interaction_path, sbinding.binding});
|
||||||
|
|
||||||
|
if (m_subaction_data.find(subaction_path_str) == m_subaction_data.end()) {
|
||||||
|
std::map<std::string, GHOST_XrSubactionData>::iterator it =
|
||||||
|
m_subaction_data
|
||||||
|
.emplace(
|
||||||
|
std::piecewise_construct, std::make_tuple(subaction_path_str), std::make_tuple())
|
||||||
|
.first;
|
||||||
|
GHOST_XrSubactionData &subaction = it->second;
|
||||||
|
|
||||||
|
CHECK_XR(xrStringToPath(instance, subaction_path_str, &subaction.subaction_path),
|
||||||
|
(std::string("Failed to get user path \"") + subaction_path_str + "\".").data());
|
||||||
|
|
||||||
|
if (is_float_action || is_button_action) {
|
||||||
|
if (is_float_action) {
|
||||||
|
subaction.float_threshold = binding_info.float_threshold;
|
||||||
}
|
}
|
||||||
|
if (is_button_action) {
|
||||||
|
subaction.axis_flag = binding_info.axis_flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (is_pose_action) {
|
||||||
|
/* Create action space for pose bindings. */
|
||||||
|
subaction.space = std::make_unique<GHOST_XrActionSpace>(session,
|
||||||
|
action,
|
||||||
|
info.action_name,
|
||||||
|
info.profile_path,
|
||||||
|
subaction.subaction_path,
|
||||||
|
subaction_path_str,
|
||||||
|
binding_info.pose);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
XrPath GHOST_XrActionProfile::getProfile() const
|
||||||
|
{
|
||||||
|
return m_profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GHOST_XrSubactionData *GHOST_XrActionProfile::getSubaction(XrPath subaction_path) const
|
||||||
|
{
|
||||||
|
for (auto &[subaction_path_str, subaction] : m_subaction_data) {
|
||||||
|
if (subaction.subaction_path == subaction_path) {
|
||||||
|
return &subaction;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GHOST_XrActionProfile::getBindings(
|
void GHOST_XrActionProfile::getBindings(
|
||||||
@@ -152,6 +200,8 @@ GHOST_XrAction::GHOST_XrAction(XrInstance instance,
|
|||||||
const GHOST_XrActionInfo &info)
|
const GHOST_XrActionInfo &info)
|
||||||
: m_type(info.type),
|
: m_type(info.type),
|
||||||
m_states(info.states),
|
m_states(info.states),
|
||||||
|
m_float_thresholds(info.float_thresholds),
|
||||||
|
m_axis_flags(info.axis_flags),
|
||||||
m_custom_data_(
|
m_custom_data_(
|
||||||
std::make_unique<GHOST_C_CustomDataWrapper>(info.customdata, info.customdata_free_fn))
|
std::make_unique<GHOST_C_CustomDataWrapper>(info.customdata, info.customdata_free_fn))
|
||||||
{
|
{
|
||||||
@@ -201,52 +251,25 @@ GHOST_XrAction::~GHOST_XrAction()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GHOST_XrAction::createSpace(XrInstance instance,
|
|
||||||
XrSession session,
|
|
||||||
const GHOST_XrActionSpaceInfo &info)
|
|
||||||
{
|
|
||||||
uint32_t subaction_idx = 0;
|
|
||||||
for (; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
|
|
||||||
if (m_spaces.find(info.subaction_paths[subaction_idx]) != m_spaces.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (subaction_idx = 0; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
|
|
||||||
m_spaces.emplace(std::piecewise_construct,
|
|
||||||
std::make_tuple(info.subaction_paths[subaction_idx]),
|
|
||||||
std::make_tuple(instance, session, m_action, info, subaction_idx));
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GHOST_XrAction::destroySpace(const char *subaction_path)
|
|
||||||
{
|
|
||||||
if (m_spaces.find(subaction_path) != m_spaces.end()) {
|
|
||||||
m_spaces.erase(subaction_path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GHOST_XrAction::createBinding(XrInstance instance,
|
bool GHOST_XrAction::createBinding(XrInstance instance,
|
||||||
const char *profile_path,
|
XrSession session,
|
||||||
const GHOST_XrActionBindingInfo &info)
|
const GHOST_XrActionProfileInfo &info)
|
||||||
{
|
{
|
||||||
if (m_profiles.find(profile_path) != m_profiles.end()) {
|
if (m_profiles.find(info.profile_path) != m_profiles.end()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_profiles.emplace(std::piecewise_construct,
|
m_profiles.emplace(std::piecewise_construct,
|
||||||
std::make_tuple(profile_path),
|
std::make_tuple(info.profile_path),
|
||||||
std::make_tuple(instance, m_action, profile_path, info));
|
std::make_tuple(instance, session, m_action, m_type, info));
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GHOST_XrAction::destroyBinding(const char *interaction_profile_path)
|
void GHOST_XrAction::destroyBinding(const char *profile_path)
|
||||||
{
|
{
|
||||||
if (m_profiles.find(interaction_profile_path) != m_profiles.end()) {
|
if (m_profiles.find(profile_path) != m_profiles.end()) {
|
||||||
m_profiles.erase(interaction_profile_path);
|
m_profiles.erase(profile_path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,6 +278,10 @@ void GHOST_XrAction::updateState(XrSession session,
|
|||||||
XrSpace reference_space,
|
XrSpace reference_space,
|
||||||
const XrTime &predicted_display_time)
|
const XrTime &predicted_display_time)
|
||||||
{
|
{
|
||||||
|
const bool is_float_action = (m_type == GHOST_kXrActionTypeFloatInput ||
|
||||||
|
m_type == GHOST_kXrActionTypeVector2fInput);
|
||||||
|
const bool is_button_action = (is_float_action || m_type == GHOST_kXrActionTypeBooleanInput);
|
||||||
|
|
||||||
XrActionStateGetInfo state_info{XR_TYPE_ACTION_STATE_GET_INFO};
|
XrActionStateGetInfo state_info{XR_TYPE_ACTION_STATE_GET_INFO};
|
||||||
state_info.action = m_action;
|
state_info.action = m_action;
|
||||||
|
|
||||||
@@ -262,6 +289,28 @@ void GHOST_XrAction::updateState(XrSession session,
|
|||||||
for (size_t subaction_idx = 0; subaction_idx < count_subaction_paths; ++subaction_idx) {
|
for (size_t subaction_idx = 0; subaction_idx < count_subaction_paths; ++subaction_idx) {
|
||||||
state_info.subactionPath = m_subaction_paths[subaction_idx];
|
state_info.subactionPath = m_subaction_paths[subaction_idx];
|
||||||
|
|
||||||
|
/* Set subaction data based on current interaction profile. */
|
||||||
|
XrInteractionProfileState profile_state{XR_TYPE_INTERACTION_PROFILE_STATE};
|
||||||
|
CHECK_XR(xrGetCurrentInteractionProfile(session, state_info.subactionPath, &profile_state),
|
||||||
|
"Failed to get current interaction profile.");
|
||||||
|
|
||||||
|
const GHOST_XrSubactionData *subaction = nullptr;
|
||||||
|
for (auto &[profile_path, profile] : m_profiles) {
|
||||||
|
if (profile.getProfile() == profile_state.interactionProfile) {
|
||||||
|
subaction = profile.getSubaction(state_info.subactionPath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subaction != nullptr) {
|
||||||
|
if (is_float_action) {
|
||||||
|
m_float_thresholds[subaction_idx] = subaction->float_threshold;
|
||||||
|
}
|
||||||
|
if (is_button_action) {
|
||||||
|
m_axis_flags[subaction_idx] = subaction->axis_flag;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
case GHOST_kXrActionTypeBooleanInput: {
|
case GHOST_kXrActionTypeBooleanInput: {
|
||||||
XrActionStateBoolean state{XR_TYPE_ACTION_STATE_BOOLEAN};
|
XrActionStateBoolean state{XR_TYPE_ACTION_STATE_BOOLEAN};
|
||||||
@@ -299,14 +348,9 @@ void GHOST_XrAction::updateState(XrSession session,
|
|||||||
xrGetActionStatePose(session, &state_info, &state),
|
xrGetActionStatePose(session, &state_info, &state),
|
||||||
(std::string("Failed to get state for pose action \"") + action_name + "\".").data());
|
(std::string("Failed to get state for pose action \"") + action_name + "\".").data());
|
||||||
if (state.isActive) {
|
if (state.isActive) {
|
||||||
XrSpace pose_space = XR_NULL_HANDLE;
|
XrSpace pose_space = ((subaction != nullptr) && (subaction->space != nullptr)) ?
|
||||||
for (auto &[path, space] : m_spaces) {
|
subaction->space->getSpace() :
|
||||||
if (space.getSubactionPath() == state_info.subactionPath) {
|
XR_NULL_HANDLE;
|
||||||
pose_space = space.getSpace();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pose_space != XR_NULL_HANDLE) {
|
if (pose_space != XR_NULL_HANDLE) {
|
||||||
XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
|
XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
|
||||||
CHECK_XR(
|
CHECK_XR(
|
||||||
|
|||||||
@@ -34,38 +34,53 @@
|
|||||||
class GHOST_XrActionSpace {
|
class GHOST_XrActionSpace {
|
||||||
public:
|
public:
|
||||||
GHOST_XrActionSpace() = delete; /* Default constructor for map storage. */
|
GHOST_XrActionSpace() = delete; /* Default constructor for map storage. */
|
||||||
GHOST_XrActionSpace(XrInstance instance,
|
GHOST_XrActionSpace(XrSession session,
|
||||||
XrSession session,
|
|
||||||
XrAction action,
|
XrAction action,
|
||||||
const GHOST_XrActionSpaceInfo &info,
|
const char *action_name,
|
||||||
uint32_t subaction_idx);
|
const char *profile_path,
|
||||||
|
XrPath subaction_path,
|
||||||
|
const char *subaction_path_str,
|
||||||
|
const GHOST_XrPose &pose);
|
||||||
~GHOST_XrActionSpace();
|
~GHOST_XrActionSpace();
|
||||||
|
|
||||||
XrSpace getSpace() const;
|
XrSpace getSpace() const;
|
||||||
const XrPath &getSubactionPath() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XrSpace m_space = XR_NULL_HANDLE;
|
XrSpace m_space = XR_NULL_HANDLE;
|
||||||
XrPath m_subaction_path = XR_NULL_PATH;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
typedef struct GHOST_XrSubactionData {
|
||||||
|
XrPath subaction_path = XR_NULL_PATH;
|
||||||
|
float float_threshold;
|
||||||
|
int16_t axis_flag;
|
||||||
|
std::unique_ptr<GHOST_XrActionSpace> space = nullptr;
|
||||||
|
} GHOST_XrSubactionData;
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
class GHOST_XrActionProfile {
|
class GHOST_XrActionProfile {
|
||||||
public:
|
public:
|
||||||
GHOST_XrActionProfile() = delete; /* Default constructor for map storage. */
|
GHOST_XrActionProfile() = delete; /* Default constructor for map storage. */
|
||||||
GHOST_XrActionProfile(XrInstance instance,
|
GHOST_XrActionProfile(XrInstance instance,
|
||||||
|
XrSession session,
|
||||||
XrAction action,
|
XrAction action,
|
||||||
const char *profile_path,
|
GHOST_XrActionType type,
|
||||||
const GHOST_XrActionBindingInfo &info);
|
const GHOST_XrActionProfileInfo &info);
|
||||||
~GHOST_XrActionProfile() = default;
|
~GHOST_XrActionProfile() = default;
|
||||||
|
|
||||||
|
XrPath getProfile() const;
|
||||||
|
const GHOST_XrSubactionData *getSubaction(XrPath subaction_path) const;
|
||||||
void getBindings(XrAction action,
|
void getBindings(XrAction action,
|
||||||
std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;
|
std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XrPath m_profile = XR_NULL_PATH;
|
XrPath m_profile = XR_NULL_PATH;
|
||||||
/* Bindings identified by interaction (user (subaction) + component) path. */
|
|
||||||
|
/** Subaction data identified by user (subaction) path. */
|
||||||
|
std::map<std::string, GHOST_XrSubactionData> m_subaction_data;
|
||||||
|
/** Bindings identified by interaction (user (subaction) + component) path. */
|
||||||
std::map<std::string, XrPath> m_bindings;
|
std::map<std::string, XrPath> m_bindings;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -77,12 +92,9 @@ class GHOST_XrAction {
|
|||||||
GHOST_XrAction(XrInstance instance, XrActionSet action_set, const GHOST_XrActionInfo &info);
|
GHOST_XrAction(XrInstance instance, XrActionSet action_set, const GHOST_XrActionInfo &info);
|
||||||
~GHOST_XrAction();
|
~GHOST_XrAction();
|
||||||
|
|
||||||
bool createSpace(XrInstance instance, XrSession session, const GHOST_XrActionSpaceInfo &info);
|
|
||||||
void destroySpace(const char *subaction_path);
|
|
||||||
|
|
||||||
bool createBinding(XrInstance instance,
|
bool createBinding(XrInstance instance,
|
||||||
const char *profile_path,
|
XrSession session,
|
||||||
const GHOST_XrActionBindingInfo &info);
|
const GHOST_XrActionProfileInfo &info);
|
||||||
void destroyBinding(const char *profile_path);
|
void destroyBinding(const char *profile_path);
|
||||||
|
|
||||||
void updateState(XrSession session,
|
void updateState(XrSession session,
|
||||||
@@ -105,12 +117,13 @@ class GHOST_XrAction {
|
|||||||
std::vector<XrPath> m_subaction_paths;
|
std::vector<XrPath> m_subaction_paths;
|
||||||
/** States for each subaction path. */
|
/** States for each subaction path. */
|
||||||
void *m_states;
|
void *m_states;
|
||||||
|
/** Input thresholds/regions for each subaction path. */
|
||||||
|
float *m_float_thresholds;
|
||||||
|
int16_t *m_axis_flags;
|
||||||
|
|
||||||
std::unique_ptr<GHOST_C_CustomDataWrapper> m_custom_data_ = nullptr; /* wmXrAction */
|
std::unique_ptr<GHOST_C_CustomDataWrapper> m_custom_data_ = nullptr; /* wmXrAction */
|
||||||
|
|
||||||
/* Spaces identified by user (subaction) path. */
|
/** Profiles identified by interaction profile path. */
|
||||||
std::map<std::string, GHOST_XrActionSpace> m_spaces;
|
|
||||||
/* Profiles identified by interaction profile path. */
|
|
||||||
std::map<std::string, GHOST_XrActionProfile> m_profiles;
|
std::map<std::string, GHOST_XrActionProfile> m_profiles;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -610,57 +610,6 @@ void GHOST_XrSession::destroyActions(const char *action_set_name,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GHOST_XrSession::createActionSpaces(const char *action_set_name,
|
|
||||||
uint32_t count,
|
|
||||||
const GHOST_XrActionSpaceInfo *infos)
|
|
||||||
{
|
|
||||||
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
|
||||||
if (action_set == nullptr) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
XrInstance instance = m_context->getInstance();
|
|
||||||
XrSession session = m_oxr->session;
|
|
||||||
|
|
||||||
for (uint32_t action_idx = 0; action_idx < count; ++action_idx) {
|
|
||||||
const GHOST_XrActionSpaceInfo &info = infos[action_idx];
|
|
||||||
|
|
||||||
GHOST_XrAction *action = action_set->findAction(info.action_name);
|
|
||||||
if (action == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!action->createSpace(instance, session, info)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GHOST_XrSession::destroyActionSpaces(const char *action_set_name,
|
|
||||||
uint32_t count,
|
|
||||||
const GHOST_XrActionSpaceInfo *infos)
|
|
||||||
{
|
|
||||||
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
|
||||||
if (action_set == nullptr) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t action_idx = 0; action_idx < count; ++action_idx) {
|
|
||||||
const GHOST_XrActionSpaceInfo &info = infos[action_idx];
|
|
||||||
|
|
||||||
GHOST_XrAction *action = action_set->findAction(info.action_name);
|
|
||||||
if (action == nullptr) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t subaction_idx = 0; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
|
|
||||||
action->destroySpace(info.subaction_paths[subaction_idx]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GHOST_XrSession::createActionBindings(const char *action_set_name,
|
bool GHOST_XrSession::createActionBindings(const char *action_set_name,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
const GHOST_XrActionProfileInfo *infos)
|
const GHOST_XrActionProfileInfo *infos)
|
||||||
@@ -671,21 +620,17 @@ bool GHOST_XrSession::createActionBindings(const char *action_set_name,
|
|||||||
}
|
}
|
||||||
|
|
||||||
XrInstance instance = m_context->getInstance();
|
XrInstance instance = m_context->getInstance();
|
||||||
|
XrSession session = m_oxr->session;
|
||||||
|
|
||||||
for (uint32_t profile_idx = 0; profile_idx < count; ++profile_idx) {
|
for (uint32_t profile_idx = 0; profile_idx < count; ++profile_idx) {
|
||||||
const GHOST_XrActionProfileInfo &info = infos[profile_idx];
|
const GHOST_XrActionProfileInfo &info = infos[profile_idx];
|
||||||
const char *profile_path = info.profile_path;
|
|
||||||
|
|
||||||
for (uint32_t binding_idx = 0; binding_idx < info.count_bindings; ++binding_idx) {
|
GHOST_XrAction *action = action_set->findAction(info.action_name);
|
||||||
const GHOST_XrActionBindingInfo &binding = info.bindings[binding_idx];
|
|
||||||
|
|
||||||
GHOST_XrAction *action = action_set->findAction(binding.action_name);
|
|
||||||
if (action == nullptr) {
|
if (action == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
action->createBinding(instance, profile_path, binding);
|
action->createBinding(instance, session, info);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@@ -693,27 +638,21 @@ bool GHOST_XrSession::createActionBindings(const char *action_set_name,
|
|||||||
|
|
||||||
void GHOST_XrSession::destroyActionBindings(const char *action_set_name,
|
void GHOST_XrSession::destroyActionBindings(const char *action_set_name,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
const GHOST_XrActionProfileInfo *infos)
|
const char *const *action_names,
|
||||||
|
const char *const *profile_paths)
|
||||||
{
|
{
|
||||||
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
|
||||||
if (action_set == nullptr) {
|
if (action_set == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint32_t profile_idx = 0; profile_idx < count; ++profile_idx) {
|
for (uint32_t i = 0; i < count; ++i) {
|
||||||
const GHOST_XrActionProfileInfo &info = infos[profile_idx];
|
GHOST_XrAction *action = action_set->findAction(action_names[i]);
|
||||||
const char *profile_path = info.profile_path;
|
|
||||||
|
|
||||||
for (uint32_t binding_idx = 0; binding_idx < info.count_bindings; ++binding_idx) {
|
|
||||||
const GHOST_XrActionBindingInfo &binding = info.bindings[binding_idx];
|
|
||||||
|
|
||||||
GHOST_XrAction *action = action_set->findAction(binding.action_name);
|
|
||||||
if (action == nullptr) {
|
if (action == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
action->destroyBinding(profile_path);
|
action->destroyBinding(profile_paths[i]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -60,18 +60,13 @@ class GHOST_XrSession {
|
|||||||
void destroyActions(const char *action_set_name,
|
void destroyActions(const char *action_set_name,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
const char *const *action_names);
|
const char *const *action_names);
|
||||||
bool createActionSpaces(const char *action_set_name,
|
|
||||||
uint32_t count,
|
|
||||||
const GHOST_XrActionSpaceInfo *infos);
|
|
||||||
void destroyActionSpaces(const char *action_set_name,
|
|
||||||
uint32_t count,
|
|
||||||
const GHOST_XrActionSpaceInfo *infos);
|
|
||||||
bool createActionBindings(const char *action_set_name,
|
bool createActionBindings(const char *action_set_name,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
const GHOST_XrActionProfileInfo *infos);
|
const GHOST_XrActionProfileInfo *infos);
|
||||||
void destroyActionBindings(const char *action_set_name,
|
void destroyActionBindings(const char *action_set_name,
|
||||||
uint32_t count,
|
uint32_t count,
|
||||||
const GHOST_XrActionProfileInfo *infos);
|
const char *const *action_names,
|
||||||
|
const char *const *profile_paths);
|
||||||
bool attachActionSets();
|
bool attachActionSets();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -74,6 +74,15 @@ typedef enum eXrOpFlag {
|
|||||||
XR_OP_MODAL = 2,
|
XR_OP_MODAL = 2,
|
||||||
} eXrOpFlag;
|
} eXrOpFlag;
|
||||||
|
|
||||||
|
typedef enum eXrAxisFlag {
|
||||||
|
/** For axis-based inputs (thumbstick/trackpad/etc). Determines the region for action execution
|
||||||
|
(mutually exclusive per axis). */
|
||||||
|
XR_AXIS0_POS = (1 << 0),
|
||||||
|
XR_AXIS0_NEG = (1 << 1),
|
||||||
|
XR_AXIS1_POS = (1 << 2),
|
||||||
|
XR_AXIS1_NEG = (1 << 3),
|
||||||
|
} eXrAxisFlag;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ if(WITH_XR_OPENXR)
|
|||||||
|
|
||||||
list(APPEND SRC
|
list(APPEND SRC
|
||||||
xr/intern/wm_xr.c
|
xr/intern/wm_xr.c
|
||||||
xr/intern/wm_xr_actions.c
|
xr/intern/wm_xr_action.c
|
||||||
xr/intern/wm_xr_draw.c
|
xr/intern/wm_xr_draw.c
|
||||||
xr/intern/wm_xr_session.c
|
xr/intern/wm_xr_session.c
|
||||||
|
|
||||||
|
|||||||
@@ -978,34 +978,24 @@ bool WM_xr_action_create(wmXrData *xr,
|
|||||||
eXrActionType type,
|
eXrActionType type,
|
||||||
unsigned int count_subaction_paths,
|
unsigned int count_subaction_paths,
|
||||||
const char **subaction_paths,
|
const char **subaction_paths,
|
||||||
const float *float_threshold,
|
|
||||||
struct wmOperatorType *ot,
|
struct wmOperatorType *ot,
|
||||||
struct IDProperty *op_properties,
|
struct IDProperty *op_properties,
|
||||||
eXrOpFlag op_flag);
|
eXrOpFlag op_flag);
|
||||||
void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char *action_name);
|
void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char *action_name);
|
||||||
bool WM_xr_action_space_create(wmXrData *xr,
|
|
||||||
const char *action_set_name,
|
|
||||||
const char *action_name,
|
|
||||||
unsigned int count_subaction_paths,
|
|
||||||
const char **subaction_paths,
|
|
||||||
const struct wmXrPose *poses);
|
|
||||||
void WM_xr_action_space_destroy(wmXrData *xr,
|
|
||||||
const char *action_set_name,
|
|
||||||
const char *action_name,
|
|
||||||
unsigned int count_subaction_paths,
|
|
||||||
const char **subaction_paths);
|
|
||||||
bool WM_xr_action_binding_create(wmXrData *xr,
|
bool WM_xr_action_binding_create(wmXrData *xr,
|
||||||
const char *action_set_name,
|
const char *action_set_name,
|
||||||
const char *profile_path,
|
|
||||||
const char *action_name,
|
const char *action_name,
|
||||||
unsigned int count_interaction_paths,
|
const char *profile_path,
|
||||||
const char **interaction_paths);
|
unsigned int count_subaction_paths,
|
||||||
|
const char **subaction_paths,
|
||||||
|
const char **component_paths,
|
||||||
|
const float *float_thresholds,
|
||||||
|
const eXrAxisFlag *axis_flags,
|
||||||
|
const struct wmXrPose *poses);
|
||||||
void WM_xr_action_binding_destroy(wmXrData *xr,
|
void WM_xr_action_binding_destroy(wmXrData *xr,
|
||||||
const char *action_set_name,
|
const char *action_set_name,
|
||||||
const char *profile_path,
|
|
||||||
const char *action_name,
|
const char *action_name,
|
||||||
unsigned int count_interaction_paths,
|
const char *profile_path);
|
||||||
const char **interaction_paths);
|
|
||||||
|
|
||||||
/* If action_set_name is NULL, then all action sets will be treated as active. */
|
/* If action_set_name is NULL, then all action sets will be treated as active. */
|
||||||
bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name);
|
bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name);
|
||||||
|
|||||||
@@ -68,7 +68,6 @@ static wmXrAction *action_create(const char *action_name,
|
|||||||
eXrActionType type,
|
eXrActionType type,
|
||||||
unsigned int count_subaction_paths,
|
unsigned int count_subaction_paths,
|
||||||
const char **subaction_paths,
|
const char **subaction_paths,
|
||||||
const float *float_threshold,
|
|
||||||
wmOperatorType *ot,
|
wmOperatorType *ot,
|
||||||
IDProperty *op_properties,
|
IDProperty *op_properties,
|
||||||
eXrOpFlag op_flag)
|
eXrOpFlag op_flag)
|
||||||
@@ -109,10 +108,15 @@ static wmXrAction *action_create(const char *action_name,
|
|||||||
action->states = MEM_calloc_arrayN(count, size, "XrAction_States");
|
action->states = MEM_calloc_arrayN(count, size, "XrAction_States");
|
||||||
action->states_prev = MEM_calloc_arrayN(count, size, "XrAction_StatesPrev");
|
action->states_prev = MEM_calloc_arrayN(count, size, "XrAction_StatesPrev");
|
||||||
|
|
||||||
if (float_threshold) {
|
const bool is_float_action = (type == XR_FLOAT_INPUT || type == XR_VECTOR2F_INPUT);
|
||||||
BLI_assert(type == XR_FLOAT_INPUT || type == XR_VECTOR2F_INPUT);
|
const bool is_button_action = (is_float_action || type == XR_BOOLEAN_INPUT);
|
||||||
action->float_threshold = *float_threshold;
|
if (is_float_action) {
|
||||||
CLAMP(action->float_threshold, 0.0f, 1.0f);
|
action->float_thresholds = MEM_calloc_arrayN(
|
||||||
|
count, sizeof(*action->float_thresholds), "XrAction_FloatThresholds");
|
||||||
|
}
|
||||||
|
if (is_button_action) {
|
||||||
|
action->axis_flags = MEM_calloc_arrayN(
|
||||||
|
count, sizeof(*action->axis_flags), "XrAction_AxisFlags");
|
||||||
}
|
}
|
||||||
|
|
||||||
action->ot = ot;
|
action->ot = ot;
|
||||||
@@ -140,6 +144,9 @@ static void action_destroy(void *val)
|
|||||||
MEM_SAFE_FREE(action->states);
|
MEM_SAFE_FREE(action->states);
|
||||||
MEM_SAFE_FREE(action->states_prev);
|
MEM_SAFE_FREE(action->states_prev);
|
||||||
|
|
||||||
|
MEM_SAFE_FREE(action->float_thresholds);
|
||||||
|
MEM_SAFE_FREE(action->axis_flags);
|
||||||
|
|
||||||
MEM_freeN(action);
|
MEM_freeN(action);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -198,7 +205,6 @@ bool WM_xr_action_create(wmXrData *xr,
|
|||||||
eXrActionType type,
|
eXrActionType type,
|
||||||
unsigned int count_subaction_paths,
|
unsigned int count_subaction_paths,
|
||||||
const char **subaction_paths,
|
const char **subaction_paths,
|
||||||
const float *float_threshold,
|
|
||||||
wmOperatorType *ot,
|
wmOperatorType *ot,
|
||||||
IDProperty *op_properties,
|
IDProperty *op_properties,
|
||||||
eXrOpFlag op_flag)
|
eXrOpFlag op_flag)
|
||||||
@@ -211,7 +217,6 @@ bool WM_xr_action_create(wmXrData *xr,
|
|||||||
type,
|
type,
|
||||||
count_subaction_paths,
|
count_subaction_paths,
|
||||||
subaction_paths,
|
subaction_paths,
|
||||||
float_threshold,
|
|
||||||
ot,
|
ot,
|
||||||
op_properties,
|
op_properties,
|
||||||
op_flag);
|
op_flag);
|
||||||
@@ -221,6 +226,8 @@ bool WM_xr_action_create(wmXrData *xr,
|
|||||||
.count_subaction_paths = count_subaction_paths,
|
.count_subaction_paths = count_subaction_paths,
|
||||||
.subaction_paths = subaction_paths,
|
.subaction_paths = subaction_paths,
|
||||||
.states = action->states,
|
.states = action->states,
|
||||||
|
.float_thresholds = action->float_thresholds,
|
||||||
|
.axis_flags = (int16_t *)action->axis_flags,
|
||||||
.customdata_free_fn = action_destroy,
|
.customdata_free_fn = action_destroy,
|
||||||
.customdata = action,
|
.customdata = action,
|
||||||
};
|
};
|
||||||
@@ -257,6 +264,11 @@ void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wmXrAction *action = action_find(xr, action_set_name, action_name);
|
||||||
|
if (!action) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (action_set->controller_pose_action &&
|
if (action_set->controller_pose_action &&
|
||||||
STREQ(action_set->controller_pose_action->name, action_name)) {
|
STREQ(action_set->controller_pose_action->name, action_name)) {
|
||||||
if (action_set == xr->runtime->session_state.active_action_set) {
|
if (action_set == xr->runtime->session_state.active_action_set) {
|
||||||
@@ -269,98 +281,60 @@ void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char
|
|||||||
action_set->active_modal_action = NULL;
|
action_set->active_modal_action = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
wmXrAction *action = action_find(xr, action_set_name, action_name);
|
GHOST_XrDestroyActions(xr->runtime->context, action_set_name, 1, &action_name);
|
||||||
if (!action) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WM_xr_action_space_create(wmXrData *xr,
|
|
||||||
const char *action_set_name,
|
|
||||||
const char *action_name,
|
|
||||||
unsigned int count_subaction_paths,
|
|
||||||
const char **subaction_paths,
|
|
||||||
const wmXrPose *poses)
|
|
||||||
{
|
|
||||||
GHOST_XrActionSpaceInfo info = {
|
|
||||||
.action_name = action_name,
|
|
||||||
.count_subaction_paths = count_subaction_paths,
|
|
||||||
.subaction_paths = subaction_paths,
|
|
||||||
};
|
|
||||||
|
|
||||||
GHOST_XrPose *ghost_poses = MEM_malloc_arrayN(
|
|
||||||
count_subaction_paths, sizeof(*ghost_poses), __func__);
|
|
||||||
for (unsigned int i = 0; i < count_subaction_paths; ++i) {
|
|
||||||
const wmXrPose *pose = &poses[i];
|
|
||||||
GHOST_XrPose *ghost_pose = &ghost_poses[i];
|
|
||||||
copy_v3_v3(ghost_pose->position, pose->position);
|
|
||||||
copy_qt_qt(ghost_pose->orientation_quat, pose->orientation_quat);
|
|
||||||
}
|
|
||||||
info.poses = ghost_poses;
|
|
||||||
|
|
||||||
bool ret = GHOST_XrCreateActionSpaces(xr->runtime->context, action_set_name, 1, &info) ? true :
|
|
||||||
false;
|
|
||||||
MEM_freeN(ghost_poses);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WM_xr_action_space_destroy(wmXrData *xr,
|
|
||||||
const char *action_set_name,
|
|
||||||
const char *action_name,
|
|
||||||
unsigned int count_subaction_paths,
|
|
||||||
const char **subaction_paths)
|
|
||||||
{
|
|
||||||
GHOST_XrActionSpaceInfo info = {
|
|
||||||
.action_name = action_name,
|
|
||||||
.count_subaction_paths = count_subaction_paths,
|
|
||||||
.subaction_paths = subaction_paths,
|
|
||||||
};
|
|
||||||
|
|
||||||
GHOST_XrDestroyActionSpaces(xr->runtime->context, action_set_name, 1, &info);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool WM_xr_action_binding_create(wmXrData *xr,
|
bool WM_xr_action_binding_create(wmXrData *xr,
|
||||||
const char *action_set_name,
|
const char *action_set_name,
|
||||||
const char *profile_path,
|
|
||||||
const char *action_name,
|
const char *action_name,
|
||||||
unsigned int count_interaction_paths,
|
const char *profile_path,
|
||||||
const char **interaction_paths)
|
unsigned int count_subaction_paths,
|
||||||
|
const char **subaction_paths,
|
||||||
|
const char **component_paths,
|
||||||
|
const float *float_thresholds,
|
||||||
|
const eXrAxisFlag *axis_flags,
|
||||||
|
const struct wmXrPose *poses)
|
||||||
{
|
{
|
||||||
GHOST_XrActionBindingInfo binding_info = {
|
GHOST_XrActionBindingInfo *binding_infos = MEM_calloc_arrayN(
|
||||||
.action_name = action_name,
|
count_subaction_paths, sizeof(*binding_infos), __func__);
|
||||||
.count_interaction_paths = count_interaction_paths,
|
|
||||||
.interaction_paths = interaction_paths,
|
for (unsigned int i = 0; i < count_subaction_paths; ++i) {
|
||||||
};
|
GHOST_XrActionBindingInfo *binding_info = &binding_infos[i];
|
||||||
|
binding_info->component_path = component_paths[i];
|
||||||
|
if (float_thresholds) {
|
||||||
|
binding_info->float_threshold = float_thresholds[i];
|
||||||
|
}
|
||||||
|
if (axis_flags) {
|
||||||
|
binding_info->axis_flag = axis_flags[i];
|
||||||
|
}
|
||||||
|
if (poses) {
|
||||||
|
copy_v3_v3(binding_info->pose.position, poses[i].position);
|
||||||
|
copy_qt_qt(binding_info->pose.orientation_quat, poses[i].orientation_quat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
GHOST_XrActionProfileInfo profile_info = {
|
GHOST_XrActionProfileInfo profile_info = {
|
||||||
|
.action_name = action_name,
|
||||||
.profile_path = profile_path,
|
.profile_path = profile_path,
|
||||||
.count_bindings = 1,
|
.count_subaction_paths = count_subaction_paths,
|
||||||
.bindings = &binding_info,
|
.subaction_paths = subaction_paths,
|
||||||
|
.bindings = binding_infos,
|
||||||
};
|
};
|
||||||
|
|
||||||
return GHOST_XrCreateActionBindings(xr->runtime->context, action_set_name, 1, &profile_info);
|
bool ret = GHOST_XrCreateActionBindings(xr->runtime->context, action_set_name, 1, &profile_info);
|
||||||
|
|
||||||
|
MEM_freeN(binding_infos);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WM_xr_action_binding_destroy(wmXrData *xr,
|
void WM_xr_action_binding_destroy(wmXrData *xr,
|
||||||
const char *action_set_name,
|
const char *action_set_name,
|
||||||
const char *profile_path,
|
|
||||||
const char *action_name,
|
const char *action_name,
|
||||||
unsigned int count_interaction_paths,
|
const char *profile_path)
|
||||||
const char **interaction_paths)
|
|
||||||
{
|
{
|
||||||
GHOST_XrActionBindingInfo binding_info = {
|
GHOST_XrDestroyActionBindings(
|
||||||
.action_name = action_name,
|
xr->runtime->context, action_set_name, 1, &action_name, &profile_path);
|
||||||
.count_interaction_paths = count_interaction_paths,
|
|
||||||
.interaction_paths = interaction_paths,
|
|
||||||
};
|
|
||||||
|
|
||||||
GHOST_XrActionProfileInfo profile_info = {
|
|
||||||
.profile_path = profile_path,
|
|
||||||
.count_bindings = 1,
|
|
||||||
.bindings = &binding_info,
|
|
||||||
};
|
|
||||||
|
|
||||||
GHOST_XrDestroyActionBindings(xr->runtime->context, action_set_name, 1, &profile_info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name)
|
bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name)
|
||||||
@@ -427,12 +401,12 @@ bool WM_xr_action_state_get(const wmXrData *xr,
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BLI_assert(action->type == (eXrActionType)r_state->type);
|
r_state->type = (int)action->type;
|
||||||
|
|
||||||
/* Find the action state corresponding to the subaction path. */
|
/* Find the action state corresponding to the subaction path. */
|
||||||
for (unsigned int i = 0; i < action->count_subaction_paths; ++i) {
|
for (unsigned int i = 0; i < action->count_subaction_paths; ++i) {
|
||||||
if (STREQ(subaction_path, action->subaction_paths[i])) {
|
if (STREQ(subaction_path, action->subaction_paths[i])) {
|
||||||
switch ((eXrActionType)r_state->type) {
|
switch (action->type) {
|
||||||
case XR_BOOLEAN_INPUT:
|
case XR_BOOLEAN_INPUT:
|
||||||
r_state->state_boolean = ((bool *)action->states)[i];
|
r_state->state_boolean = ((bool *)action->states)[i];
|
||||||
break;
|
break;
|
||||||
@@ -122,8 +122,9 @@ typedef struct wmXrAction {
|
|||||||
/** Previous states, stored to determine XR events. */
|
/** Previous states, stored to determine XR events. */
|
||||||
void *states_prev;
|
void *states_prev;
|
||||||
|
|
||||||
/** Input threshold for float/vector2f actions. */
|
/** Input thresholds/regions for each subaction path. */
|
||||||
float float_threshold;
|
float *float_thresholds;
|
||||||
|
eXrAxisFlag *axis_flags;
|
||||||
|
|
||||||
/** The currently active subaction path (if any) for modal actions. */
|
/** The currently active subaction path (if any) for modal actions. */
|
||||||
char **active_modal_path;
|
char **active_modal_path;
|
||||||
|
|||||||
Reference in New Issue
Block a user