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:
Diffstat (limited to 'source/blender/windowmanager/xr')
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr.c2
-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.c567
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_draw.c32
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h79
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c186
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) {