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:
-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);
}
}
}