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
path: root/source
diff options
context:
space:
mode:
authorPeter Kim <pk15950@gmail.com>2021-10-12 07:09:01 +0300
committerPeter Kim <pk15950@gmail.com>2021-10-12 07:48:12 +0300
commitcdeb506008e9fc6d8d9a48ce90204ec10101cdd0 (patch)
tree0652dc8128c52173a587f464b96392c22f3e3679 /source
parent4b31a21bcd19b5005cb46895186ca7ecf314c4db (diff)
XR Controller Support Step 3: XR Events
Integrates XR input actions with the WM event system. With this commit, all VR action functionality (operator execution, pose querying, haptic application), with the exception of custom drawing, is enabled. By itself, this does not bring about any changes for regular users, however it is necessary for the upcoming VR add-on update that will expose default controller actions to users. For add-on developers, this updates the Python API with access to XR event data (input states, controller poses, etc.), which can be obtained via the "xr" property added to the bpy.types.Event struct. For XR events, this property will be non-null and the event will have the type XR_ACTION. Further details: XR-type window events are queued to the regular window queues after updating and interpreting VR action states. An appropriate window is found by either using the window the VR session was started in or a fallback option. When handling XR events, mouse-specific processing is skipped and instead a dedicated XR offscreen area and region (see 08511b1c3de0) is used to execute XR event operators in the proper context. Reviewed By: Severin Differential Revision: https://developer.blender.org/D10944
Diffstat (limited to 'source')
-rw-r--r--source/blender/makesrna/intern/rna_wm.c21
-rw-r--r--source/blender/makesrna/intern/rna_xr.c238
-rw-r--r--source/blender/windowmanager/WM_api.h4
-rw-r--r--source/blender/windowmanager/intern/wm_event_query.c13
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c510
5 files changed, 784 insertions, 2 deletions
diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c
index c2d1ac67675..b45cfb04bc1 100644
--- a/source/blender/makesrna/intern/rna_wm.c
+++ b/source/blender/makesrna/intern/rna_wm.c
@@ -362,6 +362,8 @@ const EnumPropertyItem rna_enum_event_type_items[] = {
0,
"ActionZone Fullscreen",
"AZone FullScr"},
+ /* xr */
+ {EVT_XR_ACTION, "XR_ACTION", 0, "XR Action", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -700,6 +702,18 @@ static void rna_Event_tilt_get(PointerRNA *ptr, float *values)
WM_event_tablet_data(event, NULL, values);
}
+static PointerRNA rna_Event_xr_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ wmEvent *event = ptr->data;
+ wmXrActionData *actiondata = WM_event_is_xr(event) ? event->customdata : NULL;
+ return rna_pointer_inherit_refine(ptr, &RNA_XrEventData, actiondata);
+# else
+ UNUSED_VARS(ptr);
+ return PointerRNA_NULL;
+# endif
+}
+
static PointerRNA rna_PopupMenu_layout_get(PointerRNA *ptr)
{
struct uiPopupMenu *pup = ptr->data;
@@ -2228,6 +2242,13 @@ static void rna_def_event(BlenderRNA *brna)
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Absolute Motion", "The last motion event was an absolute input");
+ /* xr */
+ prop = RNA_def_property(srna, "xr", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "XrEventData");
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_pointer_funcs(prop, "rna_Event_xr_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(prop, "XR", "XR event data");
+
/* modifiers */
prop = RNA_def_property(srna, "shift", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, NULL, "shift", 1);
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index f24d28d1209..a433a93e403 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -947,6 +947,155 @@ static void rna_XrSessionState_selected_actionmap_set(PointerRNA *ptr, int value
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name XR Event Data
+ * \{ */
+
+static void rna_XrEventData_action_set_get(PointerRNA *ptr, char *r_value)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ strcpy(r_value, data->action_set);
+# else
+ UNUSED_VARS(ptr);
+ r_value[0] = '\0';
+# endif
+}
+
+static int rna_XrEventData_action_set_length(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return strlen(data->action_set);
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
+static void rna_XrEventData_action_get(PointerRNA *ptr, char *r_value)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ strcpy(r_value, data->action);
+# else
+ UNUSED_VARS(ptr);
+ r_value[0] = '\0';
+# endif
+}
+
+static int rna_XrEventData_action_length(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return strlen(data->action);
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
+static int rna_XrEventData_type_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return data->type;
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
+static void rna_XrEventData_state_get(PointerRNA *ptr, float r_values[2])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_v2_v2(r_values, data->state);
+# else
+ UNUSED_VARS(ptr);
+ zero_v2(r_values);
+# endif
+}
+
+static void rna_XrEventData_state_other_get(PointerRNA *ptr, float r_values[2])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_v2_v2(r_values, data->state_other);
+# else
+ UNUSED_VARS(ptr);
+ zero_v2(r_values);
+# endif
+}
+
+static float rna_XrEventData_float_threshold_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return data->float_threshold;
+# else
+ UNUSED_VARS(ptr);
+ return 0.0f;
+# endif
+}
+
+static void rna_XrEventData_controller_location_get(PointerRNA *ptr, float r_values[3])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_v3_v3(r_values, data->controller_loc);
+# else
+ UNUSED_VARS(ptr);
+ zero_v3(r_values);
+# endif
+}
+
+static void rna_XrEventData_controller_rotation_get(PointerRNA *ptr, float r_values[4])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_qt_qt(r_values, data->controller_rot);
+# else
+ UNUSED_VARS(ptr);
+ unit_qt(r_values);
+# endif
+}
+
+static void rna_XrEventData_controller_location_other_get(PointerRNA *ptr, float r_values[3])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_v3_v3(r_values, data->controller_loc_other);
+# else
+ UNUSED_VARS(ptr);
+ zero_v3(r_values);
+# endif
+}
+
+static void rna_XrEventData_controller_rotation_other_get(PointerRNA *ptr, float r_values[4])
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ copy_qt_qt(r_values, data->controller_rot_other);
+# else
+ UNUSED_VARS(ptr);
+ unit_qt(r_values);
+# endif
+}
+
+static bool rna_XrEventData_bimanual_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrActionData *data = ptr->data;
+ return data->bimanual;
+# else
+ UNUSED_VARS(ptr);
+ return false;
+# endif
+}
+
+/** \} */
+
#else /* RNA_RUNTIME */
/* -------------------------------------------------------------------- */
@@ -1824,6 +1973,94 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
/** \} */
+/* -------------------------------------------------------------------- */
+/** \name XR Event Data
+ * \{ */
+
+static void rna_def_xr_eventdata(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "XrEventData", NULL);
+ RNA_def_struct_ui_text(srna, "XrEventData", "XR Data for Window Manager Event");
+
+ prop = RNA_def_property(srna, "action_set", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(
+ prop, "rna_XrEventData_action_set_get", "rna_XrEventData_action_set_length", NULL);
+ RNA_def_property_ui_text(prop, "Action Set", "XR action set name");
+
+ prop = RNA_def_property(srna, "action", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_string_funcs(
+ prop, "rna_XrEventData_action_get", "rna_XrEventData_action_length", NULL);
+ RNA_def_property_ui_text(prop, "Action", "XR action name");
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_enum_items(prop, rna_enum_xr_action_types);
+ RNA_def_property_enum_funcs(prop, "rna_XrEventData_type_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Type", "XR action type");
+
+ prop = RNA_def_property(srna, "state", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_state_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "State", "XR action values corresponding to type");
+
+ prop = RNA_def_property(srna, "state_other", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_array(prop, 2);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_state_other_get", NULL, NULL);
+ RNA_def_property_ui_text(
+ prop, "State Other", "State of the other user path for bimanual actions");
+
+ prop = RNA_def_property(srna, "float_threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_float_threshold_get", NULL, NULL);
+ RNA_def_property_ui_text(prop, "Float Threshold", "Input threshold for float/2D vector actions");
+
+ prop = RNA_def_property(srna, "controller_location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_controller_location_get", NULL, NULL);
+ RNA_def_property_ui_text(prop,
+ "Controller Location",
+ "Location of the action's corresponding controller aim in world space");
+
+ prop = RNA_def_property(srna, "controller_rotation", PROP_FLOAT, PROP_QUATERNION);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_controller_rotation_get", NULL, NULL);
+ RNA_def_property_ui_text(prop,
+ "Controller Rotation",
+ "Rotation of the action's corresponding controller aim in world space");
+
+ prop = RNA_def_property(srna, "controller_location_other", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_array(prop, 3);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_controller_location_other_get", NULL, NULL);
+ RNA_def_property_ui_text(prop,
+ "Controller Location Other",
+ "Controller aim location of the other user path for bimanual actions");
+
+ prop = RNA_def_property(srna, "controller_rotation_other", PROP_FLOAT, PROP_QUATERNION);
+ RNA_def_property_array(prop, 4);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_float_funcs(prop, "rna_XrEventData_controller_rotation_other_get", NULL, NULL);
+ RNA_def_property_ui_text(prop,
+ "Controller Rotation Other",
+ "Controller aim rotation of the other user path for bimanual actions");
+
+ prop = RNA_def_property(srna, "bimanual", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(prop, "rna_XrEventData_bimanual_get", NULL);
+ RNA_def_property_ui_text(prop, "Bimanual", "Whether bimanual interaction is occurring");
+}
+
+/** \} */
+
void RNA_def_xr(BlenderRNA *brna)
{
RNA_define_animate_sdna(false);
@@ -1831,6 +2068,7 @@ void RNA_def_xr(BlenderRNA *brna)
rna_def_xr_actionmap(brna);
rna_def_xr_session_settings(brna);
rna_def_xr_session_state(brna);
+ rna_def_xr_eventdata(brna);
RNA_define_animate_sdna(true);
}
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index b79f5762955..531c5aa19bf 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -937,6 +937,10 @@ float WM_event_ndof_to_axis_angle(const struct wmNDOFMotionData *ndof, float axi
void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4]);
#endif /* WITH_INPUT_NDOF */
+#ifdef WITH_XR_OPENXR
+bool WM_event_is_xr(const struct wmEvent *event);
+#endif
+
float WM_event_tablet_data(const struct wmEvent *event, int *pen_flip, float tilt[2]);
bool WM_event_is_tablet(const struct wmEvent *event);
diff --git a/source/blender/windowmanager/intern/wm_event_query.c b/source/blender/windowmanager/intern/wm_event_query.c
index 7b5691b99a0..8b77c460be3 100644
--- a/source/blender/windowmanager/intern/wm_event_query.c
+++ b/source/blender/windowmanager/intern/wm_event_query.c
@@ -411,6 +411,19 @@ void WM_event_ndof_to_quat(const struct wmNDOFMotionData *ndof, float q[4])
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Event XR Input Access
+ * \{ */
+
+#ifdef WITH_XR_OPENXR
+bool WM_event_is_xr(const struct wmEvent *event)
+{
+ return (event->type == EVT_XR_ACTION && event->custom == EVT_DATA_XR);
+}
+#endif
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Event Tablet Input Access
* \{ */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index 819057890fd..2a59a48f152 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -21,6 +21,7 @@
#include "BKE_callbacks.h"
#include "BKE_context.h"
#include "BKE_global.h"
+#include "BKE_idprop.h"
#include "BKE_main.h"
#include "BKE_scene.h"
@@ -42,9 +43,12 @@
#include "MEM_guardedalloc.h"
+#include "PIL_time.h"
+
#include "WM_api.h"
#include "WM_types.h"
+#include "wm_event_system.h"
#include "wm_surface.h"
#include "wm_window.h"
#include "wm_xr_intern.h"
@@ -559,6 +563,509 @@ static void wm_xr_session_controller_data_update(const XrSessionSettings *settin
}
}
+static const GHOST_XrPose *wm_xr_session_controller_aim_pose_find(const wmXrSessionState *state,
+ const char *subaction_path)
+{
+ const wmXrController *controller = BLI_findstring(
+ &state->controllers, subaction_path, offsetof(wmXrController, subaction_path));
+ return controller ? &controller->aim_pose : NULL;
+}
+
+BLI_INLINE bool test_float_state(const float *state, float threshold, eXrAxisFlag flag)
+{
+ if ((flag & XR_AXIS0_POS) != 0) {
+ if (*state > threshold) {
+ return true;
+ }
+ }
+ else if ((flag & XR_AXIS0_NEG) != 0) {
+ if (*state < -threshold) {
+ return true;
+ }
+ }
+ else {
+ if (fabsf(*state) > threshold) {
+ return true;
+ }
+ }
+ return false;
+}
+
+BLI_INLINE bool test_vec2f_state(const float state[2], float threshold, eXrAxisFlag flag)
+{
+ if ((flag & XR_AXIS0_POS) != 0) {
+ if (state[0] < 0.0f) {
+ return false;
+ }
+ }
+ else if ((flag & XR_AXIS0_NEG) != 0) {
+ if (state[0] > 0.0f) {
+ return false;
+ }
+ }
+ if ((flag & XR_AXIS1_POS) != 0) {
+ if (state[1] < 0.0f) {
+ return false;
+ }
+ }
+ else if ((flag & XR_AXIS1_NEG) != 0) {
+ if (state[1] > 0.0f) {
+ return false;
+ }
+ }
+ return (len_v2(state) > threshold);
+}
+
+static bool wm_xr_session_modal_action_test(const ListBase *active_modal_actions,
+ const wmXrAction *action,
+ bool *r_found)
+{
+ if (r_found) {
+ *r_found = false;
+ }
+
+ LISTBASE_FOREACH (LinkData *, ld, active_modal_actions) {
+ wmXrAction *active_modal_action = ld->data;
+ if (action == active_modal_action) {
+ if (r_found) {
+ *r_found = true;
+ }
+ return true;
+ }
+ if (action->ot == active_modal_action->ot &&
+ IDP_EqualsProperties(action->op_properties, active_modal_action->op_properties)) {
+ /* Don't allow duplicate modal operators since this can lead to unwanted modal handler
+ * behavior. */
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static void wm_xr_session_modal_action_test_add(ListBase *active_modal_actions,
+ const wmXrAction *action)
+{
+ bool found;
+ if (wm_xr_session_modal_action_test(active_modal_actions, action, &found) && !found) {
+ LinkData *ld = MEM_callocN(sizeof(LinkData), __func__);
+ ld->data = (void *)action;
+ BLI_addtail(active_modal_actions, ld);
+ }
+}
+
+static void wm_xr_session_modal_action_remove(ListBase *active_modal_actions,
+ const wmXrAction *action)
+{
+ LISTBASE_FOREACH (LinkData *, ld, active_modal_actions) {
+ if (action == ld->data) {
+ BLI_freelinkN(active_modal_actions, ld);
+ return;
+ }
+ }
+}
+
+static wmXrHapticAction *wm_xr_session_haptic_action_find(ListBase *active_haptic_actions,
+ const wmXrAction *action,
+ const char *subaction_path)
+{
+ LISTBASE_FOREACH (wmXrHapticAction *, ha, active_haptic_actions) {
+ if ((action == ha->action) && (subaction_path == ha->subaction_path)) {
+ return ha;
+ }
+ }
+ return NULL;
+}
+
+static void wm_xr_session_haptic_action_add(ListBase *active_haptic_actions,
+ const wmXrAction *action,
+ const char *subaction_path,
+ int64_t time_now)
+{
+ wmXrHapticAction *ha = wm_xr_session_haptic_action_find(
+ active_haptic_actions, action, subaction_path);
+ if (ha) {
+ /* Reset start time since OpenXR restarts haptics if they are already active. */
+ ha->time_start = time_now;
+ }
+ else {
+ ha = MEM_callocN(sizeof(wmXrHapticAction), __func__);
+ ha->action = (wmXrAction *)action;
+ ha->subaction_path = subaction_path;
+ ha->time_start = time_now;
+ BLI_addtail(active_haptic_actions, ha);
+ }
+}
+
+static void wm_xr_session_haptic_action_remove(ListBase *active_haptic_actions,
+ const wmXrAction *action)
+{
+ LISTBASE_FOREACH (wmXrHapticAction *, ha, active_haptic_actions) {
+ if (action == ha->action) {
+ BLI_freelinkN(active_haptic_actions, ha);
+ return;
+ }
+ }
+}
+
+static void wm_xr_session_haptic_timers_check(ListBase *active_haptic_actions, int64_t time_now)
+{
+ LISTBASE_FOREACH_MUTABLE (wmXrHapticAction *, ha, active_haptic_actions) {
+ if (time_now - ha->time_start >= ha->action->haptic_duration) {
+ BLI_freelinkN(active_haptic_actions, ha);
+ }
+ }
+}
+
+static void wm_xr_session_action_states_interpret(wmXrData *xr,
+ const char *action_set_name,
+ wmXrAction *action,
+ unsigned int subaction_idx,
+ ListBase *active_modal_actions,
+ ListBase *active_haptic_actions,
+ int64_t time_now,
+ bool modal,
+ bool haptic,
+ short *r_val)
+{
+ const char *haptic_subaction_path = ((action->haptic_flag & XR_HAPTIC_MATCHUSERPATHS) != 0) ?
+ action->subaction_paths[subaction_idx] :
+ NULL;
+ bool curr = false;
+ bool prev = false;
+
+ switch (action->type) {
+ case XR_BOOLEAN_INPUT: {
+ const bool *state = &((bool *)action->states)[subaction_idx];
+ bool *state_prev = &((bool *)action->states_prev)[subaction_idx];
+ if (*state) {
+ curr = true;
+ }
+ if (*state_prev) {
+ prev = true;
+ }
+ *state_prev = *state;
+ break;
+ }
+ case XR_FLOAT_INPUT: {
+ const float *state = &((float *)action->states)[subaction_idx];
+ float *state_prev = &((float *)action->states_prev)[subaction_idx];
+ if (test_float_state(
+ state, action->float_thresholds[subaction_idx], action->axis_flags[subaction_idx])) {
+ curr = true;
+ }
+ if (test_float_state(state_prev,
+ action->float_thresholds[subaction_idx],
+ action->axis_flags[subaction_idx])) {
+ prev = true;
+ }
+ *state_prev = *state;
+ break;
+ }
+ case XR_VECTOR2F_INPUT: {
+ const float(*state)[2] = &((float(*)[2])action->states)[subaction_idx];
+ float(*state_prev)[2] = &((float(*)[2])action->states_prev)[subaction_idx];
+ if (test_vec2f_state(*state,
+ action->float_thresholds[subaction_idx],
+ action->axis_flags[subaction_idx])) {
+ curr = true;
+ }
+ if (test_vec2f_state(*state_prev,
+ action->float_thresholds[subaction_idx],
+ action->axis_flags[subaction_idx])) {
+ prev = true;
+ }
+ copy_v2_v2(*state_prev, *state);
+ break;
+ }
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ if (curr) {
+ if (!prev) {
+ if (modal || (action->op_flag == XR_OP_PRESS)) {
+ *r_val = KM_PRESS;
+ }
+ if (haptic && (action->haptic_flag & (XR_HAPTIC_PRESS | XR_HAPTIC_REPEAT)) != 0) {
+ /* Apply haptics. */
+ if (WM_xr_haptic_action_apply(xr,
+ action_set_name,
+ action->haptic_name,
+ haptic_subaction_path,
+ &action->haptic_duration,
+ &action->haptic_frequency,
+ &action->haptic_amplitude)) {
+ wm_xr_session_haptic_action_add(
+ active_haptic_actions, action, haptic_subaction_path, time_now);
+ }
+ }
+ }
+ else if (modal) {
+ *r_val = KM_PRESS;
+ }
+ if (modal && !action->active_modal_path) {
+ /* Set active modal path. */
+ action->active_modal_path = action->subaction_paths[subaction_idx];
+ /* Add to active modal actions. */
+ wm_xr_session_modal_action_test_add(active_modal_actions, action);
+ }
+ if (haptic && ((action->haptic_flag & XR_HAPTIC_REPEAT) != 0)) {
+ if (!wm_xr_session_haptic_action_find(
+ active_haptic_actions, action, haptic_subaction_path)) {
+ /* Apply haptics. */
+ if (WM_xr_haptic_action_apply(xr,
+ action_set_name,
+ action->haptic_name,
+ haptic_subaction_path,
+ &action->haptic_duration,
+ &action->haptic_frequency,
+ &action->haptic_amplitude)) {
+ wm_xr_session_haptic_action_add(
+ active_haptic_actions, action, haptic_subaction_path, time_now);
+ }
+ }
+ }
+ }
+ else if (prev) {
+ if (modal || (action->op_flag == XR_OP_RELEASE)) {
+ *r_val = KM_RELEASE;
+ if (modal && (action->subaction_paths[subaction_idx] == action->active_modal_path)) {
+ /* Unset active modal path. */
+ action->active_modal_path = NULL;
+ /* Remove from active modal actions. */
+ wm_xr_session_modal_action_remove(active_modal_actions, action);
+ }
+ }
+ if (haptic) {
+ if ((action->haptic_flag & XR_HAPTIC_RELEASE) != 0) {
+ /* Apply haptics. */
+ if (WM_xr_haptic_action_apply(xr,
+ action_set_name,
+ action->haptic_name,
+ haptic_subaction_path,
+ &action->haptic_duration,
+ &action->haptic_frequency,
+ &action->haptic_amplitude)) {
+ wm_xr_session_haptic_action_add(
+ active_haptic_actions, action, haptic_subaction_path, time_now);
+ }
+ }
+ else if ((action->haptic_flag & XR_HAPTIC_REPEAT) != 0) {
+ /* Stop any active haptics. */
+ WM_xr_haptic_action_stop(xr, action_set_name, action->haptic_name, haptic_subaction_path);
+ wm_xr_session_haptic_action_remove(active_haptic_actions, action);
+ }
+ }
+ }
+}
+
+static bool wm_xr_session_action_test_bimanual(const wmXrSessionState *session_state,
+ wmXrAction *action,
+ unsigned int subaction_idx,
+ unsigned int *r_subaction_idx_other,
+ const GHOST_XrPose **r_aim_pose_other)
+{
+ if ((action->action_flag & XR_ACTION_BIMANUAL) == 0) {
+ return false;
+ }
+
+ bool bimanual = false;
+
+ *r_subaction_idx_other = (subaction_idx == 0) ?
+ (unsigned int)min_ii(1, action->count_subaction_paths - 1) :
+ 0;
+
+ switch (action->type) {
+ case XR_BOOLEAN_INPUT: {
+ const bool *state = &((bool *)action->states)[*r_subaction_idx_other];
+ if (*state) {
+ bimanual = true;
+ }
+ break;
+ }
+ case XR_FLOAT_INPUT: {
+ const float *state = &((float *)action->states)[*r_subaction_idx_other];
+ if (test_float_state(state,
+ action->float_thresholds[*r_subaction_idx_other],
+ action->axis_flags[*r_subaction_idx_other])) {
+ bimanual = true;
+ }
+ break;
+ }
+ case XR_VECTOR2F_INPUT: {
+ const float(*state)[2] = &((float(*)[2])action->states)[*r_subaction_idx_other];
+ if (test_vec2f_state(*state,
+ action->float_thresholds[*r_subaction_idx_other],
+ action->axis_flags[*r_subaction_idx_other])) {
+ bimanual = true;
+ }
+ break;
+ }
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ if (bimanual) {
+ *r_aim_pose_other = wm_xr_session_controller_aim_pose_find(
+ session_state, action->subaction_paths[*r_subaction_idx_other]);
+ }
+
+ return bimanual;
+}
+
+static wmXrActionData *wm_xr_session_event_create(const char *action_set_name,
+ const wmXrAction *action,
+ const GHOST_XrPose *controller_aim_pose,
+ const GHOST_XrPose *controller_aim_pose_other,
+ unsigned int subaction_idx,
+ unsigned int subaction_idx_other,
+ bool bimanual)
+{
+ wmXrActionData *data = MEM_callocN(sizeof(wmXrActionData), __func__);
+ strcpy(data->action_set, action_set_name);
+ strcpy(data->action, action->name);
+ data->type = action->type;
+
+ switch (action->type) {
+ case XR_BOOLEAN_INPUT:
+ data->state[0] = ((bool *)action->states)[subaction_idx] ? 1.0f : 0.0f;
+ if (bimanual) {
+ data->state_other[0] = ((bool *)action->states)[subaction_idx_other] ? 1.0f : 0.0f;
+ }
+ break;
+ case XR_FLOAT_INPUT:
+ data->state[0] = ((float *)action->states)[subaction_idx];
+ if (bimanual) {
+ data->state_other[0] = ((float *)action->states)[subaction_idx_other];
+ }
+ data->float_threshold = action->float_thresholds[subaction_idx];
+ break;
+ case XR_VECTOR2F_INPUT:
+ copy_v2_v2(data->state, ((float(*)[2])action->states)[subaction_idx]);
+ if (bimanual) {
+ copy_v2_v2(data->state_other, ((float(*)[2])action->states)[subaction_idx_other]);
+ }
+ data->float_threshold = action->float_thresholds[subaction_idx];
+ break;
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ BLI_assert_unreachable();
+ break;
+ }
+
+ if (controller_aim_pose) {
+ copy_v3_v3(data->controller_loc, controller_aim_pose->position);
+ copy_qt_qt(data->controller_rot, controller_aim_pose->orientation_quat);
+
+ if (bimanual && controller_aim_pose_other) {
+ copy_v3_v3(data->controller_loc_other, controller_aim_pose_other->position);
+ copy_qt_qt(data->controller_rot_other, controller_aim_pose_other->orientation_quat);
+ }
+ else {
+ data->controller_rot_other[0] = 1.0f;
+ }
+ }
+ else {
+ data->controller_rot[0] = 1.0f;
+ data->controller_rot_other[0] = 1.0f;
+ }
+
+ data->ot = action->ot;
+ data->op_properties = action->op_properties;
+
+ data->bimanual = bimanual;
+
+ return data;
+}
+
+/* Dispatch events to window queues. */
+static void wm_xr_session_events_dispatch(wmXrData *xr,
+ const XrSessionSettings *settings,
+ GHOST_XrContextHandle xr_context,
+ wmXrActionSet *action_set,
+ wmXrSessionState *session_state,
+ wmWindow *win)
+{
+ const char *action_set_name = action_set->name;
+
+ const unsigned int count = GHOST_XrGetActionCount(xr_context, action_set_name);
+ if (count < 1) {
+ return;
+ }
+
+ const int64_t time_now = (int64_t)(PIL_check_seconds_timer() * 1000);
+
+ ListBase *active_modal_actions = &action_set->active_modal_actions;
+ ListBase *active_haptic_actions = &action_set->active_haptic_actions;
+
+ wmXrAction **actions = MEM_calloc_arrayN(count, sizeof(*actions), __func__);
+
+ GHOST_XrGetActionCustomdataArray(xr_context, action_set_name, (void **)actions);
+
+ /* Check haptic action timers. */
+ wm_xr_session_haptic_timers_check(active_haptic_actions, time_now);
+
+ for (unsigned int action_idx = 0; action_idx < count; ++action_idx) {
+ wmXrAction *action = actions[action_idx];
+ if (action && action->ot) {
+ const bool modal = action->ot->modal;
+ const bool haptic = (GHOST_XrGetActionCustomdata(
+ xr_context, action_set_name, action->haptic_name) != NULL);
+
+ for (unsigned int subaction_idx = 0; subaction_idx < action->count_subaction_paths;
+ ++subaction_idx) {
+ short val = KM_NOTHING;
+
+ /* Interpret action states (update modal/haptic action lists, apply haptics, etc). */
+ wm_xr_session_action_states_interpret(xr,
+ action_set_name,
+ action,
+ subaction_idx,
+ active_modal_actions,
+ active_haptic_actions,
+ time_now,
+ modal,
+ haptic,
+ &val);
+
+ const bool is_active_modal_action = wm_xr_session_modal_action_test(
+ active_modal_actions, action, NULL);
+ const bool is_active_modal_subaction = (!action->active_modal_path ||
+ (action->subaction_paths[subaction_idx] ==
+ action->active_modal_path));
+
+ if ((val != KM_NOTHING) &&
+ (!modal || (is_active_modal_action && is_active_modal_subaction))) {
+ const GHOST_XrPose *aim_pose = wm_xr_session_controller_aim_pose_find(
+ session_state, action->subaction_paths[subaction_idx]);
+ const GHOST_XrPose *aim_pose_other = NULL;
+ unsigned int subaction_idx_other = 0;
+
+ /* Test for bimanual interaction. */
+ const bool bimanual = wm_xr_session_action_test_bimanual(
+ session_state, action, subaction_idx, &subaction_idx_other, &aim_pose_other);
+
+ wmXrActionData *actiondata = wm_xr_session_event_create(action_set_name,
+ action,
+ aim_pose,
+ aim_pose_other,
+ subaction_idx,
+ subaction_idx_other,
+ bimanual);
+ wm_event_add_xrevent(win, actiondata, val);
+ }
+ }
+ }
+ }
+
+ MEM_freeN(actions);
+}
+
void wm_xr_session_actions_update(wmWindowManager *wm)
{
wmXrData *xr = &wm->xr;
@@ -593,8 +1100,7 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
xr->runtime->area = ED_area_offscreen_create(win, SPACE_VIEW3D);
}
- /* Implemented in D10944. */
- // wm_xr_session_events_dispatch(xr, settings, xr_context, active_action_set, state, win);
+ wm_xr_session_events_dispatch(xr, settings, xr_context, active_action_set, state, win);
}
}
}