Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Kim <pk15950@gmail.com>2021-08-05 07:14:26 +0300
committerPeter Kim <pk15950@gmail.com>2021-08-05 07:14:26 +0300
commitd3d4be1db3a09084eb2ff329bb7a530a87481480 (patch)
tree176e8363ec94a58a070b93bc694abf264f20aec5
parentd1c5e2e050a57216f9555098313d65511455e042 (diff)
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
-rw-r--r--intern/ghost/GHOST_C-api.h19
-rw-r--r--intern/ghost/GHOST_Types.h24
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp29
-rw-r--r--intern/ghost/intern/GHOST_XrAction.cpp188
-rw-r--r--intern/ghost/intern/GHOST_XrAction.h47
-rw-r--r--intern/ghost/intern/GHOST_XrSession.cpp87
-rw-r--r--intern/ghost/intern/GHOST_XrSession.h9
-rw-r--r--source/blender/makesdna/DNA_xr_types.h9
-rw-r--r--source/blender/windowmanager/CMakeLists.txt2
-rw-r--r--source/blender/windowmanager/WM_api.h26
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_action.c (renamed from source/blender/windowmanager/xr/intern/wm_xr_actions.c)138
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h5
12 files changed, 256 insertions, 327 deletions
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index 46e3888a367..fea5a545807 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -1067,22 +1067,6 @@ void GHOST_XrDestroyActions(GHOST_XrContextHandle xr_context,
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.
*/
int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_context,
@@ -1096,7 +1080,8 @@ int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_context,
void GHOST_XrDestroyActionBindings(GHOST_XrContextHandle xr_context,
const char *action_set_name,
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.
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 94a3fd86b73..fb19b9535ad 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -719,29 +719,27 @@ typedef struct GHOST_XrActionInfo {
const char **subaction_paths;
/** States for each subaction path. */
void *states;
+ /** Input thresholds/regions for each subaction path. */
+ float *float_thresholds;
+ int16_t *axis_flags;
GHOST_XrCustomdataFreeFn customdata_free_fn;
void *customdata; /* wmXrAction */
} 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 {
- const char *action_name;
- uint32_t count_interaction_paths;
- /** Interaction path: User (sub-action) path + component path. */
- const char **interaction_paths;
+ const char *component_path;
+ float float_threshold;
+ int16_t axis_flag;
+ GHOST_XrPose pose;
} GHOST_XrActionBindingInfo;
typedef struct GHOST_XrActionProfileInfo {
+ const char *action_name;
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;
} GHOST_XrActionProfileInfo;
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index cb409595e50..0bc9be26eb1 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -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);
}
-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,
const char *action_set_name,
uint32_t count,
@@ -998,11 +976,14 @@ int GHOST_XrCreateActionBindings(GHOST_XrContextHandle xr_contexthandle,
void GHOST_XrDestroyActionBindings(GHOST_XrContextHandle xr_contexthandle,
const char *action_set_name,
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_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)
diff --git a/intern/ghost/intern/GHOST_XrAction.cpp b/intern/ghost/intern/GHOST_XrAction.cpp
index 9c4f7fbc7d8..676a3367ee1 100644
--- a/intern/ghost/intern/GHOST_XrAction.cpp
+++ b/intern/ghost/intern/GHOST_XrAction.cpp
@@ -33,24 +33,22 @@
*
* \{ */
-GHOST_XrActionSpace::GHOST_XrActionSpace(XrInstance instance,
- XrSession session,
+GHOST_XrActionSpace::GHOST_XrActionSpace(XrSession session,
XrAction action,
- const GHOST_XrActionSpaceInfo &info,
- uint32_t subaction_idx)
+ const char *action_name,
+ 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};
action_space_info.action = action;
- action_space_info.subactionPath = m_subaction_path;
- copy_ghost_pose_to_openxr_pose(info.poses[subaction_idx], action_space_info.poseInActionSpace);
+ action_space_info.subactionPath = subaction_path;
+ copy_ghost_pose_to_openxr_pose(pose, action_space_info.poseInActionSpace);
CHECK_XR(xrCreateActionSpace(session, &action_space_info, &m_space),
- (std::string("Failed to create space \"") + subaction_path + "\" for action \"" +
- info.action_name + "\".")
+ (std::string("Failed to create space \"") + subaction_path_str + "\" for action \"" +
+ action_name + "\" and profile \"" + profile_path + "\".")
.data());
}
@@ -66,11 +64,6 @@ XrSpace GHOST_XrActionSpace::getSpace() const
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,
+ XrSession session,
XrAction action,
- const char *profile_path,
- const GHOST_XrActionBindingInfo &info)
+ GHOST_XrActionType type,
+ const GHOST_XrActionProfileInfo &info)
{
- CHECK_XR(
- xrStringToPath(instance, profile_path, &m_profile),
- (std::string("Failed to get interaction profile path \"") + profile_path + "\".").data());
+ CHECK_XR(xrStringToPath(instance, info.profile_path, &m_profile),
+ (std::string("Failed to get interaction profile path \"") + info.profile_path + "\".")
+ .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. */
XrInteractionProfileSuggestedBinding bindings_info{
@@ -93,31 +92,80 @@ GHOST_XrActionProfile::GHOST_XrActionProfile(XrInstance instance,
bindings_info.interactionProfile = m_profile;
bindings_info.countSuggestedBindings = 1;
- for (uint32_t interaction_idx = 0; interaction_idx < info.count_interaction_paths;
- ++interaction_idx) {
- const char *interaction_path = info.interaction_paths[interaction_idx];
+ for (uint32_t subaction_idx = 0; subaction_idx < info.count_subaction_paths; ++subaction_idx) {
+ const char *subaction_path_str = info.subaction_paths[subaction_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()) {
continue;
}
XrActionSuggestedBinding sbinding;
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());
bindings_info.suggestedBindings = &sbinding;
/* Although the bindings will be re-suggested in GHOST_XrSession::attachActionSets(), it
* greatly improves error checking to suggest them here first. */
CHECK_XR(xrSuggestInteractionProfileBindings(instance, &bindings_info),
- (std::string("Failed to create binding for profile \"") + profile_path +
- "\" and action \"" + info.action_name +
- "\". Are the profile and action paths correct?")
+ (std::string("Failed to create binding for action \"") + info.action_name +
+ "\" and profile \"" + info.profile_path +
+ "\". Are the action and profile paths correct?")
.data());
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(
XrAction action, std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const
{
@@ -152,6 +200,8 @@ GHOST_XrAction::GHOST_XrAction(XrInstance instance,
const GHOST_XrActionInfo &info)
: m_type(info.type),
m_states(info.states),
+ m_float_thresholds(info.float_thresholds),
+ m_axis_flags(info.axis_flags),
m_custom_data_(
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,
- const char *profile_path,
- const GHOST_XrActionBindingInfo &info)
+ XrSession session,
+ 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;
}
m_profiles.emplace(std::piecewise_construct,
- std::make_tuple(profile_path),
- std::make_tuple(instance, m_action, profile_path, info));
+ std::make_tuple(info.profile_path),
+ std::make_tuple(instance, session, m_action, m_type, info));
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()) {
- m_profiles.erase(interaction_profile_path);
+ if (m_profiles.find(profile_path) != m_profiles.end()) {
+ m_profiles.erase(profile_path);
}
}
@@ -255,6 +278,10 @@ void GHOST_XrAction::updateState(XrSession session,
XrSpace reference_space,
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};
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) {
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) {
case GHOST_kXrActionTypeBooleanInput: {
XrActionStateBoolean state{XR_TYPE_ACTION_STATE_BOOLEAN};
@@ -299,14 +348,9 @@ void GHOST_XrAction::updateState(XrSession session,
xrGetActionStatePose(session, &state_info, &state),
(std::string("Failed to get state for pose action \"") + action_name + "\".").data());
if (state.isActive) {
- XrSpace pose_space = XR_NULL_HANDLE;
- for (auto &[path, space] : m_spaces) {
- if (space.getSubactionPath() == state_info.subactionPath) {
- pose_space = space.getSpace();
- break;
- }
- }
-
+ XrSpace pose_space = ((subaction != nullptr) && (subaction->space != nullptr)) ?
+ subaction->space->getSpace() :
+ XR_NULL_HANDLE;
if (pose_space != XR_NULL_HANDLE) {
XrSpaceLocation space_location{XR_TYPE_SPACE_LOCATION};
CHECK_XR(
diff --git a/intern/ghost/intern/GHOST_XrAction.h b/intern/ghost/intern/GHOST_XrAction.h
index 32445c616bd..e2a89e87278 100644
--- a/intern/ghost/intern/GHOST_XrAction.h
+++ b/intern/ghost/intern/GHOST_XrAction.h
@@ -34,38 +34,53 @@
class GHOST_XrActionSpace {
public:
GHOST_XrActionSpace() = delete; /* Default constructor for map storage. */
- GHOST_XrActionSpace(XrInstance instance,
- XrSession session,
+ GHOST_XrActionSpace(XrSession session,
XrAction action,
- const GHOST_XrActionSpaceInfo &info,
- uint32_t subaction_idx);
+ const char *action_name,
+ const char *profile_path,
+ XrPath subaction_path,
+ const char *subaction_path_str,
+ const GHOST_XrPose &pose);
~GHOST_XrActionSpace();
XrSpace getSpace() const;
- const XrPath &getSubactionPath() const;
private:
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 {
public:
GHOST_XrActionProfile() = delete; /* Default constructor for map storage. */
GHOST_XrActionProfile(XrInstance instance,
+ XrSession session,
XrAction action,
- const char *profile_path,
- const GHOST_XrActionBindingInfo &info);
+ GHOST_XrActionType type,
+ const GHOST_XrActionProfileInfo &info);
~GHOST_XrActionProfile() = default;
+ XrPath getProfile() const;
+ const GHOST_XrSubactionData *getSubaction(XrPath subaction_path) const;
void getBindings(XrAction action,
std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;
private:
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;
};
@@ -77,12 +92,9 @@ class GHOST_XrAction {
GHOST_XrAction(XrInstance instance, XrActionSet action_set, const GHOST_XrActionInfo &info);
~GHOST_XrAction();
- bool createSpace(XrInstance instance, XrSession session, const GHOST_XrActionSpaceInfo &info);
- void destroySpace(const char *subaction_path);
-
bool createBinding(XrInstance instance,
- const char *profile_path,
- const GHOST_XrActionBindingInfo &info);
+ XrSession session,
+ const GHOST_XrActionProfileInfo &info);
void destroyBinding(const char *profile_path);
void updateState(XrSession session,
@@ -105,12 +117,13 @@ class GHOST_XrAction {
std::vector<XrPath> m_subaction_paths;
/** States for each subaction path. */
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 */
- /* Spaces identified by user (subaction) path. */
- std::map<std::string, GHOST_XrActionSpace> m_spaces;
- /* Profiles identified by interaction profile path. */
+ /** Profiles identified by interaction profile path. */
std::map<std::string, GHOST_XrActionProfile> m_profiles;
};
diff --git a/intern/ghost/intern/GHOST_XrSession.cpp b/intern/ghost/intern/GHOST_XrSession.cpp
index 919d11d22a9..a29ec1cc560 100644
--- a/intern/ghost/intern/GHOST_XrSession.cpp
+++ b/intern/ghost/intern/GHOST_XrSession.cpp
@@ -610,9 +610,9 @@ 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)
+bool GHOST_XrSession::createActionBindings(const char *action_set_name,
+ uint32_t count,
+ const GHOST_XrActionProfileInfo *infos)
{
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
if (action_set == nullptr) {
@@ -622,98 +622,37 @@ bool GHOST_XrSession::createActionSpaces(const char *action_set_name,
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];
+ for (uint32_t profile_idx = 0; profile_idx < count; ++profile_idx) {
+ const GHOST_XrActionProfileInfo &info = infos[profile_idx];
GHOST_XrAction *action = action_set->findAction(info.action_name);
if (action == nullptr) {
continue;
}
- if (!action->createSpace(instance, session, info)) {
- return false;
- }
+ action->createBinding(instance, session, info);
}
return true;
}
-void GHOST_XrSession::destroyActionSpaces(const char *action_set_name,
- uint32_t count,
- const GHOST_XrActionSpaceInfo *infos)
+void GHOST_XrSession::destroyActionBindings(const char *action_set_name,
+ uint32_t count,
+ const char *const *action_names,
+ const char *const *profile_paths)
{
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);
+ for (uint32_t i = 0; i < count; ++i) {
+ GHOST_XrAction *action = action_set->findAction(action_names[i]);
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,
- uint32_t count,
- const GHOST_XrActionProfileInfo *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();
-
- for (uint32_t profile_idx = 0; profile_idx < count; ++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) {
- const GHOST_XrActionBindingInfo &binding = info.bindings[binding_idx];
-
- GHOST_XrAction *action = action_set->findAction(binding.action_name);
- if (action == nullptr) {
- continue;
- }
-
- action->createBinding(instance, profile_path, binding);
- }
- }
-
- return true;
-}
-
-void GHOST_XrSession::destroyActionBindings(const char *action_set_name,
- uint32_t count,
- const GHOST_XrActionProfileInfo *infos)
-{
- GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
- if (action_set == nullptr) {
- return;
- }
-
- for (uint32_t profile_idx = 0; profile_idx < count; ++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) {
- const GHOST_XrActionBindingInfo &binding = info.bindings[binding_idx];
-
- GHOST_XrAction *action = action_set->findAction(binding.action_name);
- if (action == nullptr) {
- continue;
- }
-
- action->destroyBinding(profile_path);
- }
+ action->destroyBinding(profile_paths[i]);
}
}
diff --git a/intern/ghost/intern/GHOST_XrSession.h b/intern/ghost/intern/GHOST_XrSession.h
index d448585d14c..cdeef153fb1 100644
--- a/intern/ghost/intern/GHOST_XrSession.h
+++ b/intern/ghost/intern/GHOST_XrSession.h
@@ -60,18 +60,13 @@ class GHOST_XrSession {
void destroyActions(const char *action_set_name,
uint32_t count,
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,
uint32_t count,
const GHOST_XrActionProfileInfo *infos);
void destroyActionBindings(const char *action_set_name,
uint32_t count,
- const GHOST_XrActionProfileInfo *infos);
+ const char *const *action_names,
+ const char *const *profile_paths);
bool attachActionSets();
/**
diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h
index fc00d5eb839..c0928e1519f 100644
--- a/source/blender/makesdna/DNA_xr_types.h
+++ b/source/blender/makesdna/DNA_xr_types.h
@@ -74,6 +74,15 @@ typedef enum eXrOpFlag {
XR_OP_MODAL = 2,
} 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
}
#endif
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index e513c49c11b..8b0ceb02b5f 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -203,7 +203,7 @@ if(WITH_XR_OPENXR)
list(APPEND SRC
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_session.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 136c639caea..fb973592a57 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -978,34 +978,24 @@ bool WM_xr_action_create(wmXrData *xr,
eXrActionType type,
unsigned int count_subaction_paths,
const char **subaction_paths,
- const float *float_threshold,
struct wmOperatorType *ot,
struct IDProperty *op_properties,
eXrOpFlag op_flag);
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,
const char *action_set_name,
- const char *profile_path,
const char *action_name,
- unsigned int count_interaction_paths,
- const char **interaction_paths);
+ const char *profile_path,
+ 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,
const char *action_set_name,
- const char *profile_path,
const char *action_name,
- unsigned int count_interaction_paths,
- const char **interaction_paths);
+ const char *profile_path);
/* 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);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_actions.c b/source/blender/windowmanager/xr/intern/wm_xr_action.c
index 7eabd29baa0..ee4cfcccaa7 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_actions.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_action.c
@@ -68,7 +68,6 @@ static wmXrAction *action_create(const char *action_name,
eXrActionType type,
unsigned int count_subaction_paths,
const char **subaction_paths,
- const float *float_threshold,
wmOperatorType *ot,
IDProperty *op_properties,
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_prev = MEM_calloc_arrayN(count, size, "XrAction_StatesPrev");
- if (float_threshold) {
- BLI_assert(type == XR_FLOAT_INPUT || type == XR_VECTOR2F_INPUT);
- action->float_threshold = *float_threshold;
- CLAMP(action->float_threshold, 0.0f, 1.0f);
+ const bool is_float_action = (type == XR_FLOAT_INPUT || type == XR_VECTOR2F_INPUT);
+ const bool is_button_action = (is_float_action || type == XR_BOOLEAN_INPUT);
+ if (is_float_action) {
+ 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;
@@ -140,6 +144,9 @@ static void action_destroy(void *val)
MEM_SAFE_FREE(action->states);
MEM_SAFE_FREE(action->states_prev);
+ MEM_SAFE_FREE(action->float_thresholds);
+ MEM_SAFE_FREE(action->axis_flags);
+
MEM_freeN(action);
}
@@ -198,7 +205,6 @@ bool WM_xr_action_create(wmXrData *xr,
eXrActionType type,
unsigned int count_subaction_paths,
const char **subaction_paths,
- const float *float_threshold,
wmOperatorType *ot,
IDProperty *op_properties,
eXrOpFlag op_flag)
@@ -211,7 +217,6 @@ bool WM_xr_action_create(wmXrData *xr,
type,
count_subaction_paths,
subaction_paths,
- float_threshold,
ot,
op_properties,
op_flag);
@@ -221,6 +226,8 @@ bool WM_xr_action_create(wmXrData *xr,
.count_subaction_paths = count_subaction_paths,
.subaction_paths = subaction_paths,
.states = action->states,
+ .float_thresholds = action->float_thresholds,
+ .axis_flags = (int16_t *)action->axis_flags,
.customdata_free_fn = action_destroy,
.customdata = action,
};
@@ -257,6 +264,11 @@ void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char
return;
}
+ wmXrAction *action = action_find(xr, action_set_name, action_name);
+ if (!action) {
+ return;
+ }
+
if (action_set->controller_pose_action &&
STREQ(action_set->controller_pose_action->name, action_name)) {
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;
}
- wmXrAction *action = action_find(xr, action_set_name, action_name);
- if (!action) {
- return;
- }
+ GHOST_XrDestroyActions(xr->runtime->context, action_set_name, 1, &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 wmXrPose *poses)
+
+bool WM_xr_action_binding_create(wmXrData *xr,
+ const char *action_set_name,
+ const char *action_name,
+ const char *profile_path,
+ 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_XrActionSpaceInfo info = {
- .action_name = action_name,
- .count_subaction_paths = count_subaction_paths,
- .subaction_paths = subaction_paths,
- };
+ GHOST_XrActionBindingInfo *binding_infos = MEM_calloc_arrayN(
+ count_subaction_paths, sizeof(*binding_infos), __func__);
- 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);
+ 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);
+ }
}
- 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 = {
+ GHOST_XrActionProfileInfo profile_info = {
.action_name = action_name,
+ .profile_path = profile_path,
.count_subaction_paths = count_subaction_paths,
.subaction_paths = subaction_paths,
+ .bindings = binding_infos,
};
- GHOST_XrDestroyActionSpaces(xr->runtime->context, action_set_name, 1, &info);
-}
+ bool ret = GHOST_XrCreateActionBindings(xr->runtime->context, action_set_name, 1, &profile_info);
-bool WM_xr_action_binding_create(wmXrData *xr,
- const char *action_set_name,
- const char *profile_path,
- const char *action_name,
- unsigned int count_interaction_paths,
- const char **interaction_paths)
-{
- GHOST_XrActionBindingInfo binding_info = {
- .action_name = action_name,
- .count_interaction_paths = count_interaction_paths,
- .interaction_paths = interaction_paths,
- };
-
- GHOST_XrActionProfileInfo profile_info = {
- .profile_path = profile_path,
- .count_bindings = 1,
- .bindings = &binding_info,
- };
-
- return 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,
const char *action_set_name,
- const char *profile_path,
const char *action_name,
- unsigned int count_interaction_paths,
- const char **interaction_paths)
+ const char *profile_path)
{
- GHOST_XrActionBindingInfo binding_info = {
- .action_name = action_name,
- .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);
+ GHOST_XrDestroyActionBindings(
+ xr->runtime->context, action_set_name, 1, &action_name, &profile_path);
}
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;
}
- BLI_assert(action->type == (eXrActionType)r_state->type);
+ r_state->type = (int)action->type;
/* Find the action state corresponding to the subaction path. */
for (unsigned int i = 0; i < action->count_subaction_paths; ++i) {
if (STREQ(subaction_path, action->subaction_paths[i])) {
- switch ((eXrActionType)r_state->type) {
+ switch (action->type) {
case XR_BOOLEAN_INPUT:
r_state->state_boolean = ((bool *)action->states)[i];
break;
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index 6415f96e322..4530aeaa428 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -122,8 +122,9 @@ typedef struct wmXrAction {
/** Previous states, stored to determine XR events. */
void *states_prev;
- /** Input threshold for float/vector2f actions. */
- float float_threshold;
+ /** Input thresholds/regions for each subaction path. */
+ float *float_thresholds;
+ eXrAxisFlag *axis_flags;
/** The currently active subaction path (if any) for modal actions. */
char **active_modal_path;