From 9a808748887f567345e605e2704fb1cd930b4614 Mon Sep 17 00:00:00 2001 From: Peter Kim Date: Mon, 4 Apr 2022 16:55:07 +0900 Subject: XR: Add dedicated handling/API for VR trackers Allows for easier testing/debugging of tracker functionality by separating trackers from session controller data. Also, this should make it possible to use controllers and trackers during a VR session simultaneously. --- source/blender/makesdna/DNA_xr_types.h | 2 + source/blender/makesrna/intern/rna_xr.c | 159 +++++++++++++ source/blender/windowmanager/WM_api.h | 12 + .../blender/windowmanager/xr/intern/wm_xr_action.c | 84 +++++++ .../blender/windowmanager/xr/intern/wm_xr_draw.c | 31 ++- .../blender/windowmanager/xr/intern/wm_xr_intern.h | 13 +- .../windowmanager/xr/intern/wm_xr_session.c | 260 ++++++++++++++++----- 7 files changed, 494 insertions(+), 67 deletions(-) diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h index 6097dfcfe7e..e4b92fe885b 100644 --- a/source/blender/makesdna/DNA_xr_types.h +++ b/source/blender/makesdna/DNA_xr_types.h @@ -115,6 +115,8 @@ typedef enum eXrPoseFlag { /* Pose represents controller grip/aim. */ XR_POSE_GRIP = (1 << 0), XR_POSE_AIM = (1 << 1), + /* Pose represents VR tracker. */ + XR_POSE_TRACKER = (1 << 2), } eXrPoseFlag; typedef enum eXrMotionCaptureFlag { diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c index db35807b151..65f99166e51 100644 --- a/source/blender/makesrna/intern/rna_xr.c +++ b/source/blender/makesrna/intern/rna_xr.c @@ -523,6 +523,29 @@ static void rna_XrActionMapItem_pose_is_controller_aim_set(PointerRNA *ptr, bool # endif } +static bool rna_XrActionMapItem_pose_is_tracker_get(PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + XrActionMapItem *ami = ptr->data; + if ((ami->pose_flag & XR_POSE_TRACKER) != 0) { + return true; + } +# else + UNUSED_VARS(ptr); +# endif + return false; +} + +static void rna_XrActionMapItem_pose_is_tracker_set(PointerRNA *ptr, bool value) +{ +# ifdef WITH_XR_OPENXR + XrActionMapItem *ami = ptr->data; + SET_FLAG_FROM_TEST(ami->pose_flag, value, XR_POSE_TRACKER); +# else + UNUSED_VARS(ptr, value); +# endif +} + static void rna_XrActionMapItem_bindings_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) { # ifdef WITH_XR_OPENXR @@ -1048,6 +1071,32 @@ bool rna_XrSessionState_controller_pose_actions_set(bContext *C, # endif } +bool rna_XrSessionState_tracker_pose_action_add(bContext *C, + const char *action_set_name, + const char *tracker_action_name) +{ +# ifdef WITH_XR_OPENXR + wmWindowManager *wm = CTX_wm_manager(C); + return WM_xr_tracker_pose_action_add(&wm->xr, action_set_name, tracker_action_name); +# else + UNUSED_VARS(C, action_set_name, tracker_action_name); + return false; +# endif +} + +bool rna_XrSessionState_tracker_pose_action_remove(bContext *C, + const char *action_set_name, + const char *tracker_action_name) +{ +# ifdef WITH_XR_OPENXR + wmWindowManager *wm = CTX_wm_manager(C); + return WM_xr_tracker_pose_action_remove(&wm->xr, action_set_name, tracker_action_name); +# else + UNUSED_VARS(C, action_set_name, tracker_action_name); + return false; +# endif +} + void rna_XrSessionState_action_state_get(bContext *C, const char *action_set_name, const char *action_name, @@ -1171,6 +1220,32 @@ static void rna_XrSessionState_controller_aim_rotation_get(bContext *C, # endif } +static void rna_XrSessionState_tracker_location_get(bContext *C, + const char *user_path, + float r_values[3]) +{ +# ifdef WITH_XR_OPENXR + const wmWindowManager *wm = CTX_wm_manager(C); + WM_xr_session_state_tracker_location_get(&wm->xr, user_path, r_values); +# else + UNUSED_VARS(C, user_path); + zero_v3(r_values); +# endif +} + +static void rna_XrSessionState_tracker_rotation_get(bContext *C, + const char *user_path, + float r_values[4]) +{ +# ifdef WITH_XR_OPENXR + const wmWindowManager *wm = CTX_wm_manager(C); + WM_xr_session_state_tracker_rotation_get(&wm->xr, user_path, r_values); +# else + UNUSED_VARS(C, user_path); + unit_qt(r_values); +# endif +} + static void rna_XrSessionState_viewer_pose_location_get(PointerRNA *ptr, float *r_values) { # ifdef WITH_XR_OPENXR @@ -1827,6 +1902,11 @@ static void rna_def_xr_actionmap(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Is Controller Aim", "The action poses will be used for the VR controller aims"); + prop = RNA_def_property(srna, "pose_is_tracker", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_funcs( + prop, "rna_XrActionMapItem_pose_is_tracker_get", "rna_XrActionMapItem_pose_is_tracker_set"); + RNA_def_property_ui_text(prop, "Is Tracker", "The action poses represent a VR tracker"); + prop = RNA_def_property(srna, "haptic_name", PROP_STRING, PROP_NONE); RNA_def_property_ui_text( prop, "Haptic Name", "Name of the haptic action to apply when executing this action"); @@ -2359,6 +2439,42 @@ static void rna_def_xr_session_state(BlenderRNA *brna) parm = RNA_def_boolean(func, "result", 0, "Result", ""); RNA_def_function_return(func, parm); + func = RNA_def_function( + srna, "tracker_pose_action_add", "rna_XrSessionState_tracker_pose_action_add"); + RNA_def_function_ui_description(func, "Add a VR tracker pose to the session"); + RNA_def_function_flag(func, FUNC_NO_SELF); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_string(func, "action_set", NULL, MAX_NAME, "Action Set", "Action set name"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_string(func, + "tracker_action", + NULL, + MAX_NAME, + "Tracker Action", + "Name of the action representing the VR tracker"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_boolean(func, "result", 0, "Result", ""); + RNA_def_function_return(func, parm); + + func = RNA_def_function( + srna, "tracker_pose_action_remove", "rna_XrSessionState_tracker_pose_action_remove"); + RNA_def_function_ui_description(func, "Remove a VR tracker pose from the session"); + RNA_def_function_flag(func, FUNC_NO_SELF); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_string(func, "action_set", NULL, MAX_NAME, "Action Set", "Action set name"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_string(func, + "tracker_action", + NULL, + MAX_NAME, + "Tracker Action", + "Name of the action representing the VR tracker"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_boolean(func, "result", 0, "Result", ""); + RNA_def_function_return(func, parm); + func = RNA_def_function(srna, "action_state_get", "rna_XrSessionState_action_state_get"); RNA_def_function_ui_description(func, "Get the current state of a VR action"); RNA_def_function_flag(func, FUNC_NO_SELF); @@ -2541,6 +2657,49 @@ static void rna_def_xr_session_state(BlenderRNA *brna) RNA_def_property_ui_range(parm, -FLT_MAX, FLT_MAX, 1, 5); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_OUTPUT); + func = RNA_def_function(srna, "tracker_location_get", "rna_XrSessionState_tracker_location_get"); + RNA_def_function_ui_description(func, "Get the last known tracker location in world space"); + RNA_def_function_flag(func, FUNC_NO_SELF); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_string( + func, "user_path", NULL, XR_MAX_USER_PATH_LENGTH, "User Path", "OpenXR user path"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_float_translation(func, + "location", + 3, + NULL, + -FLT_MAX, + FLT_MAX, + "Location", + "Tracker location", + -FLT_MAX, + FLT_MAX); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_OUTPUT); + + func = RNA_def_function(srna, "tracker_rotation_get", "rna_XrSessionState_tracker_rotation_get"); + RNA_def_function_ui_description( + func, "Get the last known tracker rotation (quaternion) in world space"); + RNA_def_function_flag(func, FUNC_NO_SELF); + parm = RNA_def_pointer(func, "context", "Context", "", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_string( + func, "user_path", NULL, XR_MAX_USER_PATH_LENGTH, "User Path", "OpenXR user path"); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); + parm = RNA_def_float_vector(func, + "rotation", + 4, + NULL, + -FLT_MAX, + FLT_MAX, + "Rotation", + "Tracker quaternion rotation", + -FLT_MAX, + FLT_MAX); + parm->subtype = PROP_QUATERNION; + RNA_def_property_ui_range(parm, -FLT_MAX, FLT_MAX, 1, 5); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_OUTPUT); + prop = RNA_def_property(srna, "viewer_pose_location", PROP_FLOAT, PROP_TRANSLATION); RNA_def_property_array(prop, 3); RNA_def_property_float_funcs(prop, "rna_XrSessionState_viewer_pose_location_get", NULL, NULL); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index cf5d082445c..7bb2ce18ef7 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -1592,6 +1592,12 @@ bool WM_xr_session_state_controller_aim_location_get(const wmXrData *xr, bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr, unsigned int subaction_idx, float r_rotation[4]); +bool WM_xr_session_state_tracker_location_get(const wmXrData *xr, + const char *subaction_path, + float r_location[3]); +bool WM_xr_session_state_tracker_rotation_get(const wmXrData *xr, + const char *subaction_path, + float r_rotation[4]); bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3]); void WM_xr_session_state_nav_location_set(wmXrData *xr, const float location[3]); bool WM_xr_session_state_nav_rotation_get(const wmXrData *xr, float r_rotation[4]); @@ -1647,6 +1653,12 @@ bool WM_xr_controller_pose_actions_set(wmXrData *xr, const char *action_set_name, const char *grip_action_name, const char *aim_action_name); +bool WM_xr_tracker_pose_action_add(wmXrData *xr, + const char *action_set_name, + const char *tracker_action_name); +bool WM_xr_tracker_pose_action_remove(wmXrData *xr, + const char *action_set_name, + const char *tracker_action_name); /** * XR action functions to be called post-XR session start. diff --git a/source/blender/windowmanager/xr/intern/wm_xr_action.c b/source/blender/windowmanager/xr/intern/wm_xr_action.c index 6750e7a7d77..e45acb5a7b4 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_action.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_action.c @@ -43,6 +43,7 @@ static void action_set_destroy(void *val) MEM_SAFE_FREE(action_set->name); + BLI_freelistN(&action_set->tracker_actions); BLI_freelistN(&action_set->active_modal_actions); BLI_freelistN(&action_set->active_haptic_actions); @@ -200,6 +201,11 @@ void WM_xr_action_set_destroy(wmXrData *xr, const char *action_set_name) action_set->controller_grip_action = action_set->controller_aim_action = NULL; } + if (!BLI_listbase_is_empty(&action_set->tracker_actions)) { + wm_xr_session_tracker_data_clear(session_state); + BLI_freelistN(&action_set->tracker_actions); + } + BLI_freelistN(&action_set->active_modal_actions); BLI_freelistN(&action_set->active_haptic_actions); @@ -309,6 +315,14 @@ void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char action_set->controller_grip_action = action_set->controller_aim_action = NULL; } + LISTBASE_FOREACH (LinkData *, ld, &action_set->tracker_actions) { + wmXrAction *tracker_action = ld->data; + if (STREQ(tracker_action->name, action_name)) { + WM_xr_tracker_pose_action_remove(xr, action_set_name, action_name); + break; + } + } + LISTBASE_FOREACH (LinkData *, ld, &action_set->active_modal_actions) { wmXrAction *active_modal_action = ld->data; if (STREQ(active_modal_action->name, action_name)) { @@ -409,6 +423,7 @@ bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name) xr->runtime->session_state.active_action_set = action_set; + /* Update controller/tracker data. */ 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); @@ -417,6 +432,13 @@ bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name) wm_xr_session_controller_data_clear(&xr->runtime->session_state); } + if (!BLI_listbase_is_empty(&action_set->tracker_actions)) { + wm_xr_session_tracker_data_populate(&action_set->tracker_actions, xr); + } + else { + wm_xr_session_tracker_data_clear(&xr->runtime->session_state); + } + return true; } @@ -462,6 +484,68 @@ bool WM_xr_controller_pose_actions_set(wmXrData *xr, return true; } +bool WM_xr_tracker_pose_action_add(wmXrData *xr, + const char *action_set_name, + const char *tracker_action_name) +{ + wmXrActionSet *action_set = action_set_find(xr, action_set_name); + if (!action_set) { + return false; + } + + wmXrAction *tracker_action = action_find(xr, action_set_name, tracker_action_name); + if (!tracker_action) { + return false; + } + + LinkData *ld = MEM_callocN(sizeof(*ld), __func__); + ld->data = tracker_action; + BLI_addtail(&action_set->tracker_actions, ld); + + if (action_set == xr->runtime->session_state.active_action_set) { + wm_xr_session_tracker_data_populate(&action_set->tracker_actions, xr); + } + + return true; +} + +bool WM_xr_tracker_pose_action_remove(wmXrData *xr, + const char *action_set_name, + const char *tracker_action_name) +{ + wmXrActionSet *action_set = action_set_find(xr, action_set_name); + if (!action_set) { + return false; + } + + wmXrAction *tracker_action = action_find(xr, action_set_name, tracker_action_name); + if (!tracker_action) { + return false; + } + + bool removed = false; + + LISTBASE_FOREACH (LinkData *, ld, &action_set->tracker_actions) { + wmXrAction *tracker_action = ld->data; + if (STREQ(tracker_action->name, tracker_action_name)) { + BLI_freelinkN(&action_set->tracker_actions, ld); + removed = true; + break; + } + } + + if (action_set == xr->runtime->session_state.active_action_set) { + if (BLI_listbase_is_empty(&action_set->tracker_actions)) { + wm_xr_session_tracker_data_clear(&xr->runtime->session_state); + } + else { + wm_xr_session_tracker_data_populate(&action_set->tracker_actions, xr); + } + } + + return removed; +} + bool WM_xr_action_state_get(const wmXrData *xr, const char *action_set_name, const char *action_name, diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c index 303ecca17f0..57d20e5f0c2 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c @@ -225,7 +225,7 @@ static GPUBatch *wm_xr_controller_model_batch_create(GHOST_XrContextHandle xr_co static void wm_xr_controller_model_draw(const XrSessionSettings *settings, GHOST_XrContextHandle xr_context, - wmXrSessionState *state) + ListBase *controllers) { GHOST_XrControllerModelData model_data; @@ -244,7 +244,7 @@ static void wm_xr_controller_model_draw(const XrSessionSettings *settings, GPU_depth_test(GPU_DEPTH_NONE); GPU_blend(GPU_BLEND_ALPHA); - LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) { + LISTBASE_FOREACH (wmXrController *, controller, controllers) { GPUBatch *model = controller->model; if (!model) { model = controller->model = wm_xr_controller_model_batch_create(xr_context, @@ -287,7 +287,7 @@ static void wm_xr_controller_model_draw(const XrSessionSettings *settings, } } -static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, wmXrSessionState *state) +static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, ListBase *controllers) { bool draw_ray; switch (settings->controller_draw_style) { @@ -320,9 +320,9 @@ static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, wmXrSes GPU_depth_test(GPU_DEPTH_LESS_EQUAL); GPU_blend(GPU_BLEND_ALPHA); - immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(&state->controllers) * 2); + immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(controllers) * 2); - LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) { + LISTBASE_FOREACH (wmXrController *, controller, controllers) { const float(*mat)[4] = controller->aim_mat; madd_v3_v3v3fl(ray, mat[3], mat[2], -scale); @@ -344,9 +344,9 @@ static void wm_xr_controller_aim_draw(const XrSessionSettings *settings, wmXrSes GPU_depth_test(GPU_DEPTH_NONE); GPU_blend(GPU_BLEND_NONE); - immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(&state->controllers) * 6); + immBegin(GPU_PRIM_LINES, (uint)BLI_listbase_count(controllers) * 6); - LISTBASE_FOREACH (wmXrController *, controller, &state->controllers) { + LISTBASE_FOREACH (wmXrController *, controller, controllers) { const float(*mat)[4] = controller->aim_mat; madd_v3_v3v3fl(x_axis, mat[3], mat[0], scale); madd_v3_v3v3fl(y_axis, mat[3], mat[1], scale); @@ -379,8 +379,19 @@ void wm_xr_draw_controllers(const bContext *UNUSED(C), ARegion *UNUSED(region), wmXrData *xr = customdata; const XrSessionSettings *settings = &xr->session_settings; GHOST_XrContextHandle xr_context = xr->runtime->context; - wmXrSessionState *state = &xr->runtime->session_state; + ListBase *controllers = &xr->runtime->session_state.controllers; - wm_xr_controller_model_draw(settings, xr_context, state); - wm_xr_controller_aim_draw(settings, state); + wm_xr_controller_model_draw(settings, xr_context, controllers); + wm_xr_controller_aim_draw(settings, controllers); +} + +void wm_xr_draw_trackers(const bContext *UNUSED(C), ARegion *UNUSED(region), void *customdata) +{ + wmXrData *xr = customdata; + const XrSessionSettings *settings = &xr->session_settings; + GHOST_XrContextHandle xr_context = xr->runtime->context; + ListBase *trackers = &xr->runtime->session_state.trackers; + + wm_xr_controller_model_draw(settings, xr_context, trackers); + wm_xr_controller_aim_draw(settings, trackers); } diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h index c493deba7e4..4de28f43213 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h +++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h @@ -52,6 +52,8 @@ typedef struct wmXrSessionState { /** Last known controller data. */ ListBase controllers; /* #wmXrController */ + /** Last known tracker data. */ + ListBase trackers; /* #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 @@ -92,6 +94,8 @@ typedef struct { struct ARegionType *controller_art; /** Controller draw callback handle. */ void *controller_draw_handle; + /** Tracker draw callback handle. */ + void *tracker_draw_handle; } wmXrSurfaceData; typedef struct wmXrDrawData { @@ -176,11 +180,13 @@ typedef struct wmXrActionSet { /** XR pose actions that determine the controller grip/aim transforms. */ wmXrAction *controller_grip_action; wmXrAction *controller_aim_action; + /** XR pose actions that determine tracker transforms. */ + ListBase tracker_actions; /* #LinkData */ /** Currently active modal actions. */ - ListBase active_modal_actions; + ListBase active_modal_actions; /* #LinkData */ /** Currently active haptic actions. */ - ListBase active_haptic_actions; + ListBase active_haptic_actions; /* wmXrHapticAction */ } wmXrActionSet; typedef struct wmXrMotionCapturePose { @@ -223,6 +229,8 @@ 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_session_tracker_data_populate(const ListBase *tracker_actions, wmXrData *xr); +void wm_xr_session_tracker_data_clear(wmXrSessionState *state); /* wm_xr_draw.c */ void wm_xr_pose_to_mat(const GHOST_XrPose *pose, float r_mat[4][4]); @@ -237,6 +245,7 @@ void wm_xr_pose_scale_to_imat(const GHOST_XrPose *pose, float scale, float r_ima */ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata); void wm_xr_draw_controllers(const struct bContext *C, struct ARegion *region, void *customdata); +void wm_xr_draw_trackers(const struct bContext *C, struct ARegion *region, void *customdata); /* wm_xr_mocap.c */ void wm_xr_mocap_orig_poses_store(const XrSessionSettings *settings, wmXrSessionState *state); diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index 7c6caaa876e..09cbea56b69 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -75,22 +75,21 @@ static void wm_xr_session_create_cb(void) wm_xr_mocap_orig_poses_store(settings, state); } -static void wm_xr_session_controller_data_free(wmXrSessionState *state) +static void wm_xr_session_controller_data_free(ListBase *controllers) { - ListBase *lb = &state->controllers; wmXrController *c; - - while ((c = BLI_pophead(lb))) { + while ((c = BLI_pophead(controllers))) { if (c->model) { GPU_batch_discard(c->model); } - BLI_freelinkN(lb, c); + BLI_freelinkN(controllers, c); } } void wm_xr_session_data_free(wmXrSessionState *state) { - wm_xr_session_controller_data_free(state); + wm_xr_session_controller_data_free(&state->controllers); + wm_xr_session_controller_data_free(&state->trackers); BLI_freelistN(&state->mocap_orig_poses); } @@ -509,6 +508,48 @@ bool WM_xr_session_state_controller_aim_rotation_get(const wmXrData *xr, return true; } +bool WM_xr_session_state_tracker_location_get(const wmXrData *xr, + const char *subaction_path, + float r_location[3]) +{ + if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) { + zero_v3(r_location); + return false; + } + + const wmXrController *tracker = BLI_findstring(&xr->runtime->session_state.trackers, + subaction_path, + offsetof(wmXrController, subaction_path)); + if (!tracker) { + zero_v3(r_location); + return false; + } + + copy_v3_v3(r_location, tracker->grip_pose.position); + return true; +} + +bool WM_xr_session_state_tracker_rotation_get(const wmXrData *xr, + const char *subaction_path, + float r_rotation[4]) +{ + if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) { + unit_qt(r_rotation); + return false; + } + + const wmXrController *tracker = BLI_findstring(&xr->runtime->session_state.trackers, + subaction_path, + offsetof(wmXrController, subaction_path)); + if (!tracker) { + unit_qt(r_rotation); + return false; + } + + copy_qt_qt(r_rotation, tracker->grip_pose.orientation_quat); + return true; +} + bool WM_xr_session_state_nav_location_get(const wmXrData *xr, float r_location[3]) { if (!WM_xr_session_is_ready(xr) || !xr->runtime->session_state.is_view_data_set) { @@ -618,14 +659,70 @@ static void wm_xr_session_controller_pose_calc(const GHOST_XrPose *raw_pose, static void wm_xr_session_controller_data_update(const wmXrAction *grip_action, const wmXrAction *aim_action, + unsigned int subaction_idx, + const float view_ofs[3], + const float base_mat[4][4], + const float nav_mat[4][4], bContext *C, XrSessionSettings *settings, GHOST_XrContextHandle xr_context, - wmXrSessionState *state, - wmWindow *win) + Scene *scene, + ViewLayer *view_layer, + wmWindow *win, + bScreen *screen_anim, + bool *notify, + wmXrController *controller) +{ + wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)grip_action->states)[subaction_idx], + view_ofs, + base_mat, + nav_mat, + &controller->grip_pose, + controller->grip_mat, + controller->grip_mat_base); + wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)aim_action->states)[subaction_idx], + view_ofs, + base_mat, + nav_mat, + &controller->aim_pose, + controller->aim_mat, + controller->aim_mat_base); + + /* Update motion capture objects. */ + wm_xr_mocap_objects_update(controller->subaction_path, + &controller->grip_pose, + C, + settings, + scene, + view_layer, + win, + screen_anim, + notify); + + /* Update controller model. */ + if (!controller->model) { + /* Notify GHOST to load/continue loading the controller model data. This can be called more + * than once since the model may not be available from the runtime yet. The batch itself will + * be created in wm_xr_draw_controllers(). */ + GHOST_XrLoadControllerModel(xr_context, controller->subaction_path); + } + else { + GHOST_XrUpdateControllerModelComponents(xr_context, controller->subaction_path); + } +} + +static void wm_xr_session_controller_and_tracker_data_update(const wmXrAction *grip_action, + const wmXrAction *aim_action, + const ListBase *tracker_actions, + bContext *C, + XrSessionSettings *settings, + GHOST_XrContextHandle xr_context, + wmXrSessionState *state, + wmWindow *win) { BLI_assert(grip_action->count_subaction_paths == aim_action->count_subaction_paths); BLI_assert(grip_action->count_subaction_paths == BLI_listbase_count(&state->controllers)); + BLI_assert(BLI_listbase_count(tracker_actions) <= BLI_listbase_count(&state->trackers)); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -633,6 +730,7 @@ static void wm_xr_session_controller_data_update(const wmXrAction *grip_action, bScreen *screen_anim = ED_screen_animation_playing(wm); bool notify = true; unsigned int subaction_idx = 0; + wmXrController *tracker = state->trackers.first; float view_ofs[3], base_mat[4][4], nav_mat[4][4]; if ((settings->flag & XR_SESSION_USE_POSITION_TRACKING) == 0) { @@ -648,42 +746,47 @@ static void wm_xr_session_controller_data_update(const wmXrAction *grip_action, wm_xr_pose_scale_to_mat(&state->prev_base_pose, state->prev_base_scale, base_mat); wm_xr_pose_scale_to_mat(&state->nav_pose, state->nav_scale, nav_mat); + /* Update controllers. */ 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, - nav_mat, - &controller->grip_pose, - controller->grip_mat, - controller->grip_mat_base); - wm_xr_session_controller_pose_calc(&((GHOST_XrPose *)aim_action->states)[subaction_idx], - view_ofs, - base_mat, - nav_mat, - &controller->aim_pose, - controller->aim_mat, - controller->aim_mat_base); - - /* Update motion capture objects. */ - wm_xr_mocap_objects_update(controller->subaction_path, - &controller->grip_pose, - C, - settings, - scene, - view_layer, - win, - screen_anim, - ¬ify); - - /* Update controller model. */ - if (!controller->model) { - /* Notify GHOST to load/continue loading the controller model data. This can be called more - * than once since the model may not be available from the runtime yet. The batch itself will - * be created in wm_xr_draw_controllers(). */ - GHOST_XrLoadControllerModel(xr_context, controller->subaction_path); - } - else { - GHOST_XrUpdateControllerModelComponents(xr_context, controller->subaction_path); + wm_xr_session_controller_data_update(grip_action, + aim_action, + subaction_idx, + view_ofs, + base_mat, + nav_mat, + C, + settings, + xr_context, + scene, + view_layer, + win, + screen_anim, + ¬ify, + controller); + } + + /* Update trackers. */ + LISTBASE_FOREACH (LinkData *, ld, tracker_actions) { + const wmXrAction *tracker_action = ld->data; + + for (subaction_idx = 0; subaction_idx < tracker_action->count_subaction_paths; + ++subaction_idx) { + wm_xr_session_controller_data_update(tracker_action, + tracker_action, + subaction_idx, + view_ofs, + base_mat, + nav_mat, + C, + settings, + xr_context, + scene, + view_layer, + win, + screen_anim, + ¬ify, + tracker); + tracker = tracker->next; } } } @@ -1244,14 +1347,16 @@ void wm_xr_session_actions_update(const bContext *C) /* Only update controller data and dispatch events for active action set. */ if (active_action_set) { - if (active_action_set->controller_grip_action && active_action_set->controller_aim_action) { - wm_xr_session_controller_data_update(active_action_set->controller_grip_action, - active_action_set->controller_aim_action, - (bContext *)C, - settings, - xr_context, - state, - win); + if ((active_action_set->controller_grip_action && active_action_set->controller_aim_action) || + !BLI_listbase_is_empty(&active_action_set->tracker_actions)) { + wm_xr_session_controller_and_tracker_data_update(active_action_set->controller_grip_action, + active_action_set->controller_aim_action, + &active_action_set->tracker_actions, + (bContext *)C, + settings, + xr_context, + state, + win); } if (win) { @@ -1273,15 +1378,13 @@ void wm_xr_session_controller_data_populate(const wmXrAction *grip_action, wmXrSessionState *state = &xr->runtime->session_state; ListBase *controllers = &state->controllers; - 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); + wm_xr_session_controller_data_free(controllers); for (unsigned int i = 0; i < count; ++i) { 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]); @@ -1302,7 +1405,7 @@ void wm_xr_session_controller_data_populate(const wmXrAction *grip_action, void wm_xr_session_controller_data_clear(wmXrSessionState *state) { - wm_xr_session_controller_data_free(state); + wm_xr_session_controller_data_free(&state->controllers); /* Deactivate draw callback. */ if (g_xr_surface) { @@ -1316,6 +1419,53 @@ void wm_xr_session_controller_data_clear(wmXrSessionState *state) } } +void wm_xr_session_tracker_data_populate(const ListBase *tracker_actions, wmXrData *xr) +{ + wmXrSessionState *state = &xr->runtime->session_state; + ListBase *trackers = &state->trackers; + + wm_xr_session_controller_data_free(trackers); + + LISTBASE_FOREACH (const LinkData *, ld, tracker_actions) { + const wmXrAction *tracker_action = ld->data; + + for (unsigned int subaction_idx = 0; subaction_idx < tracker_action->count_subaction_paths; + ++subaction_idx) { + wmXrController *tracker = MEM_callocN(sizeof(*tracker), __func__); + strcpy(tracker->subaction_path, tracker_action->subaction_paths[subaction_idx]); + + BLI_addtail(trackers, tracker); + } + } + + /* Activate draw callback. */ + if (g_xr_surface) { + wmXrSurfaceData *surface_data = g_xr_surface->customdata; + if (surface_data && !surface_data->tracker_draw_handle) { + if (surface_data->controller_art) { + surface_data->tracker_draw_handle = ED_region_draw_cb_activate( + surface_data->controller_art, wm_xr_draw_trackers, xr, REGION_DRAW_POST_VIEW); + } + } + } +} + +void wm_xr_session_tracker_data_clear(wmXrSessionState *state) +{ + wm_xr_session_controller_data_free(&state->trackers); + + /* Deactivate draw callback. */ + if (g_xr_surface) { + wmXrSurfaceData *surface_data = g_xr_surface->customdata; + if (surface_data && surface_data->tracker_draw_handle) { + if (surface_data->controller_art) { + ED_region_draw_cb_exit(surface_data->controller_art, surface_data->tracker_draw_handle); + } + surface_data->tracker_draw_handle = NULL; + } + } +} + /** \} */ /* XR-Session Actions */ /* -------------------------------------------------------------------- */ -- cgit v1.2.3