From 6a8709ba136ef4e8522555f279294a886595e34c Mon Sep 17 00:00:00 2001 From: Peter Kim Date: Thu, 17 Feb 2022 15:41:53 +0900 Subject: XR: Allow variable count of action map subactions Previously, the number of action map subactions was limited to two per action (identified by user_path0, user_path1), however for devices with more than two user paths (e.g. Vive Tracker) it will be useful to support a variable amount instead. For example, a single pose action could then be used to query the positions of all connected trackers, with each tracker having its own subaction tracking space. NOTE: This introduces breaking changes for the XR Python API as follows: - XrActionMapItem: The new `user_paths` collection property replaces the `user_path0`/`user_path1` properties. - XrActionMapBinding: The new `component_paths` collection property replaces the `component_path0`/`component_path1` properties. Reviewed By: Severin Differential Revision: https://developer.blender.org/D13949 --- source/blender/makesdna/DNA_xr_types.h | 26 +- source/blender/makesrna/intern/rna_xr.c | 402 +++++++++++++++++---- source/blender/windowmanager/WM_api.h | 8 +- .../blender/windowmanager/xr/intern/wm_xr_action.c | 74 ++-- .../windowmanager/xr/intern/wm_xr_actionmap.c | 35 +- .../blender/windowmanager/xr/intern/wm_xr_intern.h | 8 +- .../windowmanager/xr/intern/wm_xr_session.c | 5 +- 7 files changed, 422 insertions(+), 136 deletions(-) diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h index bf77339a494..09eab0d7bf7 100644 --- a/source/blender/makesdna/DNA_xr_types.h +++ b/source/blender/makesdna/DNA_xr_types.h @@ -106,8 +106,23 @@ typedef enum eXrPoseFlag { XR_POSE_AIM = (1 << 1), } eXrPoseFlag; +/** + * The following user and component path lengths are dependent on OpenXR's XR_MAX_PATH_LENGTH + * (256). A user path will be combined with a component path to identify an action binding, and + * that combined path should also have a max of XR_MAX_PATH_LENGTH (e.g. user_path = + * /user/hand/left, component_path = /input/trigger/value, full_path = + * /user/hand/left/input/trigger/value). + */ +#define XR_MAX_USER_PATH_LENGTH 64 +#define XR_MAX_COMPONENT_PATH_LENGTH 192 + /* -------------------------------------------------------------------- */ +typedef struct XrComponentPath { + struct XrComponentPath *next, *prev; + char path[192]; /* XR_MAX_COMPONENT_PATH_LENGTH */ +} XrComponentPath; + typedef struct XrActionMapBinding { struct XrActionMapBinding *next, *prev; @@ -117,8 +132,7 @@ typedef struct XrActionMapBinding { /** OpenXR interaction profile path. */ char profile[256]; /** OpenXR component paths. */ - char component_path0[192]; - char component_path1[192]; + ListBase component_paths; /* XrComponentPath */ /** Input threshold/region. */ float float_threshold; @@ -132,6 +146,11 @@ typedef struct XrActionMapBinding { /* -------------------------------------------------------------------- */ +typedef struct XrUserPath { + struct XrUserPath *next, *prev; + char path[64]; /* XR_MAX_USER_PATH_LENGTH */ +} XrUserPath; + typedef struct XrActionMapItem { struct XrActionMapItem *next, *prev; @@ -142,8 +161,7 @@ typedef struct XrActionMapItem { char _pad[7]; /** OpenXR user paths. */ - char user_path0[64]; - char user_path1[64]; + ListBase user_paths; /* XrUserPath */ /** Operator to be called on XR events. */ char op[64]; /* OP_MAX_TYPENAME */ diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c index 87d8bc8d844..9fe3153eb1e 100644 --- a/source/blender/makesrna/intern/rna_xr.c +++ b/source/blender/makesrna/intern/rna_xr.c @@ -46,6 +46,43 @@ static wmXrData *rna_XrSession_wm_xr_data_get(PointerRNA *ptr) /** \name XR Action Map * \{ */ +static XrComponentPath *rna_XrComponentPath_new(XrActionMapBinding *amb, const char *path_str) +{ +# ifdef WITH_XR_OPENXR + XrComponentPath *component_path = MEM_callocN(sizeof(XrComponentPath), __func__); + BLI_strncpy(component_path->path, path_str, sizeof(component_path->path)); + BLI_addtail(&amb->component_paths, component_path); + return component_path; +# else + UNUSED_VARS(amb, path_str); + return NULL; +# endif +} + +static void rna_XrComponentPath_remove(XrActionMapBinding *amb, PointerRNA *component_path_ptr) +{ +# ifdef WITH_XR_OPENXR + XrComponentPath *component_path = component_path_ptr->data; + int idx = BLI_findindex(&amb->component_paths, component_path); + if (idx != -1) { + BLI_freelinkN(&amb->component_paths, component_path); + } + RNA_POINTER_INVALIDATE(component_path_ptr); +# else + UNUSED_VARS(amb, component_path_ptr); +# endif +} + +static XrComponentPath *rna_XrComponentPath_find(XrActionMapBinding *amb, const char *path_str) +{ +# ifdef WITH_XR_OPENXR + return BLI_findstring(&amb->component_paths, path_str, offsetof(XrComponentPath, path)); +# else + UNUSED_VARS(amb, path_str); + return NULL; +# endif +} + static XrActionMapBinding *rna_XrActionMapBinding_new(XrActionMapItem *ami, const char *name, bool replace_existing) @@ -99,6 +136,28 @@ static XrActionMapBinding *rna_XrActionMapBinding_find(XrActionMapItem *ami, con # endif } +static void rna_XrActionMapBinding_component_paths_begin(CollectionPropertyIterator *iter, + PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + XrActionMapBinding *amb = (XrActionMapBinding *)ptr->data; + rna_iterator_listbase_begin(iter, &amb->component_paths, NULL); +# else + UNUSED_VARS(iter, ptr); +# endif +} + +static int rna_XrActionMapBinding_component_paths_length(PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + XrActionMapBinding *amb = (XrActionMapBinding *)ptr->data; + return BLI_listbase_count(&amb->component_paths); +# else + UNUSED_VARS(ptr); + return 0; +# endif +} + static int rna_XrActionMapBinding_axis0_region_get(PointerRNA *ptr) { # ifdef WITH_XR_OPENXR @@ -174,6 +233,43 @@ static void rna_XrActionMapBinding_name_update(Main *bmain, Scene *UNUSED(scene) # endif } +static XrUserPath *rna_XrUserPath_new(XrActionMapItem *ami, const char *path_str) +{ +# ifdef WITH_XR_OPENXR + XrUserPath *user_path = MEM_callocN(sizeof(XrUserPath), __func__); + BLI_strncpy(user_path->path, path_str, sizeof(user_path->path)); + BLI_addtail(&ami->user_paths, user_path); + return user_path; +# else + UNUSED_VARS(ami, path_str); + return NULL; +# endif +} + +static void rna_XrUserPath_remove(XrActionMapItem *ami, PointerRNA *user_path_ptr) +{ +# ifdef WITH_XR_OPENXR + XrUserPath *user_path = user_path_ptr->data; + int idx = BLI_findindex(&ami->user_paths, user_path); + if (idx != -1) { + BLI_freelinkN(&ami->user_paths, user_path); + } + RNA_POINTER_INVALIDATE(user_path_ptr); +# else + UNUSED_VARS(ami, user_path_ptr); +# endif +} + +static XrUserPath *rna_XrUserPath_find(XrActionMapItem *ami, const char *path_str) +{ +# ifdef WITH_XR_OPENXR + return BLI_findstring(&ami->user_paths, path_str, offsetof(XrUserPath, path)); +# else + UNUSED_VARS(ami, path_str); + return NULL; +# endif +} + static XrActionMapItem *rna_XrActionMapItem_new(XrActionMap *am, const char *name, bool replace_existing) @@ -222,6 +318,27 @@ static XrActionMapItem *rna_XrActionMapItem_find(XrActionMap *am, const char *na # endif } +static void rna_XrActionMapItem_user_paths_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + XrActionMapItem *ami = (XrActionMapItem *)ptr->data; + rna_iterator_listbase_begin(iter, &ami->user_paths, NULL); +# else + UNUSED_VARS(iter, ptr); +# endif +} + +static int rna_XrActionMapItem_user_paths_length(PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + XrActionMapItem *ami = (XrActionMapItem *)ptr->data; + return BLI_listbase_count(&ami->user_paths); +# else + UNUSED_VARS(ptr); + return 0; +# endif +} + static void rna_XrActionMapItem_op_name_get(PointerRNA *ptr, char *value) { # ifdef WITH_XR_OPENXR @@ -395,6 +512,27 @@ static void rna_XrActionMapItem_pose_is_controller_aim_set(PointerRNA *ptr, bool # endif } +static void rna_XrActionMapItem_bindings_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + XrActionMapItem *ami = (XrActionMapItem *)ptr->data; + rna_iterator_listbase_begin(iter, &ami->bindings, NULL); +# else + UNUSED_VARS(iter, ptr); +# endif +} + +static int rna_XrActionMapItem_bindings_length(PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + XrActionMapItem *ami = (XrActionMapItem *)ptr->data; + return BLI_listbase_count(&ami->bindings); +# else + UNUSED_VARS(ptr); + return 0; +# endif +} + static void rna_XrActionMapItem_name_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { # ifdef WITH_XR_OPENXR @@ -471,6 +609,27 @@ static XrActionMap *rna_XrActionMap_find(PointerRNA *ptr, const char *name) # endif } +static void rna_XrActionMap_items_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + XrActionMap *actionmap = (XrActionMap *)ptr->data; + rna_iterator_listbase_begin(iter, &actionmap->items, NULL); +# else + UNUSED_VARS(iter, ptr); +# endif +} + +static int rna_XrActionMap_items_length(PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + XrActionMap *actionmap = (XrActionMap *)ptr->data; + return BLI_listbase_count(&actionmap->items); +# else + UNUSED_VARS(ptr); + return 0; +# endif +} + static void rna_XrActionMap_name_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { # ifdef WITH_XR_OPENXR @@ -576,26 +735,8 @@ static bool rna_XrSessionState_action_create(bContext *C, { # ifdef WITH_XR_OPENXR wmWindowManager *wm = CTX_wm_manager(C); - unsigned int count_subaction_paths = 0; - const char *subaction_paths[2]; - - if (ami->user_path0[0]) { - subaction_paths[0] = ami->user_path0; - ++count_subaction_paths; - - if (ami->user_path1[0]) { - subaction_paths[1] = ami->user_path1; - ++count_subaction_paths; - } - } - else { - if (ami->user_path1[0]) { - subaction_paths[0] = ami->user_path1; - ++count_subaction_paths; - } - else { - return false; - } + if (BLI_listbase_is_empty(&ami->user_paths)) { + return false; } const bool is_float_action = (ami->type == XR_FLOAT_INPUT || ami->type == XR_VECTOR2F_INPUT); @@ -621,8 +762,7 @@ static bool rna_XrSessionState_action_create(bContext *C, actionmap->name, ami->name, ami->type, - count_subaction_paths, - subaction_paths, + &ami->user_paths, ot, op_properties, is_button_action ? ami->haptic_name : NULL, @@ -645,30 +785,10 @@ static bool rna_XrSessionState_action_binding_create(bContext *C, { # ifdef WITH_XR_OPENXR wmWindowManager *wm = CTX_wm_manager(C); - unsigned int count_subaction_paths = 0; - const char *subaction_paths[2]; - const char *component_paths[2]; - - if (ami->user_path0[0]) { - subaction_paths[0] = ami->user_path0; - component_paths[0] = amb->component_path0; - ++count_subaction_paths; - - if (ami->user_path1[0]) { - subaction_paths[1] = ami->user_path1; - component_paths[1] = amb->component_path1; - ++count_subaction_paths; - } - } - else { - if (ami->user_path1[0]) { - subaction_paths[0] = ami->user_path1; - component_paths[0] = amb->component_path1; - ++count_subaction_paths; - } - else { - return false; - } + const int count_user_paths = BLI_listbase_count(&ami->user_paths); + const int count_component_paths = BLI_listbase_count(&amb->component_paths); + if (count_user_paths < 1 || (count_user_paths != count_component_paths)) { + return false; } const bool is_float_action = (ami->type == XR_FLOAT_INPUT || ami->type == XR_VECTOR2F_INPUT); @@ -695,9 +815,8 @@ static bool rna_XrSessionState_action_binding_create(bContext *C, actionmap->name, ami->name, amb->profile, - count_subaction_paths, - subaction_paths, - component_paths, + &ami->user_paths, + &amb->component_paths, is_float_action ? float_thresholds : NULL, is_button_action ? axis_flags : NULL, is_pose_action ? poses : NULL); @@ -954,6 +1073,18 @@ static void rna_XrSessionState_actionmaps_begin(CollectionPropertyIterator *iter # endif } +static int rna_XrSessionState_actionmaps_length(PointerRNA *ptr) +{ +# ifdef WITH_XR_OPENXR + wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr); + ListBase *lb = WM_xr_actionmaps_get(xr->runtime); + return BLI_listbase_count(lb); +# else + UNUSED_VARS(ptr); + return 0; +# endif +} + static int rna_XrSessionState_active_actionmap_get(PointerRNA *ptr) { # ifdef WITH_XR_OPENXR @@ -1240,6 +1371,42 @@ static const EnumPropertyItem rna_enum_xr_axis1_flags[] = { /** \name XR Action Map * \{ */ +static void rna_def_xr_component_paths(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "XrComponentPaths"); + srna = RNA_def_struct(brna, "XrComponentPaths", NULL); + RNA_def_struct_sdna(srna, "XrActionMapBinding"); + RNA_def_struct_ui_text(srna, "XR Component Paths", "Collection of OpenXR component paths"); + + func = RNA_def_function(srna, "new", "rna_XrComponentPath_new"); + parm = RNA_def_string( + func, "path", NULL, XR_MAX_COMPONENT_PATH_LENGTH, "Path", "OpenXR component path"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer( + func, "component_path", "XrComponentPath", "Component Path", "Added component path"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_XrComponentPath_remove"); + parm = RNA_def_pointer(func, "component_path", "XrComponentPath", "Component Path", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + func = RNA_def_function(srna, "find", "rna_XrComponentPath_find"); + parm = RNA_def_string( + func, "path", NULL, XR_MAX_COMPONENT_PATH_LENGTH, "Path", "OpenXR component path"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, + "component_path", + "XrComponentPath", + "Component Path", + "The component path with the given path"); + RNA_def_function_return(func, parm); +} + static void rna_def_xr_actionmap_bindings(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; @@ -1289,6 +1456,36 @@ static void rna_def_xr_actionmap_bindings(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); } +static void rna_def_xr_user_paths(BlenderRNA *brna, PropertyRNA *cprop) +{ + StructRNA *srna; + FunctionRNA *func; + PropertyRNA *parm; + + RNA_def_property_srna(cprop, "XrUserPaths"); + srna = RNA_def_struct(brna, "XrUserPaths", NULL); + RNA_def_struct_sdna(srna, "XrActionMapItem"); + RNA_def_struct_ui_text(srna, "XR User Paths", "Collection of OpenXR user paths"); + + func = RNA_def_function(srna, "new", "rna_XrUserPath_new"); + parm = RNA_def_string(func, "path", NULL, XR_MAX_USER_PATH_LENGTH, "Path", "OpenXR user path"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer(func, "user_path", "XrUserPath", "User Path", "Added user path"); + RNA_def_function_return(func, parm); + + func = RNA_def_function(srna, "remove", "rna_XrUserPath_remove"); + parm = RNA_def_pointer(func, "user_path", "XrUserPath", "User Path", ""); + RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR); + RNA_def_parameter_clear_flags(parm, PROP_THICK_WRAP, 0); + + func = RNA_def_function(srna, "find", "rna_XrUserPath_find"); + parm = RNA_def_string(func, "path", NULL, XR_MAX_USER_PATH_LENGTH, "Path", "OpenXR user path"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + parm = RNA_def_pointer( + func, "user_path", "XrUserPath", "User Path", "The user path with the given path"); + RNA_def_function_return(func, parm); +} + static void rna_def_xr_actionmap_items(BlenderRNA *brna, PropertyRNA *cprop) { StructRNA *srna; @@ -1404,6 +1601,15 @@ static void rna_def_xr_actionmap(BlenderRNA *brna) prop = RNA_def_property(srna, "actionmap_items", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "items", NULL); RNA_def_property_struct_type(prop, "XrActionMapItem"); + RNA_def_property_collection_funcs(prop, + "rna_XrActionMap_items_begin", + "rna_iterator_listbase_next", + "rna_iterator_listbase_end", + "rna_iterator_listbase_get", + "rna_XrActionMap_items_length", + NULL, + NULL, + NULL); RNA_def_property_ui_text( prop, "Items", @@ -1414,6 +1620,15 @@ static void rna_def_xr_actionmap(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "selitem"); RNA_def_property_ui_text(prop, "Selected Item", ""); + /* XrUserPath */ + srna = RNA_def_struct(brna, "XrUserPath", NULL); + RNA_def_struct_sdna(srna, "XrUserPath"); + RNA_def_struct_ui_text(srna, "XR User Path", ""); + + prop = RNA_def_property(srna, "path", PROP_STRING, PROP_NONE); + RNA_def_property_string_maxlength(prop, XR_MAX_USER_PATH_LENGTH); + RNA_def_property_ui_text(prop, "Path", "OpenXR user path"); + /* XrActionMapItem */ srna = RNA_def_struct(brna, "XrActionMapItem", NULL); RNA_def_struct_sdna(srna, "XrActionMapItem"); @@ -1429,13 +1644,19 @@ static void rna_def_xr_actionmap(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Type", "Action type"); RNA_def_property_update(prop, 0, "rna_XrActionMapItem_update"); - prop = RNA_def_property(srna, "user_path0", PROP_STRING, PROP_NONE); - RNA_def_property_string_maxlength(prop, 64); - RNA_def_property_ui_text(prop, "User Path 0", "OpenXR user path"); - - prop = RNA_def_property(srna, "user_path1", PROP_STRING, PROP_NONE); - RNA_def_property_string_maxlength(prop, 64); - RNA_def_property_ui_text(prop, "User Path 1", "OpenXR user path"); + prop = RNA_def_property(srna, "user_paths", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "XrUserPath"); + RNA_def_property_collection_funcs(prop, + "rna_XrActionMapItem_user_paths_begin", + "rna_iterator_listbase_next", + "rna_iterator_listbase_end", + "rna_iterator_listbase_get", + "rna_XrActionMapItem_user_paths_length", + NULL, + NULL, + NULL); + RNA_def_property_ui_text(prop, "User Paths", "OpenXR user paths"); + rna_def_xr_user_paths(brna, prop); prop = RNA_def_property(srna, "op", PROP_STRING, PROP_NONE); RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME); @@ -1520,6 +1741,15 @@ static void rna_def_xr_actionmap(BlenderRNA *brna) prop = RNA_def_property(srna, "bindings", PROP_COLLECTION, PROP_NONE); RNA_def_property_struct_type(prop, "XrActionMapBinding"); + RNA_def_property_collection_funcs(prop, + "rna_XrActionMapItem_bindings_begin", + "rna_iterator_listbase_next", + "rna_iterator_listbase_end", + "rna_iterator_listbase_get", + "rna_XrActionMapItem_bindings_length", + NULL, + NULL, + NULL); RNA_def_property_ui_text( prop, "Bindings", "Bindings for the action map item, mapping the action to an XR input"); rna_def_xr_actionmap_bindings(brna, prop); @@ -1528,6 +1758,15 @@ static void rna_def_xr_actionmap(BlenderRNA *brna) RNA_def_property_int_sdna(prop, NULL, "selbinding"); RNA_def_property_ui_text(prop, "Selected Binding", "Currently selected binding"); + /* XrComponentPath */ + srna = RNA_def_struct(brna, "XrComponentPath", NULL); + RNA_def_struct_sdna(srna, "XrComponentPath"); + RNA_def_struct_ui_text(srna, "XR Component Path", ""); + + prop = RNA_def_property(srna, "path", PROP_STRING, PROP_NONE); + RNA_def_property_string_maxlength(prop, XR_MAX_COMPONENT_PATH_LENGTH); + RNA_def_property_ui_text(prop, "Path", "OpenXR component path"); + /* XrActionMapBinding */ srna = RNA_def_struct(brna, "XrActionMapBinding", NULL); RNA_def_struct_sdna(srna, "XrActionMapBinding"); @@ -1542,13 +1781,19 @@ static void rna_def_xr_actionmap(BlenderRNA *brna) RNA_def_property_string_maxlength(prop, 256); RNA_def_property_ui_text(prop, "Profile", "OpenXR interaction profile path"); - prop = RNA_def_property(srna, "component_path0", PROP_STRING, PROP_NONE); - RNA_def_property_string_maxlength(prop, 192); - RNA_def_property_ui_text(prop, "Component Path 0", "OpenXR component path"); - - prop = RNA_def_property(srna, "component_path1", PROP_STRING, PROP_NONE); - RNA_def_property_string_maxlength(prop, 192); - RNA_def_property_ui_text(prop, "Component Path 1", "OpenXR component path"); + prop = RNA_def_property(srna, "component_paths", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "XrComponentPath"); + RNA_def_property_collection_funcs(prop, + "rna_XrActionMapBinding_component_paths_begin", + "rna_iterator_listbase_next", + "rna_iterator_listbase_end", + "rna_iterator_listbase_get", + "rna_XrActionMapBinding_component_paths_length", + NULL, + NULL, + NULL); + RNA_def_property_ui_text(prop, "Component Paths", "OpenXR component paths"); + rna_def_xr_component_paths(brna, prop); prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "float_threshold"); @@ -1812,7 +2057,7 @@ static void rna_def_xr_session_state(BlenderRNA *brna) 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, 64, "Action Set", "Action set name"); + 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_boolean(func, "result", 0, "Result", ""); RNA_def_function_return(func, parm); @@ -1823,19 +2068,19 @@ static void rna_def_xr_session_state(BlenderRNA *brna) 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, 64, "Action Set", "Action set name"); + 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, "grip_action", NULL, - 64, + MAX_NAME, "Grip Action", "Name of the action representing the controller grips"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_string(func, "aim_action", NULL, - 64, + MAX_NAME, "Aim Action", "Name of the action representing the controller aims"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); @@ -1847,11 +2092,12 @@ static void rna_def_xr_session_state(BlenderRNA *brna) 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_name", NULL, 64, "Action Set", "Action set name"); + parm = RNA_def_string(func, "action_set_name", NULL, MAX_NAME, "Action Set", "Action set name"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_string(func, "action_name", NULL, 64, "Action", "Action name"); + parm = RNA_def_string(func, "action_name", NULL, MAX_NAME, "Action", "Action name"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_string(func, "user_path", NULL, 64, "User Path", "OpenXR user path"); + 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_array( func, @@ -1871,15 +2117,15 @@ static void rna_def_xr_session_state(BlenderRNA *brna) 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_name", NULL, 64, "Action Set", "Action set name"); + parm = RNA_def_string(func, "action_set_name", NULL, MAX_NAME, "Action Set", "Action set name"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_string(func, "action_name", NULL, 64, "Action", "Action name"); + parm = RNA_def_string(func, "action_name", NULL, MAX_NAME, "Action", "Action name"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_string( func, "user_path", NULL, - 64, + XR_MAX_USER_PATH_LENGTH, "User Path", "Optional OpenXR user path. If not set, the action will be applied to all paths"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); @@ -1922,15 +2168,15 @@ static void rna_def_xr_session_state(BlenderRNA *brna) 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_name", NULL, 64, "Action Set", "Action set name"); + parm = RNA_def_string(func, "action_set_name", NULL, MAX_NAME, "Action Set", "Action set name"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); - parm = RNA_def_string(func, "action_name", NULL, 64, "Action", "Action name"); + parm = RNA_def_string(func, "action_name", NULL, MAX_NAME, "Action", "Action name"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); parm = RNA_def_string( func, "user_path", NULL, - 64, + XR_MAX_USER_PATH_LENGTH, "User Path", "Optional OpenXR user path. If not set, the action will be stopped for all paths"); RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED); @@ -2068,16 +2314,16 @@ static void rna_def_xr_session_state(BlenderRNA *brna) "Additional scale multiplier to apply to base scale when determining viewer scale"); prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE); + RNA_def_property_struct_type(prop, "XrActionMap"); RNA_def_property_collection_funcs(prop, "rna_XrSessionState_actionmaps_begin", "rna_iterator_listbase_next", "rna_iterator_listbase_end", "rna_iterator_listbase_get", - NULL, + "rna_XrSessionState_actionmaps_length", NULL, NULL, NULL); - RNA_def_property_struct_type(prop, "XrActionMap"); RNA_def_property_ui_text(prop, "XR Action Maps", ""); rna_def_xr_actionmaps(brna, prop); diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index c1281632cc1..49fbf2c27e1 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -1583,8 +1583,7 @@ bool WM_xr_action_create(wmXrData *xr, const char *action_set_name, const char *action_name, eXrActionType type, - unsigned int count_subaction_paths, - const char **subaction_paths, + const ListBase *user_paths, struct wmOperatorType *ot, struct IDProperty *op_properties, const char *haptic_name, @@ -1599,9 +1598,8 @@ bool WM_xr_action_binding_create(wmXrData *xr, const char *action_set_name, const char *action_name, const char *profile_path, - unsigned int count_subaction_paths, - const char **subaction_paths, - const char **component_paths, + const ListBase *user_paths, + const ListBase *component_paths, const float *float_thresholds, const eXrAxisFlag *axis_flags, const struct wmXrPose *poses); diff --git a/source/blender/windowmanager/xr/intern/wm_xr_action.c b/source/blender/windowmanager/xr/intern/wm_xr_action.c index f6003428700..0ce0837d83a 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_action.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_action.c @@ -56,8 +56,7 @@ static wmXrActionSet *action_set_find(wmXrData *xr, const char *action_set_name) static wmXrAction *action_create(const char *action_name, eXrActionType type, - unsigned int count_subaction_paths, - const char **subaction_paths, + const ListBase *user_paths, wmOperatorType *ot, IDProperty *op_properties, const char *haptic_name, @@ -73,15 +72,16 @@ static wmXrAction *action_create(const char *action_name, strcpy(action->name, action_name); action->type = type; - const unsigned int count = count_subaction_paths; + const unsigned int count = (unsigned int)BLI_listbase_count(user_paths); + unsigned int subaction_idx = 0; action->count_subaction_paths = count; action->subaction_paths = MEM_mallocN(sizeof(*action->subaction_paths) * count, "XrAction_SubactionPaths"); - for (unsigned int i = 0; i < count; ++i) { - action->subaction_paths[i] = MEM_mallocN(strlen(subaction_paths[i]) + 1, - "XrAction_SubactionPath"); - strcpy(action->subaction_paths[i], subaction_paths[i]); + LISTBASE_FOREACH_INDEX (XrUserPath *, user_path, user_paths, subaction_idx) { + action->subaction_paths[subaction_idx] = MEM_mallocN(strlen(user_path->path) + 1, + "XrAction_SubactionPath"); + strcpy(action->subaction_paths[subaction_idx], user_path->path); } size_t size; @@ -140,10 +140,9 @@ static void action_destroy(void *val) MEM_SAFE_FREE(action->name); - const unsigned int count = action->count_subaction_paths; char **subaction_paths = action->subaction_paths; if (subaction_paths) { - for (unsigned int i = 0; i < count; ++i) { + for (unsigned int i = 0; i < action->count_subaction_paths; ++i) { MEM_SAFE_FREE(subaction_paths[i]); } MEM_freeN(subaction_paths); @@ -214,8 +213,7 @@ bool WM_xr_action_create(wmXrData *xr, const char *action_set_name, const char *action_name, eXrActionType type, - unsigned int count_subaction_paths, - const char **subaction_paths, + const ListBase *user_paths, wmOperatorType *ot, IDProperty *op_properties, const char *haptic_name, @@ -232,8 +230,7 @@ bool WM_xr_action_create(wmXrData *xr, wmXrAction *action = action_create(action_name, type, - count_subaction_paths, - subaction_paths, + user_paths, ot, op_properties, haptic_name, @@ -244,9 +241,19 @@ bool WM_xr_action_create(wmXrData *xr, action_flag, haptic_flag); + const unsigned int count = (unsigned int)BLI_listbase_count(user_paths); + unsigned int subaction_idx = 0; + + char **subaction_paths = MEM_calloc_arrayN( + count, sizeof(*subaction_paths), "XrAction_SubactionPathPointers"); + + LISTBASE_FOREACH_INDEX (XrUserPath *, user_path, user_paths, subaction_idx) { + subaction_paths[subaction_idx] = (char *)user_path->path; + } + GHOST_XrActionInfo info = { .name = action_name, - .count_subaction_paths = count_subaction_paths, + .count_subaction_paths = count, .subaction_paths = subaction_paths, .states = action->states, .float_thresholds = action->float_thresholds, @@ -273,11 +280,11 @@ bool WM_xr_action_create(wmXrData *xr, break; } - if (!GHOST_XrCreateActions(xr->runtime->context, action_set_name, 1, &info)) { - return false; - } + const bool success = GHOST_XrCreateActions(xr->runtime->context, action_set_name, 1, &info); - return true; + MEM_freeN(subaction_paths); + + return success; } void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char *action_name) @@ -323,19 +330,29 @@ bool WM_xr_action_binding_create(wmXrData *xr, const char *action_set_name, const char *action_name, const char *profile_path, - unsigned int count_subaction_paths, - const char **subaction_paths, - const char **component_paths, + const ListBase *user_paths, + const ListBase *component_paths, const float *float_thresholds, const eXrAxisFlag *axis_flags, const struct wmXrPose *poses) { + const unsigned int count = (unsigned int)BLI_listbase_count(user_paths); + BLI_assert(count == (unsigned int)BLI_listbase_count(component_paths)); + GHOST_XrActionBindingInfo *binding_infos = MEM_calloc_arrayN( - count_subaction_paths, sizeof(*binding_infos), __func__); + count, sizeof(*binding_infos), "XrActionBinding_Infos"); - for (unsigned int i = 0; i < count_subaction_paths; ++i) { + char **subaction_paths = MEM_calloc_arrayN( + count, sizeof(*subaction_paths), "XrActionBinding_SubactionPathPointers"); + + for (unsigned int i = 0; i < count; ++i) { GHOST_XrActionBindingInfo *binding_info = &binding_infos[i]; - binding_info->component_path = component_paths[i]; + const XrUserPath *user_path = BLI_findlink(user_paths, i); + const XrComponentPath *component_path = BLI_findlink(component_paths, i); + + subaction_paths[i] = (char *)user_path->path; + + binding_info->component_path = component_path->path; if (float_thresholds) { binding_info->float_threshold = float_thresholds[i]; } @@ -351,15 +368,18 @@ bool WM_xr_action_binding_create(wmXrData *xr, GHOST_XrActionProfileInfo profile_info = { .action_name = action_name, .profile_path = profile_path, - .count_subaction_paths = count_subaction_paths, + .count_subaction_paths = count, .subaction_paths = subaction_paths, .bindings = binding_infos, }; - bool ret = GHOST_XrCreateActionBindings(xr->runtime->context, action_set_name, 1, &profile_info); + const bool success = GHOST_XrCreateActionBindings( + xr->runtime->context, action_set_name, 1, &profile_info); + MEM_freeN(subaction_paths); MEM_freeN(binding_infos); - return ret; + + return success; } void WM_xr_action_binding_destroy(wmXrData *xr, diff --git a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c index 0c356ab2b2e..267fb0481a8 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c @@ -118,11 +118,17 @@ XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami, return amb_dst; } +static void wm_xr_actionmap_binding_clear(XrActionMapBinding *amb) +{ + BLI_freelistN(&amb->component_paths); +} + bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *amb) { int idx = BLI_findindex(&ami->bindings, amb); if (idx != -1) { + wm_xr_actionmap_binding_clear(amb); BLI_freelinkN(&ami->bindings, amb); if (idx <= ami->selbinding) { @@ -155,12 +161,6 @@ XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const cha * Item in an XR action map, that maps an XR event to an operator, pose, or haptic output. * \{ */ -static void wm_xr_actionmap_item_bindings_clear(XrActionMapItem *ami) -{ - BLI_freelistN(&ami->bindings); - ami->selbinding = 0; -} - static void wm_xr_actionmap_item_properties_set(XrActionMapItem *ami) { WM_operator_properties_alloc(&(ami->op_properties_ptr), &(ami->op_properties), ami->op); @@ -180,6 +180,19 @@ static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami) } } +static void wm_xr_actionmap_item_clear(XrActionMapItem *ami) +{ + LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) { + wm_xr_actionmap_binding_clear(amb); + } + BLI_freelistN(&ami->bindings); + ami->selbinding = 0; + + wm_xr_actionmap_item_properties_free(ami); + + BLI_freelistN(&ami->user_paths); +} + void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami) { switch (ami->type) { @@ -324,8 +337,7 @@ bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami) int idx = BLI_findindex(&actionmap->items, ami); if (idx != -1) { - wm_xr_actionmap_item_bindings_clear(ami); - wm_xr_actionmap_item_properties_free(ami); + wm_xr_actionmap_item_clear(ami); BLI_freelinkN(&actionmap->items, ami); if (idx <= actionmap->selitem) { @@ -480,12 +492,9 @@ XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name) void WM_xr_actionmap_clear(XrActionMap *actionmap) { LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) { - wm_xr_actionmap_item_bindings_clear(ami); - wm_xr_actionmap_item_properties_free(ami); + wm_xr_actionmap_item_clear(ami); } - BLI_freelistN(&actionmap->items); - actionmap->selitem = 0; } @@ -494,9 +503,7 @@ 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 = 0; } diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h index 0e7c4d18753..9480104150a 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h +++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h @@ -114,12 +114,8 @@ typedef struct 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]; + /** OpenXR user path identifier. */ + char subaction_path[64]; /* XR_MAX_USER_PATH_LENGTH */ /** Pose (in world space) that represents the user's hand when holding the controller. */ GHOST_XrPose grip_pose; diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index 59b4eb00363..dfeaeae196c 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -1188,8 +1188,9 @@ void wm_xr_session_actions_update(wmWindowManager *wm) &state->viewer_pose, settings->base_scale * state->nav_scale, state->viewer_viewmat); } - int ret = GHOST_XrSyncActions(xr_context, active_action_set ? active_action_set->name : NULL); - if (!ret) { + const bool synced = GHOST_XrSyncActions(xr_context, + active_action_set ? active_action_set->name : NULL); + if (!synced) { return; } -- cgit v1.2.3