Changeset View
Changeset View
Standalone View
Standalone View
intern/ghost/intern/GHOST_XrAction.cpp
| Show All 27 Lines | |||||
| #include "GHOST_XrAction.h" | #include "GHOST_XrAction.h" | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name GHOST_XrActionSpace | /** \name GHOST_XrActionSpace | ||||
| * | * | ||||
| * \{ */ | * \{ */ | ||||
| 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()); | ||||
| } | } | ||||
| GHOST_XrActionSpace::~GHOST_XrActionSpace() | GHOST_XrActionSpace::~GHOST_XrActionSpace() | ||||
| { | { | ||||
| if (m_space != XR_NULL_HANDLE) { | if (m_space != XR_NULL_HANDLE) { | ||||
| CHECK_XR_ASSERT(xrDestroySpace(m_space)); | CHECK_XR_ASSERT(xrDestroySpace(m_space)); | ||||
| } | } | ||||
| } | } | ||||
| XrSpace GHOST_XrActionSpace::getSpace() const | XrSpace GHOST_XrActionSpace::getSpace() const | ||||
| { | { | ||||
| return m_space; | return m_space; | ||||
| } | } | ||||
| const XrPath &GHOST_XrActionSpace::getSubactionPath() const | |||||
| { | |||||
| return m_subaction_path; | |||||
| } | |||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name GHOST_XrActionProfile | /** \name GHOST_XrActionProfile | ||||
| * | * | ||||
| * \{ */ | * \{ */ | ||||
| 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{ | ||||
| XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; | XR_TYPE_INTERACTION_PROFILE_SUGGESTED_BINDING}; | ||||
| 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( | ||||
| XrAction action, std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const | XrAction action, std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const | ||||
| { | { | ||||
| std::map<XrPath, std::vector<XrActionSuggestedBinding>>::iterator it = r_bindings.find( | std::map<XrPath, std::vector<XrActionSuggestedBinding>>::iterator it = r_bindings.find( | ||||
| m_profile); | m_profile); | ||||
| if (it == r_bindings.end()) { | if (it == r_bindings.end()) { | ||||
| Show All 20 Lines | |||||
| * | * | ||||
| * \{ */ | * \{ */ | ||||
| GHOST_XrAction::GHOST_XrAction(XrInstance instance, | GHOST_XrAction::GHOST_XrAction(XrInstance instance, | ||||
| XrActionSet action_set, | XrActionSet action_set, | ||||
| 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)) | ||||
| { | { | ||||
| m_subaction_paths.resize(info.count_subaction_paths); | m_subaction_paths.resize(info.count_subaction_paths); | ||||
| for (uint32_t i = 0; i < info.count_subaction_paths; ++i) { | for (uint32_t i = 0; i < info.count_subaction_paths; ++i) { | ||||
| CHECK_XR(xrStringToPath(instance, info.subaction_paths[i], &m_subaction_paths[i]), | CHECK_XR(xrStringToPath(instance, info.subaction_paths[i], &m_subaction_paths[i]), | ||||
| (std::string("Failed to get user path \"") + info.subaction_paths[i] + "\".").data()); | (std::string("Failed to get user path \"") + info.subaction_paths[i] + "\".").data()); | ||||
| Show All 33 Lines | |||||
| GHOST_XrAction::~GHOST_XrAction() | GHOST_XrAction::~GHOST_XrAction() | ||||
| { | { | ||||
| if (m_action != XR_NULL_HANDLE) { | if (m_action != XR_NULL_HANDLE) { | ||||
| CHECK_XR_ASSERT(xrDestroyAction(m_action)); | CHECK_XR_ASSERT(xrDestroyAction(m_action)); | ||||
| } | } | ||||
| } | } | ||||
| 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); | ||||
| } | } | ||||
| } | } | ||||
| void GHOST_XrAction::updateState(XrSession session, | void GHOST_XrAction::updateState(XrSession session, | ||||
| const char *action_name, | const char *action_name, | ||||
| 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; | ||||
| const size_t count_subaction_paths = m_subaction_paths.size(); | const size_t count_subaction_paths = m_subaction_paths.size(); | ||||
| 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}; | ||||
| CHECK_XR(xrGetActionStateBoolean(session, &state_info, &state), | CHECK_XR(xrGetActionStateBoolean(session, &state_info, &state), | ||||
| (std::string("Failed to get state for boolean action \"") + action_name + "\".") | (std::string("Failed to get state for boolean action \"") + action_name + "\".") | ||||
| .data()); | .data()); | ||||
| if (state.isActive) { | if (state.isActive) { | ||||
| ((bool *)m_states)[subaction_idx] = state.currentState; | ((bool *)m_states)[subaction_idx] = state.currentState; | ||||
| Show All 21 Lines | switch (m_type) { | ||||
| break; | break; | ||||
| } | } | ||||
| case GHOST_kXrActionTypePoseInput: { | case GHOST_kXrActionTypePoseInput: { | ||||
| XrActionStatePose state{XR_TYPE_ACTION_STATE_POSE}; | XrActionStatePose state{XR_TYPE_ACTION_STATE_POSE}; | ||||
| CHECK_XR( | CHECK_XR( | ||||
| 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( | ||||
| xrLocateSpace( | xrLocateSpace( | ||||
| pose_space, reference_space, predicted_display_time, &space_location), | pose_space, reference_space, predicted_display_time, &space_location), | ||||
| (std::string("Failed to query pose space for action \"") + action_name + "\".") | (std::string("Failed to query pose space for action \"") + action_name + "\".") | ||||
| .data()); | .data()); | ||||
| copy_openxr_pose_to_ghost_pose(space_location.pose, | copy_openxr_pose_to_ghost_pose(space_location.pose, | ||||
| ▲ Show 20 Lines • Show All 161 Lines • Show Last 20 Lines | |||||