diff options
Diffstat (limited to 'source/blender/windowmanager/xr')
-rw-r--r-- | source/blender/windowmanager/xr/intern/wm_xr.c | 2 | ||||
-rw-r--r-- | source/blender/windowmanager/xr/intern/wm_xr_action.c (renamed from source/blender/windowmanager/xr/intern/wm_xr_actions.c) | 281 | ||||
-rw-r--r-- | source/blender/windowmanager/xr/intern/wm_xr_actionmap.c | 567 | ||||
-rw-r--r-- | source/blender/windowmanager/xr/intern/wm_xr_draw.c | 32 | ||||
-rw-r--r-- | source/blender/windowmanager/xr/intern/wm_xr_intern.h | 79 | ||||
-rw-r--r-- | source/blender/windowmanager/xr/intern/wm_xr_session.c | 186 |
6 files changed, 942 insertions, 205 deletions
diff --git a/source/blender/windowmanager/xr/intern/wm_xr.c b/source/blender/windowmanager/xr/intern/wm_xr.c index 2a67c2bee9f..3091a3a19f1 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr.c +++ b/source/blender/windowmanager/xr/intern/wm_xr.c @@ -115,6 +115,7 @@ bool wm_xr_init(wmWindowManager *wm) void wm_xr_exit(wmWindowManager *wm) { if (wm->xr.runtime != NULL) { + WM_xr_actionmaps_clear(wm->xr.runtime); wm_xr_runtime_data_free(&wm->xr.runtime); } if (wm->xr.session_settings.shading.prop) { @@ -148,6 +149,7 @@ bool wm_xr_events_handle(wmWindowManager *wm) wmXrRuntimeData *wm_xr_runtime_data_create(void) { wmXrRuntimeData *runtime = MEM_callocN(sizeof(*runtime), __func__); + runtime->actactionmap = runtime->selactionmap = -1; return runtime; } diff --git a/source/blender/windowmanager/xr/intern/wm_xr_actions.c b/source/blender/windowmanager/xr/intern/wm_xr_action.c index 7eabd29baa0..ba347c537ec 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_actions.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_action.c @@ -23,6 +23,7 @@ * All functions are designed to be usable by RNA / the Python API. */ +#include "BLI_listbase.h" #include "BLI_math.h" #include "GHOST_C-api.h" @@ -56,6 +57,9 @@ static void action_set_destroy(void *val) MEM_SAFE_FREE(action_set->name); + BLI_freelistN(&action_set->active_modal_actions); + BLI_freelistN(&action_set->active_haptic_actions); + MEM_freeN(action_set); } @@ -68,10 +72,15 @@ 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) + const char *haptic_name, + const int64_t *haptic_duration, + const float *haptic_frequency, + const float *haptic_amplitude, + eXrOpFlag op_flag, + eXrActionFlag action_flag, + eXrHapticFlag haptic_flag) { wmXrAction *action = MEM_callocN(sizeof(*action), __func__); action->name = MEM_mallocN(strlen(action_name) + 1, "XrAction_Name"); @@ -109,15 +118,32 @@ 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; action->op_properties = op_properties; + + if (haptic_name) { + BLI_assert(is_button_action); + action->haptic_name = MEM_mallocN(strlen(haptic_name) + 1, "XrAction_HapticName"); + strcpy(action->haptic_name, haptic_name); + action->haptic_duration = *haptic_duration; + action->haptic_frequency = *haptic_frequency; + action->haptic_amplitude = *haptic_amplitude; + } + action->op_flag = op_flag; + action->action_flag = action_flag; + action->haptic_flag = haptic_flag; return action; } @@ -140,6 +166,11 @@ 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_SAFE_FREE(action->haptic_name); + MEM_freeN(action); } @@ -179,13 +210,14 @@ void WM_xr_action_set_destroy(wmXrData *xr, const char *action_set_name) wmXrSessionState *session_state = &xr->runtime->session_state; if (action_set == session_state->active_action_set) { - if (action_set->controller_pose_action) { + if (action_set->controller_grip_action || action_set->controller_aim_action) { wm_xr_session_controller_data_clear(session_state); - action_set->controller_pose_action = NULL; - } - if (action_set->active_modal_action) { - action_set->active_modal_action = NULL; + action_set->controller_grip_action = action_set->controller_aim_action = NULL; } + + BLI_freelistN(&action_set->active_modal_actions); + BLI_freelistN(&action_set->active_haptic_actions); + session_state->active_action_set = NULL; } @@ -198,10 +230,15 @@ 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) + const char *haptic_name, + const int64_t *haptic_duration, + const float *haptic_frequency, + const float *haptic_amplitude, + eXrOpFlag op_flag, + eXrActionFlag action_flag, + eXrHapticFlag haptic_flag) { if (action_find(xr, action_set_name, action_name)) { return false; @@ -211,16 +248,23 @@ bool WM_xr_action_create(wmXrData *xr, type, count_subaction_paths, subaction_paths, - float_threshold, ot, op_properties, - op_flag); + haptic_name, + haptic_duration, + haptic_frequency, + haptic_amplitude, + op_flag, + action_flag, + haptic_flag); GHOST_XrActionInfo info = { .name = action_name, .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,110 +301,88 @@ void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char 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) { - wm_xr_session_controller_data_clear(&xr->runtime->session_state); - } - action_set->controller_pose_action = NULL; - } - if (action_set->active_modal_action && - STREQ(action_set->active_modal_action->name, action_name)) { - action_set->active_modal_action = NULL; - } - wmXrAction *action = action_find(xr, action_set_name, 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); + if ((action_set->controller_grip_action && + STREQ(action_set->controller_grip_action->name, action_name)) || + (action_set->controller_aim_action && + STREQ(action_set->controller_aim_action->name, action_name))) { + if (action_set == xr->runtime->session_state.active_action_set) { + wm_xr_session_controller_data_clear(&xr->runtime->session_state); + } + action_set->controller_grip_action = action_set->controller_aim_action = NULL; } - info.poses = ghost_poses; - bool ret = GHOST_XrCreateActionSpaces(xr->runtime->context, action_set_name, 1, &info) ? true : - false; - MEM_freeN(ghost_poses); - return ret; -} + LISTBASE_FOREACH (LinkData *, ld, &action_set->active_modal_actions) { + wmXrAction *active_modal_action = ld->data; + if (STREQ(active_modal_action->name, action_name)) { + BLI_freelinkN(&action_set->active_modal_actions, ld); + break; + } + } -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, - }; + LISTBASE_FOREACH_MUTABLE (wmXrHapticAction *, ha, &action_set->active_haptic_actions) { + if (STREQ(ha->action->name, action_name)) { + BLI_freelinkN(&action_set->active_haptic_actions, ha); + } + } - GHOST_XrDestroyActionSpaces(xr->runtime->context, action_set_name, 1, &info); + GHOST_XrDestroyActions(xr->runtime->context, action_set_name, 1, &action_name); } 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) { - GHOST_XrActionBindingInfo binding_info = { - .action_name = action_name, - .count_interaction_paths = count_interaction_paths, - .interaction_paths = interaction_paths, - }; + GHOST_XrActionBindingInfo *binding_infos = MEM_calloc_arrayN( + count_subaction_paths, sizeof(*binding_infos), __func__); + + 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 = { + .action_name = action_name, .profile_path = profile_path, - .count_bindings = 1, - .bindings = &binding_info, + .count_subaction_paths = count_subaction_paths, + .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, 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) @@ -371,46 +393,64 @@ bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name) } { - /* Unset active modal action (if any). */ + /* Clear any active modal/haptic actions. */ wmXrActionSet *active_action_set = xr->runtime->session_state.active_action_set; if (active_action_set) { - wmXrAction *active_modal_action = active_action_set->active_modal_action; - if (active_modal_action) { - if (active_modal_action->active_modal_path) { - active_modal_action->active_modal_path = NULL; - } - active_action_set->active_modal_action = NULL; - } + BLI_freelistN(&active_action_set->active_modal_actions); + BLI_freelistN(&active_action_set->active_haptic_actions); } } xr->runtime->session_state.active_action_set = action_set; - if (action_set->controller_pose_action) { - wm_xr_session_controller_data_populate(action_set->controller_pose_action, xr); + if (action_set->controller_grip_action && action_set->controller_aim_action) { + wm_xr_session_controller_data_populate( + action_set->controller_grip_action, action_set->controller_aim_action, xr); + } + else { + wm_xr_session_controller_data_clear(&xr->runtime->session_state); } return true; } -bool WM_xr_controller_pose_action_set(wmXrData *xr, - const char *action_set_name, - const char *action_name) +bool WM_xr_controller_pose_actions_set(wmXrData *xr, + const char *action_set_name, + const char *grip_action_name, + const char *aim_action_name) { wmXrActionSet *action_set = action_set_find(xr, action_set_name); if (!action_set) { return false; } - wmXrAction *action = action_find(xr, action_set_name, action_name); - if (!action) { + wmXrAction *grip_action = action_find(xr, action_set_name, grip_action_name); + if (!grip_action) { return false; } - action_set->controller_pose_action = action; + wmXrAction *aim_action = action_find(xr, action_set_name, aim_action_name); + if (!aim_action) { + return false; + } + + /* Ensure consistent subaction paths. */ + const unsigned int count = grip_action->count_subaction_paths; + if (count != aim_action->count_subaction_paths) { + return false; + } + + for (unsigned int i = 0; i < count; ++i) { + if (!STREQ(grip_action->subaction_paths[i], aim_action->subaction_paths[i])) { + return false; + } + } + + action_set->controller_grip_action = grip_action; + action_set->controller_aim_action = aim_action; if (action_set == xr->runtime->session_state.active_action_set) { - wm_xr_session_controller_data_populate(action, xr); + wm_xr_session_controller_data_populate(grip_action, aim_action, xr); } return true; @@ -427,12 +467,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; @@ -462,19 +502,28 @@ bool WM_xr_action_state_get(const wmXrData *xr, bool WM_xr_haptic_action_apply(wmXrData *xr, const char *action_set_name, const char *action_name, + const char *subaction_path, const int64_t *duration, const float *frequency, const float *amplitude) { - return GHOST_XrApplyHapticAction( - xr->runtime->context, action_set_name, action_name, duration, frequency, amplitude) ? + return GHOST_XrApplyHapticAction(xr->runtime->context, + action_set_name, + action_name, + subaction_path, + duration, + frequency, + amplitude) ? true : false; } -void WM_xr_haptic_action_stop(wmXrData *xr, const char *action_set_name, const char *action_name) +void WM_xr_haptic_action_stop(wmXrData *xr, + const char *action_set_name, + const char *action_name, + const char *subaction_path) { - GHOST_XrStopHapticAction(xr->runtime->context, action_set_name, action_name); + GHOST_XrStopHapticAction(xr->runtime->context, action_set_name, action_name, subaction_path); } /** \} */ /* XR-Action API */ diff --git a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c new file mode 100644 index 00000000000..f9ad34b5a9b --- /dev/null +++ b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c @@ -0,0 +1,567 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup wm + * + * \name Window-Manager XR Action Maps + * + * XR actionmap API, similar to WM keymap API. + */ + +#include <math.h> +#include <string.h> + +#include "BKE_context.h" +#include "BKE_idprop.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "GHOST_Types.h" + +#include "MEM_guardedalloc.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "wm_xr_intern.h" + +#define WM_XR_ACTIONMAP_STR_DEFAULT "actionmap" +#define WM_XR_ACTIONMAP_ITEM_STR_DEFAULT "action" +#define WM_XR_ACTIONMAP_BINDING_STR_DEFAULT "binding" + +/* -------------------------------------------------------------------- */ +/** \name Action Map Binding + * + * Binding in an XR action map item, that maps an action to an XR input. + * \{ */ + +XrActionMapBinding *WM_xr_actionmap_binding_new(XrActionMapItem *ami, + const char *name, + bool replace_existing) +{ + XrActionMapBinding *amb_prev = WM_xr_actionmap_binding_find(ami, name); + if (amb_prev && replace_existing) { + return amb_prev; + } + + XrActionMapBinding *amb = MEM_callocN(sizeof(XrActionMapBinding), __func__); + BLI_strncpy(amb->name, name, MAX_NAME); + if (amb_prev) { + WM_xr_actionmap_binding_ensure_unique(ami, amb); + } + + BLI_addtail(&ami->bindings, amb); + + /* Set non-zero threshold by default. */ + amb->float_threshold = 0.3f; + + return amb; +} + +static XrActionMapBinding *wm_xr_actionmap_binding_find_except(XrActionMapItem *ami, + const char *name, + XrActionMapBinding *ambexcept) +{ + LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) { + if (STREQLEN(name, amb->name, MAX_NAME) && (amb != ambexcept)) { + return amb; + } + } + return NULL; +} + +/** + * Ensure unique name among all action map bindings. + */ +void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb) +{ + char name[MAX_NAME]; + char *suffix; + size_t baselen; + size_t idx = 0; + + BLI_strncpy(name, amb->name, MAX_NAME); + baselen = BLI_strnlen(name, MAX_NAME); + suffix = &name[baselen]; + + while (wm_xr_actionmap_binding_find_except(ami, name, amb)) { + if ((baselen + 1) + (log10(++idx) + 1) > MAX_NAME) { + /* Use default base name. */ + BLI_strncpy(name, WM_XR_ACTIONMAP_BINDING_STR_DEFAULT, MAX_NAME); + baselen = BLI_strnlen(name, MAX_NAME); + suffix = &name[baselen]; + idx = 0; + } + else { + BLI_snprintf(suffix, MAX_NAME, "%zu", idx); + } + } + + BLI_strncpy(amb->name, name, MAX_NAME); +} + +static XrActionMapBinding *wm_xr_actionmap_binding_copy(XrActionMapBinding *amb_src) +{ + XrActionMapBinding *amb_dst = MEM_dupallocN(amb_src); + + amb_dst->prev = amb_dst->next = NULL; + + return amb_dst; +} + +XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami, + XrActionMapBinding *amb_src) +{ + XrActionMapBinding *amb_dst = wm_xr_actionmap_binding_copy(amb_src); + + WM_xr_actionmap_binding_ensure_unique(ami, amb_dst); + + BLI_addtail(&ami->bindings, amb_dst); + + return amb_dst; +} + +bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *amb) +{ + int idx = BLI_findindex(&ami->bindings, amb); + + if (idx != -1) { + BLI_freelinkN(&ami->bindings, amb); + + if (BLI_listbase_is_empty(&ami->bindings)) { + ami->selbinding = -1; + } + else { + if (idx <= ami->selbinding) { + if (--ami->selbinding < 0) { + ami->selbinding = 0; + } + } + } + + return true; + } + + return false; +} + +XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const char *name) +{ + LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) { + if (STREQLEN(name, amb->name, MAX_NAME)) { + return amb; + } + } + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Action Map Item + * + * Item in an XR action map, that maps an XR event to an operator, pose, or haptic output. + * \{ */ + +static void wm_xr_actionmap_item_properties_set(XrActionMapItem *ami) +{ + WM_operator_properties_alloc(&(ami->op_properties_ptr), &(ami->op_properties), ami->op); + WM_operator_properties_sanitize(ami->op_properties_ptr, 1); +} + +static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami) +{ + if (ami->op_properties_ptr) { + WM_operator_properties_free(ami->op_properties_ptr); + MEM_freeN(ami->op_properties_ptr); + ami->op_properties_ptr = NULL; + ami->op_properties = NULL; + } + else { + BLI_assert(ami->op_properties == NULL); + } +} + +/** + * Similar to #wm_xr_actionmap_item_properties_set() + * but checks for the #eXrActionType and #wmOperatorType having changed. + */ +void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami) +{ + switch (ami->type) { + case XR_BOOLEAN_INPUT: + case XR_FLOAT_INPUT: + case XR_VECTOR2F_INPUT: + break; + case XR_POSE_INPUT: + case XR_VIBRATION_OUTPUT: + wm_xr_actionmap_item_properties_free(ami); + memset(ami->op, 0, sizeof(ami->op)); + return; + } + + if (ami->op[0] == 0) { + wm_xr_actionmap_item_properties_free(ami); + return; + } + + if (ami->op_properties_ptr == NULL) { + wm_xr_actionmap_item_properties_set(ami); + } + else { + wmOperatorType *ot = WM_operatortype_find(ami->op, 0); + if (ot) { + if (ot->srna != ami->op_properties_ptr->type) { + /* Matches wm_xr_actionmap_item_properties_set() but doesn't alloc new ptr. */ + WM_operator_properties_create_ptr(ami->op_properties_ptr, ot); + if (ami->op_properties) { + ami->op_properties_ptr->data = ami->op_properties; + } + WM_operator_properties_sanitize(ami->op_properties_ptr, 1); + } + } + else { + wm_xr_actionmap_item_properties_free(ami); + } + } +} + +XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap, + const char *name, + bool replace_existing) +{ + XrActionMapItem *ami_prev = WM_xr_actionmap_item_find(actionmap, name); + if (ami_prev && replace_existing) { + wm_xr_actionmap_item_properties_free(ami_prev); + return ami_prev; + } + + XrActionMapItem *ami = MEM_callocN(sizeof(XrActionMapItem), __func__); + BLI_strncpy(ami->name, name, MAX_NAME); + if (ami_prev) { + WM_xr_actionmap_item_ensure_unique(actionmap, ami); + } + ami->selbinding = -1; + + BLI_addtail(&actionmap->items, ami); + + /* Set type to float (button) input by default. */ + ami->type = XR_FLOAT_INPUT; + + return ami; +} + +static XrActionMapItem *wm_xr_actionmap_item_find_except(XrActionMap *actionmap, + const char *name, + const XrActionMapItem *amiexcept) +{ + LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) { + if (STREQLEN(name, ami->name, MAX_NAME) && (ami != amiexcept)) { + return ami; + } + } + return NULL; +} + +/** + * Ensure unique name among all action map items. + */ +void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami) +{ + char name[MAX_NAME]; + char *suffix; + size_t baselen; + size_t idx = 0; + + BLI_strncpy(name, ami->name, MAX_NAME); + baselen = BLI_strnlen(name, MAX_NAME); + suffix = &name[baselen]; + + while (wm_xr_actionmap_item_find_except(actionmap, name, ami)) { + if ((baselen + 1) + (log10(++idx) + 1) > MAX_NAME) { + /* Use default base name. */ + BLI_strncpy(name, WM_XR_ACTIONMAP_ITEM_STR_DEFAULT, MAX_NAME); + baselen = BLI_strnlen(name, MAX_NAME); + suffix = &name[baselen]; + idx = 0; + } + else { + BLI_snprintf(suffix, MAX_NAME, "%zu", idx); + } + } + + BLI_strncpy(ami->name, name, MAX_NAME); +} + +static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami) +{ + XrActionMapItem *amin = MEM_dupallocN(ami); + + amin->prev = amin->next = NULL; + + if (amin->op_properties) { + amin->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr"); + WM_operator_properties_create(amin->op_properties_ptr, amin->op); + + amin->op_properties = IDP_CopyProperty(amin->op_properties); + amin->op_properties_ptr->data = amin->op_properties; + } + else { + amin->op_properties = NULL; + amin->op_properties_ptr = NULL; + } + + return amin; +} + +XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src) +{ + XrActionMapItem *ami_dst = wm_xr_actionmap_item_copy(ami_src); + + WM_xr_actionmap_item_ensure_unique(actionmap, ami_dst); + + BLI_addtail(&actionmap->items, ami_dst); + + return ami_dst; +} + +bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami) +{ + int idx = BLI_findindex(&actionmap->items, ami); + + if (idx != -1) { + if (ami->op_properties_ptr) { + WM_operator_properties_free(ami->op_properties_ptr); + MEM_freeN(ami->op_properties_ptr); + } + BLI_freelinkN(&actionmap->items, ami); + + if (BLI_listbase_is_empty(&actionmap->items)) { + actionmap->selitem = -1; + } + else { + if (idx <= actionmap->selitem) { + if (--actionmap->selitem < 0) { + actionmap->selitem = 0; + } + } + } + + return true; + } + + return false; +} + +XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *name) +{ + LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) { + if (STREQLEN(name, ami->name, MAX_NAME)) { + return ami; + } + } + return NULL; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Action Map + * + * List of XR action map items. + * \{ */ + +XrActionMap *WM_xr_actionmap_new(wmXrRuntimeData *runtime, const char *name, bool replace_existing) +{ + XrActionMap *am_prev = WM_xr_actionmap_find(runtime, name); + if (am_prev && replace_existing) { + WM_xr_actionmap_clear(am_prev); + return am_prev; + } + + XrActionMap *am = MEM_callocN(sizeof(struct XrActionMap), __func__); + BLI_strncpy(am->name, name, MAX_NAME); + if (am_prev) { + WM_xr_actionmap_ensure_unique(runtime, am); + } + am->selitem = -1; + + BLI_addtail(&runtime->actionmaps, am); + + return am; +} + +static XrActionMap *wm_xr_actionmap_find_except(wmXrRuntimeData *runtime, + const char *name, + const XrActionMap *am_except) +{ + LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) { + if (STREQLEN(name, am->name, MAX_NAME) && (am != am_except)) { + return am; + } + } + + return NULL; +} + +/** + * Ensure unique name among all action maps. + */ +void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *actionmap) +{ + char name[MAX_NAME]; + char *suffix; + size_t baselen; + size_t idx = 0; + + BLI_strncpy(name, actionmap->name, MAX_NAME); + baselen = BLI_strnlen(name, MAX_NAME); + suffix = &name[baselen]; + + while (wm_xr_actionmap_find_except(runtime, name, actionmap)) { + if ((baselen + 1) + (log10(++idx) + 1) > MAX_NAME) { + /* Use default base name. */ + BLI_strncpy(name, WM_XR_ACTIONMAP_STR_DEFAULT, MAX_NAME); + baselen = BLI_strnlen(name, MAX_NAME); + suffix = &name[baselen]; + idx = 0; + } + else { + BLI_snprintf(suffix, MAX_NAME, "%zu", idx); + } + } + + BLI_strncpy(actionmap->name, name, MAX_NAME); +} + +static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src) +{ + XrActionMap *am_dst = MEM_dupallocN(am_src); + + am_dst->prev = am_dst->next = NULL; + BLI_listbase_clear(&am_dst->items); + + LISTBASE_FOREACH (XrActionMapItem *, ami, &am_src->items) { + XrActionMapItem *ami_new = wm_xr_actionmap_item_copy(ami); + BLI_addtail(&am_dst->items, ami_new); + } + + return am_dst; +} + +XrActionMap *WM_xr_actionmap_add_copy(wmXrRuntimeData *runtime, XrActionMap *am_src) +{ + XrActionMap *am_dst = wm_xr_actionmap_copy(am_src); + + WM_xr_actionmap_ensure_unique(runtime, am_dst); + + BLI_addtail(&runtime->actionmaps, am_dst); + + return am_dst; +} + +bool WM_xr_actionmap_remove(wmXrRuntimeData *runtime, XrActionMap *actionmap) +{ + int idx = BLI_findindex(&runtime->actionmaps, actionmap); + + if (idx != -1) { + WM_xr_actionmap_clear(actionmap); + BLI_freelinkN(&runtime->actionmaps, actionmap); + + if (BLI_listbase_is_empty(&runtime->actionmaps)) { + runtime->actactionmap = runtime->selactionmap = -1; + } + else { + if (idx <= runtime->actactionmap) { + if (--runtime->actactionmap < 0) { + runtime->actactionmap = 0; + } + } + if (idx <= runtime->selactionmap) { + if (--runtime->selactionmap < 0) { + runtime->selactionmap = 0; + } + } + } + + return true; + } + + return false; +} + +XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name) +{ + LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) { + if (STREQLEN(name, am->name, MAX_NAME)) { + return am; + } + } + return NULL; +} + +void WM_xr_actionmap_clear(XrActionMap *actionmap) +{ + LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) { + wm_xr_actionmap_item_properties_free(ami); + } + + BLI_freelistN(&actionmap->items); + + actionmap->selitem = -1; +} + +void WM_xr_actionmaps_clear(wmXrRuntimeData *runtime) +{ + LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) { + WM_xr_actionmap_clear(am); + } + + BLI_freelistN(&runtime->actionmaps); + + runtime->actactionmap = runtime->selactionmap = -1; +} + +ListBase *WM_xr_actionmaps_get(wmXrRuntimeData *runtime) +{ + return &runtime->actionmaps; +} + +short WM_xr_actionmap_active_index_get(const wmXrRuntimeData *runtime) +{ + return runtime->actactionmap; +} + +void WM_xr_actionmap_active_index_set(wmXrRuntimeData *runtime, short idx) +{ + BLI_assert(idx < BLI_listbase_count(&runtime->actionmaps)); + runtime->actactionmap = idx; +} + +short WM_xr_actionmap_selected_index_get(const wmXrRuntimeData *runtime) +{ + return runtime->selactionmap; +} + +void WM_xr_actionmap_selected_index_set(wmXrRuntimeData *runtime, short idx) +{ + BLI_assert(idx < BLI_listbase_count(&runtime->actionmaps)); + runtime->selactionmap = idx; +} + +/** \} */ diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c index 4ac05e339b9..bbb73fc2007 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c @@ -38,18 +38,18 @@ #include "wm_surface.h" #include "wm_xr_intern.h" -void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4]) +void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]) { - float iquat[4]; - invert_qt_qt_normalized(iquat, pose->orientation_quat); - quat_to_mat4(r_viewmat, iquat); - translate_m4(r_viewmat, -pose->position[0], -pose->position[1], -pose->position[2]); + quat_to_mat4(r_mat, pose->orientation_quat); + copy_v3_v3(r_mat[3], pose->position); } -void wm_xr_controller_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]) +void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]) { - quat_to_mat4(r_mat, pose->orientation_quat); - copy_v3_v3(r_mat[3], pose->position); + float iquat[4]; + invert_qt_qt_normalized(iquat, pose->orientation_quat); + quat_to_mat4(r_imat, iquat); + translate_m4(r_imat, -pose->position[0], -pose->position[1], -pose->position[2]); } static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data, @@ -59,6 +59,7 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data, float r_proj_mat[4][4]) { GHOST_XrPose eye_pose; + float eye_inv[4][4], base_inv[4][4]; copy_qt_qt(eye_pose.orientation_quat, draw_view->eye_pose.orientation_quat); copy_v3_v3(eye_pose.position, draw_view->eye_pose.position); @@ -69,6 +70,12 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data, sub_v3_v3(eye_pose.position, draw_data->eye_position_ofs); } + wm_xr_pose_to_imat(&eye_pose, eye_inv); + /* Calculate the base pose matrix (in world space!). */ + wm_xr_pose_to_imat(&draw_data->base_pose, base_inv); + + mul_m4_m4m4(r_view_mat, eye_inv, base_inv); + perspective_m4_fov(r_proj_mat, draw_view->fov.angle_left, draw_view->fov.angle_right, @@ -76,15 +83,6 @@ static void wm_xr_draw_matrices_create(const wmXrDrawData *draw_data, draw_view->fov.angle_down, session_settings->clip_start, session_settings->clip_end); - - float eye_mat[4][4]; - float base_mat[4][4]; - - wm_xr_pose_to_viewmat(&eye_pose, eye_mat); - /* Calculate the base pose matrix (in world space!). */ - wm_xr_pose_to_viewmat(&draw_data->base_pose, base_mat); - - mul_m4_m4m4(r_view_mat, eye_mat, base_mat); } static void wm_xr_draw_viewport_buffers_to_active_framebuffer( diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h index 6415f96e322..4d4df43f796 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h +++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h @@ -26,19 +26,6 @@ struct wmXrActionSet; -typedef struct wmXrControllerData { - /** OpenXR path identifier. Length is dependent on OpenXR's XR_MAX_PATH_LENGTH (256). - This subaction path will later be combined with a component path, and that combined path should - also have a max of XR_MAX_PATH_LENGTH (e.g. subaction_path = /user/hand/left, component_path = - /input/trigger/value, interaction_path = /user/hand/left/input/trigger/value). - */ - char subaction_path[64]; - /** Last known controller pose (in world space) stored for queries. */ - GHOST_XrPose pose; - /** The last known controller matrix, calculated from above's controller pose. */ - float mat[4][4]; -} wmXrControllerData; - typedef struct wmXrSessionState { bool is_started; @@ -65,7 +52,7 @@ typedef struct wmXrSessionState { bool is_view_data_set; /** Last known controller data. */ - wmXrControllerData controllers[2]; + ListBase controllers; /* wmXrController */ /** The currently active action set that will be updated on calls to * wm_xr_session_actions_update(). If NULL, all action sets will be treated as active and @@ -83,6 +70,10 @@ typedef struct wmXrRuntimeData { /** Although this struct is internal, RNA gets a handle to this for state information queries. */ wmXrSessionState session_state; wmXrSessionExitFn exit_fn; + + ListBase actionmaps; /* XrActionMap */ + short actactionmap; + short selactionmap; } wmXrRuntimeData; typedef struct wmXrViewportPair { @@ -112,6 +103,22 @@ typedef struct wmXrDrawData { float eye_position_ofs[3]; /* Local/view space. */ } wmXrDrawData; +typedef struct wmXrController { + struct wmXrController *next, *prev; + /** OpenXR path identifier. Length is dependent on OpenXR's XR_MAX_PATH_LENGTH (256). + This subaction path will later be combined with a component path, and that combined path should + also have a max of XR_MAX_PATH_LENGTH (e.g. subaction_path = /user/hand/left, component_path = + /input/trigger/value, interaction_path = /user/hand/left/input/trigger/value). + */ + char subaction_path[64]; + /* Pose (in world space) that represents the user's hand when holding the controller.*/ + GHOST_XrPose grip_pose; + float grip_mat[4][4]; + /* Pose (in world space) that represents the controller's aiming source. */ + GHOST_XrPose aim_pose; + float aim_mat[4][4]; +} wmXrController; + typedef struct wmXrAction { char *name; eXrActionType type; @@ -122,28 +129,47 @@ 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; + const char *active_modal_path; /** Operator to be called on XR events. */ struct wmOperatorType *ot; IDProperty *op_properties; + + /** Haptics. */ + char *haptic_name; + int64_t haptic_duration; + float haptic_frequency; + float haptic_amplitude; + + /** Flags. */ eXrOpFlag op_flag; + eXrActionFlag action_flag; + eXrHapticFlag haptic_flag; } wmXrAction; +typedef struct wmXrHapticAction { + struct wmXrHapticAction *next, *prev; + wmXrAction *action; + const char *subaction_path; + int64_t time_start; +} wmXrHapticAction; + typedef struct wmXrActionSet { char *name; - /** The XR pose action that determines the controller - * transforms. This is usually identified by the OpenXR path "/grip/pose" or "/aim/pose", - * although it could differ depending on the specification and hardware. */ - wmXrAction *controller_pose_action; + /** XR pose actions that determine the controller grip/aim transforms. */ + wmXrAction *controller_grip_action; + wmXrAction *controller_aim_action; - /** The currently active modal action (if any). */ - wmXrAction *active_modal_action; + /** Currently active modal actions. */ + ListBase active_modal_actions; + /** Currently active haptic actions. */ + ListBase active_haptic_actions; } wmXrActionSet; wmXrRuntimeData *wm_xr_runtime_data_create(void); @@ -164,10 +190,11 @@ void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle context); void wm_xr_session_actions_init(wmXrData *xr); void wm_xr_session_actions_update(wmXrData *xr); -void wm_xr_session_controller_data_populate(const wmXrAction *controller_pose_action, +void wm_xr_session_controller_data_populate(const wmXrAction *grip_action, + const wmXrAction *aim_action, wmXrData *xr); void wm_xr_session_controller_data_clear(wmXrSessionState *state); -void wm_xr_pose_to_viewmat(const GHOST_XrPose *pose, float r_viewmat[4][4]); -void wm_xr_controller_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]); +void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]); +void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]); void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata); diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index 252f358c798..ba30b0dd864 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -63,6 +63,16 @@ static void wm_xr_session_create_cb(void) wm_xr_session_actions_init(xr_data); } +static void wm_xr_session_controller_data_free(wmXrSessionState *state) +{ + BLI_freelistN(&state->controllers); +} + +static void wm_xr_session_data_free(wmXrSessionState *state) +{ + wm_xr_session_controller_data_free(state); +} + static void wm_xr_session_exit_cb(void *customdata) { wmXrData *xr_data = customdata; @@ -74,6 +84,7 @@ static void wm_xr_session_exit_cb(void *customdata) } /* Free the entire runtime data (including session state and context), to play safe. */ + wm_xr_session_data_free(&xr_data->runtime->session_state); wm_xr_runtime_data_free(&xr_data->runtime); } @@ -338,7 +349,7 @@ void wm_xr_session_state_update(const XrSessionSettings *settings, copy_v3_v3(state->viewer_pose.position, viewer_pose.position); copy_qt_qt(state->viewer_pose.orientation_quat, viewer_pose.orientation_quat); - wm_xr_pose_to_viewmat(&viewer_pose, state->viewer_viewmat); + wm_xr_pose_to_imat(&viewer_pose, state->viewer_viewmat); /* No idea why, but multiplying by two seems to make it match the VR view more. */ state->focal_len = 2.0f * fov_to_focallength(draw_view->fov.angle_right - draw_view->fov.angle_left, @@ -398,32 +409,71 @@ bool WM_xr_session_state_viewer_pose_matrix_info_get(const wmXrData *xr, return true; } -bool WM_xr_session_state_controller_pose_location_get(const wmXrData *xr, +bool WM_xr_session_state_controller_grip_location_get(const wmXrData *xr, unsigned int subaction_idx, float r_location[3]) { if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set || - subaction_idx >= ARRAY_SIZE(xr->runtime->session_state.controllers)) { + (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers))) { zero_v3(r_location); return false; } - copy_v3_v3(r_location, xr->runtime->session_state.controllers[subaction_idx].pose.position); + const wmXrController *controller = BLI_findlink(&xr->runtime->session_state.controllers, + subaction_idx); + BLI_assert(controller); + copy_v3_v3(r_location, controller->grip_pose.position); return true; } -bool WM_xr_session_state_controller_pose_rotation_get(const wmXrData *xr, +bool WM_xr_session_state_controller_grip_rotation_get(const wmXrData *xr, unsigned int subaction_idx, float r_rotation[4]) { if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set || - subaction_idx >= ARRAY_SIZE(xr->runtime->session_state.controllers)) { + (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers))) { unit_qt(r_rotation); return false; } - copy_v4_v4(r_rotation, - xr->runtime->session_state.controllers[subaction_idx].pose.orientation_quat); + const wmXrController *controller = BLI_findlink(&xr->runtime->session_state.controllers, + subaction_idx); + BLI_assert(controller); + copy_qt_qt(r_rotation, controller->grip_pose.orientation_quat); + return true; +} + +bool WM_xr_session_state_controller_aim_location_get(const wmXrData *xr, + unsigned int subaction_idx, + float r_location[3]) +{ + if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set || + (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers))) { + zero_v3(r_location); + return false; + } + + const wmXrController *controller = BLI_findlink(&xr->runtime->session_state.controllers, + subaction_idx); + BLI_assert(controller); + copy_v3_v3(r_location, controller->aim_pose.position); + return true; +} + +bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr, + unsigned int subaction_idx, + float r_rotation[4]) +{ + if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set || + (subaction_idx >= BLI_listbase_count(&xr->runtime->session_state.controllers))) { + unit_qt(r_rotation); + return false; + } + + const wmXrController *controller = BLI_findlink(&xr->runtime->session_state.controllers, + subaction_idx); + BLI_assert(controller); + copy_qt_qt(r_rotation, controller->aim_pose.orientation_quat); return true; } @@ -443,16 +493,34 @@ void wm_xr_session_actions_init(wmXrData *xr) GHOST_XrAttachActionSets(xr->runtime->context); } -static void wm_xr_session_controller_mats_update(const XrSessionSettings *settings, - const wmXrAction *controller_pose_action, +static void wm_xr_session_controller_pose_calc(const GHOST_XrPose *raw_pose, + const float view_ofs[3], + const float base_mat[4][4], + GHOST_XrPose *r_pose, + float r_mat[4][4]) +{ + float m[4][4]; + /* Calculate controller matrix in world space. */ + wm_xr_pose_to_mat(raw_pose, m); + + /* Apply eye position and base pose offsets. */ + sub_v3_v3(m[3], view_ofs); + mul_m4_m4m4(r_mat, base_mat, m); + + /* Save final pose. */ + mat4_to_loc_quat(r_pose->position, r_pose->orientation_quat, r_mat); +} + +static void wm_xr_session_controller_data_update(const XrSessionSettings *settings, + const wmXrAction *grip_action, + const wmXrAction *aim_action, wmXrSessionState *state) { - const unsigned int count = (unsigned int)min_ii( - (int)controller_pose_action->count_subaction_paths, (int)ARRAY_SIZE(state->controllers)); + BLI_assert(grip_action->count_subaction_paths == aim_action->count_subaction_paths); + BLI_assert(grip_action->count_subaction_paths == BLI_listbase_count(&state->controllers)); - float view_ofs[3]; - float base_inv[4][4]; - float tmp[4][4]; + unsigned int subaction_idx = 0; + float view_ofs[3], base_mat[4][4]; if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) { copy_v3_v3(view_ofs, state->prev_local_pose.position); @@ -464,22 +532,19 @@ static void wm_xr_session_controller_mats_update(const XrSessionSettings *settin add_v3_v3(view_ofs, state->prev_eye_position_ofs); } - wm_xr_pose_to_viewmat(&state->prev_base_pose, base_inv); - invert_m4(base_inv); - - for (unsigned int i = 0; i < count; ++i) { - wmXrControllerData *controller = &state->controllers[i]; - - /* Calculate controller matrix in world space. */ - wm_xr_controller_pose_to_mat(&((GHOST_XrPose *)controller_pose_action->states)[i], tmp); - - /* Apply eye position and base pose offsets. */ - sub_v3_v3(tmp[3], view_ofs); - mul_m4_m4m4(controller->mat, base_inv, tmp); + wm_xr_pose_to_mat(&state->prev_base_pose, base_mat); - /* Save final pose. */ - mat4_to_loc_quat( - controller->pose.position, controller->pose.orientation_quat, controller->mat); + LISTBASE_FOREACH_INDEX (wmXrController *, controller, &state->controllers, subaction_idx) { + wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)grip_action->states)[subaction_idx], + view_ofs, + base_mat, + &controller->grip_pose, + controller->grip_mat); + wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)aim_action->states)[subaction_idx], + view_ofs, + base_mat, + &controller->aim_pose, + controller->aim_mat); } } @@ -498,33 +563,44 @@ void wm_xr_session_actions_update(wmXrData *xr) return; } - /* Only update controller mats for active action set. */ + /* Only update controller data for active action set. */ if (active_action_set) { - if (active_action_set->controller_pose_action) { - wm_xr_session_controller_mats_update( - &xr->session_settings, active_action_set->controller_pose_action, state); + if (active_action_set->controller_grip_action && active_action_set->controller_aim_action) { + wm_xr_session_controller_data_update(&xr->session_settings, + active_action_set->controller_grip_action, + active_action_set->controller_aim_action, + state); } } } -void wm_xr_session_controller_data_populate(const wmXrAction *controller_pose_action, wmXrData *xr) +void wm_xr_session_controller_data_populate(const wmXrAction *grip_action, + const wmXrAction *aim_action, + wmXrData *xr) { + UNUSED_VARS(aim_action); /* Only used for asserts. */ + wmXrSessionState *state = &xr->runtime->session_state; + ListBase *controllers = &state->controllers; - const unsigned int count = (unsigned int)min_ii( - (int)ARRAY_SIZE(state->controllers), (int)controller_pose_action->count_subaction_paths); + BLI_assert(grip_action->count_subaction_paths == aim_action->count_subaction_paths); + const unsigned int count = grip_action->count_subaction_paths; + + wm_xr_session_controller_data_free(state); for (unsigned int i = 0; i < count; ++i) { - wmXrControllerData *c = &state->controllers[i]; - strcpy(c->subaction_path, controller_pose_action->subaction_paths[i]); - memset(&c->pose, 0, sizeof(c->pose)); - zero_m4(c->mat); + wmXrController *controller = MEM_callocN(sizeof(*controller), __func__); + + BLI_assert(STREQ(grip_action->subaction_paths[i], aim_action->subaction_paths[i])); + strcpy(controller->subaction_path, grip_action->subaction_paths[i]); + + BLI_addtail(controllers, controller); } } void wm_xr_session_controller_data_clear(wmXrSessionState *state) { - memset(state->controllers, 0, sizeof(state->controllers)); + wm_xr_session_controller_data_free(state); } /** \} */ /* XR-Session Actions */ @@ -581,9 +657,6 @@ bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, GPUViewport *viewport = vp->viewport; const bool size_changed = offscreen && (GPU_offscreen_width(offscreen) != draw_view->width) && (GPU_offscreen_height(offscreen) != draw_view->height); - char err_out[256] = "unknown"; - bool failure = false; - if (offscreen) { BLI_assert(viewport); @@ -594,8 +667,29 @@ bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, GPU_offscreen_free(offscreen); } + char err_out[256] = "unknown"; + bool failure = false; + eGPUTextureFormat format = + GPU_R8; /* Initialize with some unsupported format to check following switch statement. */ + + switch (draw_view->swapchain_format) { + case GHOST_kXrSwapchainFormatRGBA8: + format = GPU_RGBA8; + break; + case GHOST_kXrSwapchainFormatRGBA16: + format = GPU_RGBA16; + break; + case GHOST_kXrSwapchainFormatRGBA16F: + format = GPU_RGBA16F; + break; + case GHOST_kXrSwapchainFormatRGB10_A2: + format = GPU_RGB10_A2; + break; + } + BLI_assert(format != GPU_R8); + offscreen = vp->offscreen = GPU_offscreen_create( - draw_view->width, draw_view->height, true, false, err_out); + draw_view->width, draw_view->height, true, format, err_out); if (offscreen) { viewport = vp->viewport = GPU_viewport_create(); if (!viewport) { |