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--build_files/config/pipeline_config.yaml2
-rw-r--r--intern/ghost/GHOST_Types.h4
-rw-r--r--intern/ghost/intern/GHOST_XrContext.cpp13
-rw-r--r--intern/ghost/intern/GHOST_XrContext.h4
-rw-r--r--source/blender/blenloader/intern/readfile.c4
-rw-r--r--source/blender/editors/include/ED_transform.h16
-rw-r--r--source/blender/editors/include/ED_view3d.h4
-rw-r--r--source/blender/editors/include/UI_interface.h1
-rw-r--r--source/blender/editors/interface/CMakeLists.txt3
-rw-r--r--source/blender/editors/interface/interface_templates.c38
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c29
-rw-r--r--source/blender/editors/transform/transform_convert.c4
-rw-r--r--source/blender/editors/transform/transform_convert.h4
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c2
-rw-r--r--source/blender/editors/transform/transform_convert_object.c14
-rw-r--r--source/blender/editors/transform/transform_convert_sequencer_image.c2
-rw-r--r--source/blender/makesdna/DNA_xr_types.h45
-rw-r--r--source/blender/makesrna/intern/rna_ui_api.c5
-rw-r--r--source/blender/makesrna/intern/rna_xr.c672
-rw-r--r--source/blender/windowmanager/CMakeLists.txt3
-rw-r--r--source/blender/windowmanager/WM_api.h42
-rw-r--r--source/blender/windowmanager/intern/wm.c61
-rw-r--r--source/blender/windowmanager/intern/wm_files.c6
-rw-r--r--source/blender/windowmanager/intern/wm_window.c2
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr.c15
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_action.c82
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_actionmap.c136
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_draw.c31
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h49
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_mocap.c272
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_operators.c944
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_session.c288
-rw-r--r--source/blender/windowmanager/xr/wm_xr.h3
33 files changed, 2428 insertions, 372 deletions
diff --git a/build_files/config/pipeline_config.yaml b/build_files/config/pipeline_config.yaml
index 8222f2ff0b9..6bfb0125e95 100644
--- a/build_files/config/pipeline_config.yaml
+++ b/build_files/config/pipeline_config.yaml
@@ -5,7 +5,7 @@
update-code:
git:
submodules:
- - branch: master
+ - branch: xr-dev
commit_id: HEAD
path: release/scripts/addons
- branch: master
diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h
index 78f2b24ea78..01a0a7652aa 100644
--- a/intern/ghost/GHOST_Types.h
+++ b/intern/ghost/GHOST_Types.h
@@ -661,6 +661,10 @@ enum {
* (use DirectX fallback instead). */
GHOST_kXrContextGpuNVIDIA = (1 << 2),
# endif
+ /* Needed to selectively enable the #XR_HTCX_vive_tracker_interaction extension, as it causes
+ incorrect controller poses with SteamVR (1.21). Although not ideal, either trackers or
+ controllers (but not both) can be used during a given session. */
+ GHOST_kXrContextEnableViveTrackerExtension = (1 << 3),
};
typedef struct {
diff --git a/intern/ghost/intern/GHOST_XrContext.cpp b/intern/ghost/intern/GHOST_XrContext.cpp
index 2ac3d9ec2a5..4a7f833a25b 100644
--- a/intern/ghost/intern/GHOST_XrContext.cpp
+++ b/intern/ghost/intern/GHOST_XrContext.cpp
@@ -82,7 +82,7 @@ void GHOST_XrContext::initialize(const GHOST_XrContextCreateInfo *create_info)
determineGraphicsBindingTypesToEnable(create_info);
assert(m_oxr->instance == XR_NULL_HANDLE);
- createOpenXRInstance(graphics_binding_types);
+ createOpenXRInstance(graphics_binding_types, create_info);
storeInstanceProperties();
/* Multiple bindings may be enabled. Now that we know the runtime in use, settle for one. */
@@ -95,7 +95,8 @@ void GHOST_XrContext::initialize(const GHOST_XrContextCreateInfo *create_info)
}
void GHOST_XrContext::createOpenXRInstance(
- const std::vector<GHOST_TXrGraphicsBinding> &graphics_binding_types)
+ const std::vector<GHOST_TXrGraphicsBinding> &graphics_binding_types,
+ const GHOST_XrContextCreateInfo *ctx_create_info)
{
XrInstanceCreateInfo create_info = {XR_TYPE_INSTANCE_CREATE_INFO};
@@ -104,7 +105,7 @@ void GHOST_XrContext::createOpenXRInstance(
create_info.applicationInfo.apiVersion = XR_CURRENT_API_VERSION;
getAPILayersToEnable(m_enabled_layers);
- getExtensionsToEnable(graphics_binding_types, m_enabled_extensions);
+ getExtensionsToEnable(graphics_binding_types, ctx_create_info, m_enabled_extensions);
create_info.enabledApiLayerCount = m_enabled_layers.size();
create_info.enabledApiLayerNames = m_enabled_layers.data();
create_info.enabledExtensionCount = m_enabled_extensions.size();
@@ -400,6 +401,7 @@ static const char *openxr_ext_name_from_wm_gpu_binding(GHOST_TXrGraphicsBinding
*/
void GHOST_XrContext::getExtensionsToEnable(
const std::vector<GHOST_TXrGraphicsBinding> &graphics_binding_types,
+ const GHOST_XrContextCreateInfo *create_info,
std::vector<const char *> &r_ext_names)
{
std::vector<std::string_view> try_ext;
@@ -415,6 +417,11 @@ void GHOST_XrContext::getExtensionsToEnable(
#ifdef XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME
try_ext.push_back(XR_HTC_VIVE_FOCUS3_CONTROLLER_INTERACTION_EXTENSION_NAME);
#endif
+ if ((create_info->context_flag & GHOST_kXrContextEnableViveTrackerExtension) != 0) {
+#ifdef XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME
+ try_ext.push_back(XR_HTCX_VIVE_TRACKER_INTERACTION_EXTENSION_NAME);
+#endif
+ }
try_ext.push_back(XR_HUAWEI_CONTROLLER_INTERACTION_EXTENSION_NAME);
/* Controller model extension. */
diff --git a/intern/ghost/intern/GHOST_XrContext.h b/intern/ghost/intern/GHOST_XrContext.h
index 6eac4284e43..435454397cf 100644
--- a/intern/ghost/intern/GHOST_XrContext.h
+++ b/intern/ghost/intern/GHOST_XrContext.h
@@ -108,7 +108,8 @@ class GHOST_XrContext : public GHOST_IXrContext {
bool m_debug = false;
bool m_debug_time = false;
- void createOpenXRInstance(const std::vector<GHOST_TXrGraphicsBinding> &graphics_binding_types);
+ void createOpenXRInstance(const std::vector<GHOST_TXrGraphicsBinding> &graphics_binding_types,
+ const GHOST_XrContextCreateInfo *create_info);
void storeInstanceProperties();
void initDebugMessenger();
@@ -122,6 +123,7 @@ class GHOST_XrContext : public GHOST_IXrContext {
void initExtensionsEx(std::vector<XrExtensionProperties> &extensions, const char *layer_name);
void getAPILayersToEnable(std::vector<const char *> &r_ext_names);
void getExtensionsToEnable(const std::vector<GHOST_TXrGraphicsBinding> &graphics_binding_types,
+ const GHOST_XrContextCreateInfo *create_info,
std::vector<const char *> &r_ext_names);
std::vector<GHOST_TXrGraphicsBinding> determineGraphicsBindingTypesToEnable(
const GHOST_XrContextCreateInfo *create_info);
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 973965ada50..a34ba753912 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -2441,6 +2441,10 @@ static void lib_link_wm_xr_data_restore(struct IDNameLib_Map *id_map, wmXrData *
{
xr_data->session_settings.base_pose_object = restore_pointer_by_name(
id_map, (ID *)xr_data->session_settings.base_pose_object, USER_REAL);
+
+ LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &xr_data->session_settings.mocap_objects) {
+ mocap_ob->ob = restore_pointer_by_name(id_map, (ID *)mocap_ob->ob, USER_REAL);
+ }
}
static void lib_link_window_scene_data_restore(wmWindow *win, Scene *scene, ViewLayer *view_layer)
diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h
index 82cc518f029..1cebdfafd74 100644
--- a/source/blender/editors/include/ED_transform.h
+++ b/source/blender/editors/include/ED_transform.h
@@ -13,10 +13,13 @@ extern "C" {
/* ******************* Registration Function ********************** */
+struct ID;
struct Object;
struct bContext;
+struct ViewLayer;
struct wmKeyConfig;
struct wmOperatorType;
+struct wmTimer;
void ED_keymap_transform(struct wmKeyConfig *keyconf);
void transform_operatortypes(void);
@@ -202,6 +205,19 @@ int ED_transform_calc_gizmo_stats(const struct bContext *C,
const struct TransformCalcParams *params,
struct TransformBounds *tbounds);
+/* transform_convert.c */
+void ED_transform_animrecord_check_state(struct Scene *scene,
+ struct wmTimer *animtimer,
+ struct ID *id);
+
+/* transform_convert_object.c */
+void ED_transform_autokeyframe_object(struct bContext *C,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ struct Object *ob,
+ int tmode);
+bool ED_transform_motionpath_need_update_object(struct Scene *scene, struct Object *ob);
+
/**
* Iterates over all the strips and finds the closest snapping candidate of either \a frame_1 or \a
* frame_2. The closest snapping candidate will be the closest start or end frame of an existing
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 0298983ed26..ddd0cb252cb 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -974,6 +974,10 @@ void ED_view3d_viewcontext_init(struct bContext *C,
*/
void ED_view3d_viewcontext_init_object(struct ViewContext *vc, struct Object *obact);
/**
+ * Deselect all except b.
+ */
+bool ED_view3d_object_deselect_all_except(struct ViewLayer *view_layer, struct Base *b);
+/**
* Use this call when executing an operator,
* event system doesn't set for each event the OpenGL drawing context.
*/
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index b2ec2102ddd..984d3409554 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2417,6 +2417,7 @@ void uiTemplateEditModeSelection(uiLayout *layout, struct bContext *C);
void uiTemplateReportsBanner(uiLayout *layout, struct bContext *C);
void uiTemplateInputStatus(uiLayout *layout, struct bContext *C);
void uiTemplateKeymapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
+void uiTemplateXrActionmapItemProperties(uiLayout *layout, struct PointerRNA *ptr);
bool uiTemplateEventFromKeymapItem(struct uiLayout *layout,
const char *text,
diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt
index 2a1852bd6e7..a140ee27d3c 100644
--- a/source/blender/editors/interface/CMakeLists.txt
+++ b/source/blender/editors/interface/CMakeLists.txt
@@ -106,6 +106,9 @@ if(WIN32 OR APPLE)
endif()
endif()
+if(WITH_XR_OPENXR)
+ add_definitions(-DWITH_XR_OPENXR)
+endif()
blender_add_lib(bf_editor_interface "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 05ae5299e58..4b3937dabce 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -6367,6 +6367,44 @@ void uiTemplateKeymapItemProperties(uiLayout *layout, PointerRNA *ptr)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name XR Actionmap Template
+ * \{ */
+
+#ifdef WITH_XR_OPENXR
+static void xr_actionmap_item_modified(bContext *UNUSED(C),
+ void *UNUSED(ami_p),
+ void *UNUSED(unused))
+{
+}
+#endif
+
+void uiTemplateXrActionmapItemProperties(uiLayout *layout, PointerRNA *ptr)
+{
+#ifdef WITH_XR_OPENXR
+ PointerRNA propptr = RNA_pointer_get(ptr, "op_properties");
+
+ if (propptr.data) {
+ uiBut *but = uiLayoutGetBlock(layout)->buttons.last;
+
+ WM_operator_properties_sanitize(&propptr, false);
+ /* Use same template as keymap item properties. */
+ template_keymap_item_properties(layout, NULL, &propptr);
+
+ for (; but; but = but->next) {
+ if (but->rnaprop) {
+ UI_but_func_set(but, xr_actionmap_item_modified, ptr->data, NULL);
+ UI_but_flag_enable(but, UI_BUT_UPDATE_DELAY);
+ }
+ }
+ }
+#else
+ UNUSED_VARS(layout, ptr);
+#endif
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Event Icon Template
* \{ */
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index 8eff9ee472f..01f94bcab55 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -134,18 +134,12 @@ void ED_view3d_viewcontext_init_object(ViewContext *vc, Object *obact)
}
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Internal Object Utilities
- * \{ */
-
-static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
+bool ED_view3d_object_deselect_all_except(ViewLayer *view_layer, Base *b)
{
bool changed = false;
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->flag & BASE_SELECTED) {
- if (BASE_SELECTABLE(v3d, base)) {
+ if (b != base) {
ED_object_base_select(base, BA_DESELECT);
changed = true;
}
@@ -154,13 +148,18 @@ static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
return changed;
}
-/* deselect all except b */
-static bool object_deselect_all_except(ViewLayer *view_layer, Base *b)
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Internal Object Utilities
+ * \{ */
+
+static bool object_deselect_all_visible(ViewLayer *view_layer, View3D *v3d)
{
bool changed = false;
LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) {
if (base->flag & BASE_SELECTED) {
- if (b != base) {
+ if (BASE_SELECTABLE(v3d, base)) {
ED_object_base_select(base, BA_DESELECT);
changed = true;
}
@@ -1494,7 +1493,7 @@ static int object_select_menu_exec(bContext *C, wmOperator *op)
}
}
else {
- object_deselect_all_except(view_layer, basact);
+ ED_view3d_object_deselect_all_except(view_layer, basact);
ED_object_base_select(basact, BA_SELECT);
changed = true;
}
@@ -2705,7 +2704,7 @@ static bool ed_object_select_pick(bContext *C,
else if (found || params->deselect_all) {
/* Deselect everything. */
/* `basact` may be NULL. */
- if (object_deselect_all_except(view_layer, basact)) {
+ if (ED_view3d_object_deselect_all_except(view_layer, basact)) {
changed_object = true;
}
}
@@ -2717,7 +2716,7 @@ static bool ed_object_select_pick(bContext *C,
if (vc.obedit) {
/* Only do the select (use for setting vertex parents & hooks).
* In edit-mode do not activate. */
- object_deselect_all_except(view_layer, basact);
+ ED_view3d_object_deselect_all_except(view_layer, basact);
ED_object_base_select(basact, BA_SELECT);
changed_object = true;
@@ -2748,7 +2747,7 @@ static bool ed_object_select_pick(bContext *C,
break;
}
case SEL_OP_SET: {
- object_deselect_all_except(view_layer, basact);
+ ED_view3d_object_deselect_all_except(view_layer, basact);
ED_object_base_select(basact, BA_SELECT);
break;
}
diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c
index d9b971c5478..267a519ebee 100644
--- a/source/blender/editors/transform/transform_convert.c
+++ b/source/blender/editors/transform/transform_convert.c
@@ -1607,10 +1607,8 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc)
}
}
-void animrecord_check_state(TransInfo *t, struct ID *id)
+void ED_transform_animrecord_check_state(Scene *scene, wmTimer *animtimer, struct ID *id)
{
- Scene *scene = t->scene;
- wmTimer *animtimer = t->animtimer;
ScreenAnimData *sad = (animtimer) ? animtimer->customdata : NULL;
/* sanity checks */
diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h
index 037fbe26c77..3aeea049150 100644
--- a/source/blender/editors/transform/transform_convert.h
+++ b/source/blender/editors/transform/transform_convert.h
@@ -92,10 +92,6 @@ char transform_convert_frame_side_dir_get(TransInfo *t, float cframe);
*/
bool FrameOnMouseSide(char side, float frame, float cframe);
void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
-/**
- * For the realtime animation recording feature, handle overlapping data.
- */
-void animrecord_check_state(TransInfo *t, struct ID *id);
/* transform_convert_action.c */
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index e1b25acb21e..485425c644a 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -1471,7 +1471,7 @@ void recalcData_pose(TransInfo *t)
/* XXX: this currently doesn't work, since flags aren't set yet! */
int targetless_ik = (t->flag & T_AUTOIK);
- animrecord_check_state(t, &ob->id);
+ ED_transform_animrecord_check_state(t->scene, t->animtimer, &ob->id);
autokeyframe_pose(t->context, t->scene, ob, t->mode, targetless_ik);
}
diff --git a/source/blender/editors/transform/transform_convert_object.c b/source/blender/editors/transform/transform_convert_object.c
index 5879a65eb4b..02549390c6a 100644
--- a/source/blender/editors/transform/transform_convert_object.c
+++ b/source/blender/editors/transform/transform_convert_object.c
@@ -718,7 +718,7 @@ void createTransObject(bContext *C, TransInfo *t)
* \note Context may not always be available,
* so must check before using it as it's a luxury for a few cases.
*/
-static void autokeyframe_object(
+void ED_transform_autokeyframe_object(
bContext *C, Scene *scene, ViewLayer *view_layer, Object *ob, int tmode)
{
Main *bmain = CTX_data_main(C);
@@ -840,7 +840,7 @@ static void autokeyframe_object(
/* Return if we need to update motion paths, only if they already exist,
* and we will insert a keyframe at the end of transform. */
-static bool motionpath_need_update_object(Scene *scene, Object *ob)
+bool ED_transform_motionpath_need_update_object(Scene *scene, Object *ob)
{
/* XXX: there's potential here for problems with unkeyed rotations/scale,
* but for now (until proper data-locality for baking operations),
@@ -884,11 +884,11 @@ void recalcData_objects(TransInfo *t)
/* TODO: autokeyframe calls need some setting to specify to add samples
* (FPoints) instead of keyframes? */
if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
- animrecord_check_state(t, &ob->id);
- autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
+ ED_transform_animrecord_check_state(t->scene, t->animtimer, &ob->id);
+ ED_transform_autokeyframe_object(t->context, t->scene, t->view_layer, ob, t->mode);
}
- motionpath_update |= motionpath_need_update_object(t->scene, ob);
+ motionpath_update |= ED_transform_motionpath_need_update_object(t->scene, ob);
/* sets recalc flags fully, instead of flushing existing ones
* otherwise proxies don't function correctly
@@ -961,10 +961,10 @@ void special_aftertrans_update__object(bContext *C, TransInfo *t)
/* Set auto-key if necessary. */
if (!canceled) {
- autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
+ ED_transform_autokeyframe_object(C, t->scene, t->view_layer, ob, t->mode);
}
- motionpath_update |= motionpath_need_update_object(t->scene, ob);
+ motionpath_update |= ED_transform_motionpath_need_update_object(t->scene, ob);
/* Restore rigid body transform. */
if (ob->rigidbody_object && canceled) {
diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c
index 76c6632039a..741b1e35838 100644
--- a/source/blender/editors/transform/transform_convert_sequencer_image.c
+++ b/source/blender/editors/transform/transform_convert_sequencer_image.c
@@ -238,7 +238,7 @@ void recalcData_sequencer_image(TransInfo *t)
}
if ((t->animtimer) && IS_AUTOKEY_ON(t->scene)) {
- animrecord_check_state(t, &t->scene->id);
+ ED_transform_animrecord_check_state(t->scene, t->animtimer, &t->scene->id);
autokeyframe_sequencer_image(t->context, t->scene, transform, t->mode);
}
diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h
index 44419c9763f..fa590c69728 100644
--- a/source/blender/makesdna/DNA_xr_types.h
+++ b/source/blender/makesdna/DNA_xr_types.h
@@ -40,11 +40,22 @@ typedef struct XrSessionSettings {
/** Object type settings to apply to VR view (unlike shading, not shared with window 3D-View). */
int object_type_exclude_viewport;
int object_type_exclude_select;
+
+ ListBase actionmaps; /* XrActionMap */
+ short act_actionmap;
+ short sel_actionmap;
+ char _pad3[2];
+
+ /** Objects to bind to headset/controller poses. */
+ short sel_mocap_object;
+ ListBase mocap_objects; /* #XrMotionCaptureObject */
} XrSessionSettings;
typedef enum eXrSessionFlag {
XR_SESSION_USE_POSITION_TRACKING = (1 << 0),
XR_SESSION_USE_ABSOLUTE_TRACKING = (1 << 1),
+ XR_SESSION_ENABLE_VIVE_TRACKER_EXTENSION =
+ (1 << 2), /* See #GHOST_kXrContextEnableViveTrackerExtension. */
} eXrSessionFlag;
typedef enum eXRSessionBasePoseType {
@@ -108,8 +119,15 @@ 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 {
+ XR_MOCAP_OBJECT_ENABLE = (1 << 0),
+ XR_MOCAP_OBJECT_AUTOKEY = (1 << 1),
+} eXrMotionCaptureFlag;
+
/**
* 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
@@ -141,7 +159,8 @@ typedef struct XrActionMapBinding {
/** Input threshold/region. */
float float_threshold;
short axis_flag; /* eXrAxisFlag */
- char _pad[2];
+
+ short sel_component_path;
/** Pose action properties. */
float pose_location[3];
@@ -187,8 +206,8 @@ typedef struct XrActionMapItem {
float haptic_frequency;
float haptic_amplitude;
- short selbinding;
- char _pad3[2];
+ short sel_user_path;
+ short sel_binding;
ListBase bindings; /* XrActionMapBinding */
} XrActionMapItem;
@@ -201,12 +220,30 @@ typedef struct XrActionMap {
char name[64]; /* MAX_NAME */
ListBase items; /* XrActionMapItem */
- short selitem;
+ short sel_item;
char _pad[6];
} XrActionMap;
/* -------------------------------------------------------------------- */
+typedef struct XrMotionCaptureObject {
+ struct XrMotionCaptureObject *next, *prev;
+
+ /** Object to bind to a VR device. Used as struct identifier. */
+ Object *ob;
+ /** OpenXR user path, identifies the target headset/controller. */
+ char user_path[64]; /* XR_MAX_USER_PATH_LENGTH */
+
+ /** Location/rotation offsets. */
+ float location_offset[3];
+ float rotation_offset[3];
+
+ short flag; /* eXrMotionCaptureFlag */
+ char _pad[6];
+} XrMotionCaptureObject;
+
+/* -------------------------------------------------------------------- */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c
index 1b416e4b6e5..e05e4a03f40 100644
--- a/source/blender/makesrna/intern/rna_ui_api.c
+++ b/source/blender/makesrna/intern/rna_ui_api.c
@@ -1793,6 +1793,11 @@ void RNA_api_ui_layout(StructRNA *srna)
parm = RNA_def_pointer(func, "item", "KeyMapItem", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ func = RNA_def_function(
+ srna, "template_xr_actionmap_item_properties", "uiTemplateXrActionmapItemProperties");
+ parm = RNA_def_pointer(func, "item", "XrActionMapItem", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+
func = RNA_def_function(srna, "template_component_menu", "uiTemplateComponentMenu");
RNA_def_function_ui_description(func, "Item. Display expanded property in a popup menu");
parm = RNA_def_pointer(func, "data", "AnyType", "", "Data from which to take property");
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index dcfa1bbca51..f01bfbe4fee 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -66,6 +66,12 @@ static void rna_XrComponentPath_remove(XrActionMapBinding *amb, PointerRNA *comp
int idx = BLI_findindex(&amb->component_paths, component_path);
if (idx != -1) {
BLI_freelinkN(&amb->component_paths, component_path);
+
+ if (idx <= amb->sel_component_path) {
+ if (--amb->sel_component_path < 0) {
+ amb->sel_component_path = 0;
+ }
+ }
}
RNA_POINTER_INVALIDATE(component_path_ptr);
# else
@@ -216,12 +222,11 @@ static void rna_XrActionMapBinding_name_update(Main *bmain, Scene *UNUSED(scene)
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = bmain->wm.first;
- if (wm && wm->xr.runtime) {
- ListBase *actionmaps = WM_xr_actionmaps_get(wm->xr.runtime);
- short idx = WM_xr_actionmap_selected_index_get(wm->xr.runtime);
- XrActionMap *actionmap = BLI_findlink(actionmaps, idx);
+ if (wm) {
+ XrActionMap *actionmap = BLI_findlink(&wm->xr.session_settings.actionmaps,
+ wm->xr.session_settings.sel_actionmap);
if (actionmap) {
- XrActionMapItem *ami = BLI_findlink(&actionmap->items, actionmap->selitem);
+ XrActionMapItem *ami = BLI_findlink(&actionmap->items, actionmap->sel_item);
if (ami) {
XrActionMapBinding *amb = ptr->data;
WM_xr_actionmap_binding_ensure_unique(ami, amb);
@@ -253,6 +258,12 @@ static void rna_XrUserPath_remove(XrActionMapItem *ami, PointerRNA *user_path_pt
int idx = BLI_findindex(&ami->user_paths, user_path);
if (idx != -1) {
BLI_freelinkN(&ami->user_paths, user_path);
+
+ if (idx <= ami->sel_user_path) {
+ if (--ami->sel_user_path < 0) {
+ ami->sel_user_path = 0;
+ }
+ }
}
RNA_POINTER_INVALIDATE(user_path_ptr);
# else
@@ -512,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
@@ -537,10 +571,9 @@ static void rna_XrActionMapItem_name_update(Main *bmain, Scene *UNUSED(scene), P
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = bmain->wm.first;
- if (wm && wm->xr.runtime) {
- ListBase *actionmaps = WM_xr_actionmaps_get(wm->xr.runtime);
- short idx = WM_xr_actionmap_selected_index_get(wm->xr.runtime);
- XrActionMap *actionmap = BLI_findlink(actionmaps, idx);
+ if (wm) {
+ XrActionMap *actionmap = BLI_findlink(&wm->xr.session_settings.actionmaps,
+ wm->xr.session_settings.sel_actionmap);
if (actionmap) {
XrActionMapItem *ami = ptr->data;
WM_xr_actionmap_item_ensure_unique(actionmap, ami);
@@ -561,50 +594,51 @@ static void rna_XrActionMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene)
# endif
}
-static XrActionMap *rna_XrActionMap_new(PointerRNA *ptr, const char *name, bool replace_existing)
+static XrActionMap *rna_XrActionMap_new(XrSessionSettings *settings,
+ const char *name,
+ bool replace_existing)
{
# ifdef WITH_XR_OPENXR
- wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
- return WM_xr_actionmap_new(xr->runtime, name, replace_existing);
+ return WM_xr_actionmap_new(settings, name, replace_existing);
# else
- UNUSED_VARS(ptr, name, replace_existing);
+ UNUSED_VARS(settings, name, replace_existing);
return NULL;
# endif
}
-static XrActionMap *rna_XrActionMap_new_from_actionmap(PointerRNA *ptr, XrActionMap *am_src)
+static XrActionMap *rna_XrActionMap_new_from_actionmap(XrSessionSettings *settings,
+ XrActionMap *am_src)
{
# ifdef WITH_XR_OPENXR
- wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
- return WM_xr_actionmap_add_copy(xr->runtime, am_src);
+ return WM_xr_actionmap_add_copy(settings, am_src);
# else
- UNUSED_VARS(ptr, am_src);
+ UNUSED_VARS(settings, am_src);
return NULL;
# endif
}
-static void rna_XrActionMap_remove(ReportList *reports, PointerRNA *ptr, PointerRNA *actionmap_ptr)
+static void rna_XrActionMap_remove(XrSessionSettings *settings,
+ ReportList *reports,
+ PointerRNA *actionmap_ptr)
{
# ifdef WITH_XR_OPENXR
- wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
XrActionMap *actionmap = actionmap_ptr->data;
- if (WM_xr_actionmap_remove(xr->runtime, actionmap) == false) {
+ if (WM_xr_actionmap_remove(settings, actionmap) == false) {
BKE_reportf(reports, RPT_ERROR, "ActionMap '%s' cannot be removed", actionmap->name);
return;
}
RNA_POINTER_INVALIDATE(actionmap_ptr);
# else
- UNUSED_VARS(ptr, reports, actionmap_ptr);
+ UNUSED_VARS(settings, reports, actionmap_ptr);
# endif
}
-static XrActionMap *rna_XrActionMap_find(PointerRNA *ptr, const char *name)
+static XrActionMap *rna_XrActionMap_find(XrSessionSettings *settings, const char *name)
{
# ifdef WITH_XR_OPENXR
- wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
- return WM_xr_actionmap_find(xr->runtime, name);
+ return WM_xr_actionmap_find(settings, name);
# else
- UNUSED_VARS(ptr, name);
+ UNUSED_VARS(settings, name);
return NULL;
# endif
}
@@ -634,9 +668,9 @@ static void rna_XrActionMap_name_update(Main *bmain, Scene *UNUSED(scene), Point
{
# ifdef WITH_XR_OPENXR
wmWindowManager *wm = bmain->wm.first;
- if (wm && wm->xr.runtime) {
+ if (wm) {
XrActionMap *actionmap = ptr->data;
- WM_xr_actionmap_ensure_unique(wm->xr.runtime, actionmap);
+ WM_xr_actionmap_ensure_unique(&wm->xr.session_settings, actionmap);
}
# else
UNUSED_VARS(bmain, ptr);
@@ -646,6 +680,126 @@ static void rna_XrActionMap_name_update(Main *bmain, Scene *UNUSED(scene), Point
/** \} */
/* -------------------------------------------------------------------- */
+/** \name XR Motion Capture
+ * \{ */
+
+static XrMotionCaptureObject *rna_XrMotionCaptureObject_new(XrSessionSettings *settings,
+ PointerRNA *ob_ptr)
+{
+# ifdef WITH_XR_OPENXR
+ Object *ob = ob_ptr->data;
+ return WM_xr_mocap_object_new(settings, ob);
+# else
+ UNUSED_VARS(settings, ob_ptr);
+ return NULL;
+# endif
+}
+
+static void rna_XrMotionCaptureObject_remove(XrSessionSettings *settings, PointerRNA *mocap_ob_ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrMotionCaptureObject *mocap_ob = mocap_ob_ptr->data;
+ WM_xr_mocap_object_remove(settings, mocap_ob);
+ RNA_POINTER_INVALIDATE(mocap_ob_ptr);
+# else
+ UNUSED_VARS(settings, mocap_ob_ptr);
+# endif
+}
+
+static XrMotionCaptureObject *rna_XrMotionCaptureObject_find(XrSessionSettings *settings,
+ PointerRNA *ob_ptr)
+{
+# ifdef WITH_XR_OPENXR
+ Object *ob = ob_ptr->data;
+ return WM_xr_mocap_object_find(settings, ob);
+# else
+ UNUSED_VARS(settings, ob_ptr);
+ return NULL;
+# endif
+}
+
+static void rna_XrMotionCaptureObject_object_update(Main *bmain,
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm) {
+ XrMotionCaptureObject *mocap_ob = ptr->data;
+ WM_xr_mocap_object_ensure_unique(&wm->xr.session_settings, mocap_ob);
+ }
+# else
+ UNUSED_VARS(bmain, ptr);
+# endif
+}
+
+static bool rna_XrMotionCaptureObject_enable_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const XrMotionCaptureObject *mocap_ob = ptr->data;
+ return (mocap_ob->flag & XR_MOCAP_OBJECT_ENABLE) != 0;
+# else
+ UNUSED_VARS(ptr);
+ return false;
+# endif
+}
+
+static void rna_XrMotionCaptureObject_enable_set(PointerRNA *ptr, bool value)
+{
+# ifdef WITH_XR_OPENXR
+ XrMotionCaptureObject *mocap_ob = ptr->data;
+ SET_FLAG_FROM_TEST(mocap_ob->flag, value, XR_MOCAP_OBJECT_ENABLE);
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+static void rna_XrMotionCaptureObject_enable_update(Main *bmain,
+ Scene *UNUSED(scene),
+ PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm) {
+ XrMotionCaptureObject *mocap_ob = ptr->data;
+ if ((mocap_ob->flag & XR_MOCAP_OBJECT_ENABLE) != 0) {
+ /* Store object's original pose. */
+ WM_xr_session_state_mocap_pose_set(&wm->xr, mocap_ob);
+ }
+ else {
+ /* Restore object's original pose. */
+ WM_xr_session_state_mocap_pose_get(&wm->xr, mocap_ob);
+ }
+ }
+# else
+ UNUSED_VARS(bmain, ptr);
+# endif
+}
+
+static bool rna_XrMotionCaptureObject_autokey_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const XrMotionCaptureObject *mocap_ob = ptr->data;
+ return (mocap_ob->flag & XR_MOCAP_OBJECT_AUTOKEY) != 0;
+# else
+ UNUSED_VARS(ptr);
+ return false;
+# endif
+}
+
+static void rna_XrMotionCaptureObject_autokey_set(PointerRNA *ptr, bool value)
+{
+# ifdef WITH_XR_OPENXR
+ XrMotionCaptureObject *mocap_ob = ptr->data;
+ SET_FLAG_FROM_TEST(mocap_ob->flag, value, XR_MOCAP_OBJECT_AUTOKEY);
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name XR Session Settings
* \{ */
@@ -691,6 +845,27 @@ static void rna_XrSessionSettings_use_absolute_tracking_set(PointerRNA *ptr, boo
# endif
}
+static bool rna_XrSessionSettings_enable_vive_tracker_extension_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ return (xr->session_settings.flag & XR_SESSION_ENABLE_VIVE_TRACKER_EXTENSION) != 0;
+# else
+ UNUSED_VARS(ptr);
+ return false;
+# endif
+}
+
+static void rna_XrSessionSettings_enable_vive_tracker_extension_set(PointerRNA *ptr, bool value)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ SET_FLAG_FROM_TEST(xr->session_settings.flag, value, XR_SESSION_ENABLE_VIVE_TRACKER_EXTENSION);
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
static int rna_XrSessionSettings_icon_from_show_object_viewport_get(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
@@ -710,6 +885,50 @@ static int rna_XrSessionSettings_icon_from_show_object_viewport_get(PointerRNA *
# endif
}
+static void rna_XrSessionSettings_actionmaps_begin(CollectionPropertyIterator *iter,
+ PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ rna_iterator_listbase_begin(iter, &xr->session_settings.actionmaps, NULL);
+# else
+ UNUSED_VARS(iter, ptr);
+# endif
+}
+
+static int rna_XrSessionSettings_actionmaps_length(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ return BLI_listbase_count(&xr->session_settings.actionmaps);
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
+static void rna_XrSessionSettings_mocap_objects_begin(CollectionPropertyIterator *iter,
+ PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ rna_iterator_listbase_begin(iter, &xr->session_settings.mocap_objects, NULL);
+# else
+ UNUSED_VARS(iter, ptr);
+# endif
+}
+
+static int rna_XrSessionSettings_mocap_objects_length(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ return BLI_listbase_count(&xr->session_settings.mocap_objects);
+# else
+ UNUSED_VARS(ptr);
+ return 0;
+# endif
+}
+
/** \} */
/* -------------------------------------------------------------------- */
@@ -871,6 +1090,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,
@@ -994,6 +1239,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
@@ -1081,71 +1352,6 @@ static void rna_XrSessionState_nav_scale_set(PointerRNA *ptr, float value)
# endif
}
-static void rna_XrSessionState_actionmaps_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
-{
-# ifdef WITH_XR_OPENXR
- wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
- ListBase *lb = WM_xr_actionmaps_get(xr->runtime);
- rna_iterator_listbase_begin(iter, lb, NULL);
-# else
- UNUSED_VARS(iter, ptr);
-# 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
- const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
- return WM_xr_actionmap_active_index_get(xr->runtime);
-# else
- UNUSED_VARS(ptr);
- return -1;
-# endif
-}
-
-static void rna_XrSessionState_active_actionmap_set(PointerRNA *ptr, int value)
-{
-# ifdef WITH_XR_OPENXR
- wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
- WM_xr_actionmap_active_index_set(xr->runtime, (short)value);
-# else
- UNUSED_VARS(ptr, value);
-# endif
-}
-
-static int rna_XrSessionState_selected_actionmap_get(PointerRNA *ptr)
-{
-# ifdef WITH_XR_OPENXR
- const wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
- return WM_xr_actionmap_selected_index_get(xr->runtime);
-# else
- UNUSED_VARS(ptr);
- return -1;
-# endif
-}
-
-static void rna_XrSessionState_selected_actionmap_set(PointerRNA *ptr, int value)
-{
-# ifdef WITH_XR_OPENXR
- wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
- WM_xr_actionmap_selected_index_set(xr->runtime, (short)value);
-# else
- UNUSED_VARS(ptr, value);
-# endif
-}
-
/** \} */
/* -------------------------------------------------------------------- */
@@ -1600,12 +1806,10 @@ static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_property_srna(cprop, "XrActionMaps");
srna = RNA_def_struct(brna, "XrActionMaps", NULL);
+ RNA_def_struct_sdna(srna, "XrSessionSettings");
RNA_def_struct_ui_text(srna, "XR Action Maps", "Collection of XR action maps");
func = RNA_def_function(srna, "new", "rna_XrActionMap_new");
- RNA_def_function_flag(func, FUNC_NO_SELF);
- parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_boolean(func,
@@ -1618,9 +1822,6 @@ static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "new_from_actionmap", "rna_XrActionMap_new_from_actionmap");
- RNA_def_function_flag(func, FUNC_NO_SELF);
- parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_pointer(
func, "actionmap", "XrActionMap", "Action Map", "Action map to use as a reference");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
@@ -1628,17 +1829,12 @@ static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
RNA_def_function_return(func, parm);
func = RNA_def_function(srna, "remove", "rna_XrActionMap_remove");
- RNA_def_function_flag(func, FUNC_NO_SELF | FUNC_USE_REPORTS);
- parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
parm = RNA_def_pointer(func, "actionmap", "XrActionMap", "Action Map", "Removed action map");
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_XrActionMap_find");
- RNA_def_function_flag(func, FUNC_NO_SELF);
- parm = RNA_def_pointer(func, "xr_session_state", "XrSessionState", "XR Session State", "");
- RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED | PARM_RNAPTR);
parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
parm = RNA_def_pointer(
@@ -1680,7 +1876,7 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
rna_def_xr_actionmap_items(brna, prop);
prop = RNA_def_property(srna, "selected_item", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "selitem");
+ RNA_def_property_int_sdna(prop, NULL, "sel_item");
RNA_def_property_ui_text(prop, "Selected Item", "");
/* XrUserPath */
@@ -1721,6 +1917,10 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "User Paths", "OpenXR user paths");
rna_def_xr_user_paths(brna, prop);
+ prop = RNA_def_property(srna, "selected_user_path", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sel_user_path");
+ RNA_def_property_ui_text(prop, "Selected User Path", "Currently selected user path");
+
prop = RNA_def_property(srna, "op", PROP_STRING, PROP_NONE);
RNA_def_property_string_maxlength(prop, OP_MAX_TYPENAME);
RNA_def_property_ui_text(prop, "Operator", "Identifier of operator to call on action event");
@@ -1765,6 +1965,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");
@@ -1818,7 +2023,7 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
rna_def_xr_actionmap_bindings(brna, prop);
prop = RNA_def_property(srna, "selected_binding", PROP_INT, PROP_NONE);
- RNA_def_property_int_sdna(prop, NULL, "selbinding");
+ RNA_def_property_int_sdna(prop, NULL, "sel_binding");
RNA_def_property_ui_text(prop, "Selected Binding", "Currently selected binding");
/* XrComponentPath */
@@ -1858,6 +2063,10 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
RNA_def_property_ui_text(prop, "Component Paths", "OpenXR component paths");
rna_def_xr_component_paths(brna, prop);
+ prop = RNA_def_property(srna, "selected_component_path", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sel_component_path");
+ RNA_def_property_ui_text(prop, "Selected Component Path", "Currently selected component path");
+
prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE);
RNA_def_property_float_sdna(prop, NULL, "float_threshold");
RNA_def_property_range(prop, 0.0, 1.0);
@@ -1891,6 +2100,97 @@ static void rna_def_xr_actionmap(BlenderRNA *brna)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name XR Motion Capture
+ * \{ */
+
+static void rna_def_xr_motioncapture_objects(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "XrMotionCaptureObjects");
+ srna = RNA_def_struct(brna, "XrMotionCaptureObjects", NULL);
+ RNA_def_struct_sdna(srna, "XrSessionSettings");
+ RNA_def_struct_ui_text(
+ srna, "XR Motion Capture Objects", "Collection of XR motion capture objects");
+
+ func = RNA_def_function(srna, "new", "rna_XrMotionCaptureObject_new");
+ parm = RNA_def_pointer(func,
+ "object",
+ "Object",
+ "Object",
+ "Blender object used to identify the motion capture object");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_pointer(func,
+ "mocap_object",
+ "XrMotionCaptureObject",
+ "Motion Capture Object",
+ "Added motion capture object");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_XrMotionCaptureObject_remove");
+ parm = RNA_def_pointer(func,
+ "mocap_object",
+ "XrMotionCaptureObject",
+ "Motion Capture Object",
+ "Removed motion capture object");
+ 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_XrMotionCaptureObject_find");
+ parm = RNA_def_pointer(
+ func, "object", "Object", "Object", "Blender object identifying the motion capture object");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED | PARM_RNAPTR);
+ parm = RNA_def_pointer(func,
+ "mocap_object",
+ "XrMotionCaptureObject",
+ "Motion Capture Object",
+ "The motion capture object with the given name");
+ RNA_def_function_return(func, parm);
+}
+
+static void rna_def_xr_motioncapture_object(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ srna = RNA_def_struct(brna, "XrMotionCaptureObject", NULL);
+ RNA_def_struct_sdna(srna, "XrMotionCaptureObject");
+ RNA_def_struct_ui_text(srna, "XR Motion Capture Object", "");
+
+ prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE);
+ RNA_def_property_pointer_sdna(prop, NULL, "ob");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(prop, "Object", "Object to bind to a VR device");
+ RNA_def_property_update(prop, 0, "rna_XrMotionCaptureObject_object_update");
+
+ prop = RNA_def_property(srna, "user_path", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_maxlength(prop, 64);
+ RNA_def_property_ui_text(prop, "User Path", "OpenXR user path identifying the target VR device");
+
+ prop = RNA_def_property(srna, "location_offset", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_ui_text(prop, "Location Offset", "Location offset in device space");
+
+ prop = RNA_def_property(srna, "rotation_offset", PROP_FLOAT, PROP_EULER);
+ RNA_def_property_ui_text(prop, "Rotation Offset", "Rotation offset in device space");
+
+ prop = RNA_def_property(srna, "enable", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_XrMotionCaptureObject_enable_get", "rna_XrMotionCaptureObject_enable_set");
+ RNA_def_property_ui_text(prop, "Enable", "Bind object to target VR device");
+ RNA_def_property_update(prop, 0, "rna_XrMotionCaptureObject_enable_update");
+
+ prop = RNA_def_property(srna, "autokey", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_XrMotionCaptureObject_autokey_get", "rna_XrMotionCaptureObject_autokey_set");
+ RNA_def_property_ui_text(prop, "Auto Key", "Auto-insert keyframes on animation playback");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name XR Session Settings
* \{ */
@@ -2052,6 +2352,16 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
"Allow the VR tracking origin to be defined independently of the headset location");
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+ prop = RNA_def_property(srna, "enable_vive_tracker_extension", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop,
+ "rna_XrSessionSettings_enable_vive_tracker_extension_get",
+ "rna_XrSessionSettings_enable_vive_tracker_extension_set");
+ RNA_def_property_ui_text(prop,
+ "Enable Vive Tracker Extension",
+ "Enable bindings for the HTC Vive Trackers. Note that this may not be "
+ "supported by all OpenXR runtimes");
+ RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
+
rna_def_object_type_visibility_flags_common(srna, NC_WM | ND_XR_DATA_CHANGED);
/* Helper for drawing the icon. */
@@ -2060,6 +2370,48 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
prop, "rna_XrSessionSettings_icon_from_show_object_viewport_get", NULL, NULL);
RNA_def_property_clear_flag(prop, PROP_EDITABLE);
RNA_def_property_ui_text(prop, "Visibility Icon", "");
+
+ prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop,
+ "rna_XrSessionSettings_actionmaps_begin",
+ "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end",
+ "rna_iterator_listbase_get",
+ "rna_XrSessionSettings_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);
+
+ prop = RNA_def_property(srna, "active_actionmap", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "act_actionmap");
+ RNA_def_property_ui_text(prop, "Active Action Map", "");
+
+ prop = RNA_def_property(srna, "selected_actionmap", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sel_actionmap");
+ RNA_def_property_ui_text(prop, "Selected Action Map", "");
+
+ prop = RNA_def_property(srna, "mocap_objects", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "XrMotionCaptureObject");
+ RNA_def_property_collection_funcs(prop,
+ "rna_XrSessionSettings_mocap_objects_begin",
+ "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end",
+ "rna_iterator_listbase_get",
+ "rna_XrSessionSettings_mocap_objects_length",
+ NULL,
+ NULL,
+ NULL);
+ RNA_def_property_ui_text(
+ prop, "XR Motion Capture Objects", "Objects to bind to headset/controller poses");
+ rna_def_xr_motioncapture_objects(brna, prop);
+
+ prop = RNA_def_property(srna, "selected_mocap_object", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "sel_mocap_object");
+ RNA_def_property_ui_text(
+ prop, "Selected Motion Capture Object", "Currently selected motion capture object");
}
/** \} */
@@ -2165,6 +2517,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);
@@ -2347,6 +2735,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);
@@ -2390,34 +2821,6 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
prop,
"Navigation Scale",
"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",
- "rna_XrSessionState_actionmaps_length",
- NULL,
- NULL,
- NULL);
- RNA_def_property_ui_text(prop, "XR Action Maps", "");
- rna_def_xr_actionmaps(brna, prop);
-
- prop = RNA_def_property(srna, "active_actionmap", PROP_INT, PROP_NONE);
- RNA_def_property_int_funcs(prop,
- "rna_XrSessionState_active_actionmap_get",
- "rna_XrSessionState_active_actionmap_set",
- NULL);
- RNA_def_property_ui_text(prop, "Active Action Map", "");
-
- prop = RNA_def_property(srna, "selected_actionmap", PROP_INT, PROP_NONE);
- RNA_def_property_int_funcs(prop,
- "rna_XrSessionState_selected_actionmap_get",
- "rna_XrSessionState_selected_actionmap_set",
- NULL);
- RNA_def_property_ui_text(prop, "Selected Action Map", "");
}
/** \} */
@@ -2528,6 +2931,7 @@ void RNA_def_xr(BlenderRNA *brna)
RNA_define_animate_sdna(false);
rna_def_xr_actionmap(brna);
+ rna_def_xr_motioncapture_object(brna);
rna_def_xr_session_settings(brna);
rna_def_xr_session_state(brna);
rna_def_xr_eventdata(brna);
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 4c553d0edfe..3cc643a7ac7 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -176,6 +176,8 @@ if(WITH_XR_OPENXR)
list(APPEND INC
xr
+ # For wm_xr_operators.c: BKE_editmesh.h
+ ../bmesh
)
list(APPEND SRC
@@ -183,6 +185,7 @@ if(WITH_XR_OPENXR)
xr/intern/wm_xr_action.c
xr/intern/wm_xr_actionmap.c
xr/intern/wm_xr_draw.c
+ xr/intern/wm_xr_mocap.c
xr/intern/wm_xr_operators.c
xr/intern/wm_xr_session.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 60cded3b869..e60d812e5b6 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -1667,6 +1667,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]);
@@ -1722,6 +1728,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.
@@ -1745,23 +1757,17 @@ void WM_xr_haptic_action_stop(wmXrData *xr,
/* wm_xr_actionmap.c */
-XrActionMap *WM_xr_actionmap_new(struct wmXrRuntimeData *runtime,
+XrActionMap *WM_xr_actionmap_new(XrSessionSettings *settings,
const char *name,
bool replace_existing);
/**
* Ensure unique name among all action maps.
*/
-void WM_xr_actionmap_ensure_unique(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
-XrActionMap *WM_xr_actionmap_add_copy(struct wmXrRuntimeData *runtime, XrActionMap *am_src);
-bool WM_xr_actionmap_remove(struct wmXrRuntimeData *runtime, XrActionMap *actionmap);
-XrActionMap *WM_xr_actionmap_find(struct wmXrRuntimeData *runtime, const char *name);
-void WM_xr_actionmap_clear(XrActionMap *actionmap);
-void WM_xr_actionmaps_clear(struct wmXrRuntimeData *runtime);
-ListBase *WM_xr_actionmaps_get(struct wmXrRuntimeData *runtime);
-short WM_xr_actionmap_active_index_get(const struct wmXrRuntimeData *runtime);
-void WM_xr_actionmap_active_index_set(struct wmXrRuntimeData *runtime, short idx);
-short WM_xr_actionmap_selected_index_get(const struct wmXrRuntimeData *runtime);
-void WM_xr_actionmap_selected_index_set(struct wmXrRuntimeData *runtime, short idx);
+void WM_xr_actionmap_ensure_unique(XrSessionSettings *settings, XrActionMap *actionmap);
+XrActionMap *WM_xr_actionmap_add_copy(XrSessionSettings *settings, XrActionMap *am_src);
+bool WM_xr_actionmap_remove(XrSessionSettings *settings, XrActionMap *actionmap);
+XrActionMap *WM_xr_actionmap_find(XrSessionSettings *settings, const char *name);
+void WM_xr_actionmaps_free(XrSessionSettings *settings);
XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
const char *name,
@@ -1790,6 +1796,18 @@ XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami,
XrActionMapBinding *amb_src);
bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *amb);
XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const char *name);
+
+/* wm_xr_mocap.c */
+
+XrMotionCaptureObject *WM_xr_mocap_object_new(XrSessionSettings *settings, Object *ob);
+void WM_xr_mocap_object_ensure_unique(XrSessionSettings *settings,
+ XrMotionCaptureObject *mocap_ob);
+void WM_xr_mocap_object_remove(XrSessionSettings *settings, XrMotionCaptureObject *mocap_ob);
+XrMotionCaptureObject *WM_xr_mocap_object_find(const XrSessionSettings *settings,
+ const Object *ob);
+
+bool WM_xr_session_state_mocap_pose_get(const wmXrData *xr, XrMotionCaptureObject *mocap_ob);
+void WM_xr_session_state_mocap_pose_set(wmXrData *xr, const XrMotionCaptureObject *mocap_ob);
#endif /* WITH_XR_OPENXR */
#ifdef __cplusplus
diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c
index 40d9b0b9a35..d113669a998 100644
--- a/source/blender/windowmanager/intern/wm.c
+++ b/source/blender/windowmanager/intern/wm.c
@@ -95,6 +95,33 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data)
static void write_wm_xr_data(BlendWriter *writer, wmXrData *xr_data)
{
BKE_screen_view3d_shading_blend_write(writer, &xr_data->session_settings.shading);
+
+ LISTBASE_FOREACH (XrActionMap *, am, &xr_data->session_settings.actionmaps) {
+ BLO_write_struct(writer, XrActionMap, am);
+
+ LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
+ BLO_write_struct(writer, XrActionMapItem, ami);
+ if (ami->op[0] && ami->op_properties) {
+ IDP_BlendWrite(writer, ami->op_properties);
+ }
+
+ LISTBASE_FOREACH (XrUserPath *, user_path, &ami->user_paths) {
+ BLO_write_struct(writer, XrUserPath, user_path);
+ }
+
+ LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) {
+ BLO_write_struct(writer, XrActionMapBinding, amb);
+
+ LISTBASE_FOREACH (XrComponentPath *, component_path, &amb->component_paths) {
+ BLO_write_struct(writer, XrComponentPath, component_path);
+ }
+ }
+ }
+ }
+
+ LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &xr_data->session_settings.mocap_objects) {
+ BLO_write_struct(writer, XrMotionCaptureObject, mocap_ob);
+ }
}
static void window_manager_blend_write(BlendWriter *writer, ID *id, const void *id_address)
@@ -123,6 +150,36 @@ static void window_manager_blend_write(BlendWriter *writer, ID *id, const void *
static void direct_link_wm_xr_data(BlendDataReader *reader, wmXrData *xr_data)
{
BKE_screen_view3d_shading_blend_read_data(reader, &xr_data->session_settings.shading);
+
+ BLO_read_list(reader, &xr_data->session_settings.actionmaps);
+
+ LISTBASE_FOREACH (XrActionMap *, am, &xr_data->session_settings.actionmaps) {
+ BLO_read_list(reader, &am->items);
+
+ LISTBASE_FOREACH (XrActionMapItem *, ami, &am->items) {
+ if (ami->op[0] && ami->op_properties) {
+ BLO_read_data_address(reader, &ami->op_properties);
+ IDP_BlendDataRead(reader, &ami->op_properties);
+
+ ami->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
+ WM_operator_properties_create(ami->op_properties_ptr, ami->op);
+ ami->op_properties_ptr->data = ami->op_properties;
+ }
+ else {
+ ami->op_properties = NULL;
+ ami->op_properties_ptr = NULL;
+ }
+
+ BLO_read_list(reader, &ami->user_paths);
+ BLO_read_list(reader, &ami->bindings);
+
+ LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) {
+ BLO_read_list(reader, &amb->component_paths);
+ }
+ }
+ }
+
+ BLO_read_list(reader, &xr_data->session_settings.mocap_objects);
}
static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
@@ -216,6 +273,10 @@ static void window_manager_blend_read_data(BlendDataReader *reader, ID *id)
static void lib_link_wm_xr_data(BlendLibReader *reader, ID *parent_id, wmXrData *xr_data)
{
BLO_read_id_address(reader, parent_id->lib, &xr_data->session_settings.base_pose_object);
+
+ LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &xr_data->session_settings.mocap_objects) {
+ BLO_read_id_address(reader, parent_id->lib, &mocap_ob->ob);
+ }
}
static void lib_link_workspace_instance_hook(BlendLibReader *reader,
diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c
index a170fa9902b..45d192d227c 100644
--- a/source/blender/windowmanager/intern/wm_files.c
+++ b/source/blender/windowmanager/intern/wm_files.c
@@ -201,6 +201,12 @@ static void wm_window_match_init(bContext *C, ListBase *wmlist)
WM_msgbus_destroy(wm->message_bus);
wm->message_bus = NULL;
}
+
+#ifdef WITH_XR_OPENXR
+ /* Free XR action maps and motion capture objects. */
+ WM_xr_actionmaps_free(&wm->xr.session_settings);
+ BLI_freelistN(&wm->xr.session_settings.mocap_objects);
+#endif
}
BLI_listbase_clear(&G_MAIN->wm);
diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c
index 91ec45da6d4..104eda220cc 100644
--- a/source/blender/windowmanager/intern/wm_window.c
+++ b/source/blender/windowmanager/intern/wm_window.c
@@ -1519,7 +1519,7 @@ void wm_window_process_events(const bContext *C)
#ifdef WITH_XR_OPENXR
/* XR events don't use the regular window queues. So here we don't only trigger
* processing/dispatching but also handling. */
- has_event |= wm_xr_events_handle(CTX_wm_manager(C));
+ has_event |= wm_xr_events_handle(C);
#endif
/* When there is no event, sleep 5 milliseconds not to use too much CPU when idle.
diff --git a/source/blender/windowmanager/xr/intern/wm_xr.c b/source/blender/windowmanager/xr/intern/wm_xr.c
index e46af0657a5..c4427898d3a 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr.c
@@ -8,6 +8,9 @@
* representation of the OpenXR runtime connection within the application.
*/
+#include "BLI_listbase.h"
+
+#include "BKE_context.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
#include "BKE_main.h"
@@ -87,6 +90,9 @@ bool wm_xr_init(wmWindowManager *wm)
create_info.context_flag |= GHOST_kXrContextGpuNVIDIA;
}
#endif
+ if ((wm->xr.session_settings.flag & XR_SESSION_ENABLE_VIVE_TRACKER_EXTENSION) != 0) {
+ create_info.context_flag |= GHOST_kXrContextEnableViveTrackerExtension;
+ }
if (!(context = GHOST_XrContextCreate(&create_info))) {
return false;
@@ -117,16 +123,20 @@ void wm_xr_exit(wmWindowManager *wm)
IDP_FreeProperty(wm->xr.session_settings.shading.prop);
wm->xr.session_settings.shading.prop = NULL;
}
+ WM_xr_actionmaps_free(&wm->xr.session_settings);
+ BLI_freelistN(&wm->xr.session_settings.mocap_objects);
}
-bool wm_xr_events_handle(wmWindowManager *wm)
+bool wm_xr_events_handle(const bContext *C)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
+
if (wm->xr.runtime && wm->xr.runtime->context) {
GHOST_XrEventsHandle(wm->xr.runtime->context);
/* Process OpenXR action events. */
if (WM_xr_session_is_ready(&wm->xr)) {
- wm_xr_session_actions_update(wm);
+ wm_xr_session_actions_update(C);
}
/* wm_window_process_events() uses the return value to determine if it can put the main thread
@@ -168,7 +178,6 @@ void wm_xr_runtime_data_free(wmXrRuntimeData **runtime)
(*runtime)->area = NULL;
}
wm_xr_session_data_free(&(*runtime)->session_state);
- WM_xr_actionmaps_clear(*runtime);
GHOST_XrContextDestroy(context);
}
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_action.c b/source/blender/windowmanager/xr/intern/wm_xr_action.c
index a83415c98af..3dc354e148d 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)) {
@@ -416,6 +430,7 @@ bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name, bool
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);
@@ -424,6 +439,13 @@ bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name, bool
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;
}
@@ -469,6 +491,66 @@ 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;
+ }
+
+ {
+ LinkData *ld = BLI_findptr(
+ &action_set->tracker_actions, tracker_action, offsetof(LinkData, data));
+ if (!ld) {
+ return false;
+ }
+ BLI_freelinkN(&action_set->tracker_actions, ld);
+ }
+
+ 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 true;
+}
+
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_actionmap.c b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
index 8a1982fa8b5..20d77c8bdcf 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
@@ -127,6 +127,7 @@ XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami,
static void wm_xr_actionmap_binding_clear(XrActionMapBinding *amb)
{
BLI_freelistN(&amb->component_paths);
+ amb->sel_component_path = 0;
}
bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *amb)
@@ -137,9 +138,9 @@ bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *am
wm_xr_actionmap_binding_clear(amb);
BLI_freelinkN(&ami->bindings, amb);
- if (idx <= ami->selbinding) {
- if (--ami->selbinding < 0) {
- ami->selbinding = 0;
+ if (idx <= ami->sel_binding) {
+ if (--ami->sel_binding < 0) {
+ ami->sel_binding = 0;
}
}
@@ -192,11 +193,12 @@ static void wm_xr_actionmap_item_clear(XrActionMapItem *ami)
wm_xr_actionmap_binding_clear(amb);
}
BLI_freelistN(&ami->bindings);
- ami->selbinding = 0;
-
- wm_xr_actionmap_item_properties_free(ami);
+ ami->sel_binding = 0;
BLI_freelistN(&ami->user_paths);
+ ami->sel_user_path = 0;
+
+ wm_xr_actionmap_item_properties_free(ami);
}
void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
@@ -313,6 +315,12 @@ static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami_src)
BLI_addtail(&ami_dst->bindings, amb_new);
}
+ BLI_listbase_clear(&ami_dst->user_paths);
+ LISTBASE_FOREACH (XrUserPath *, path, &ami_src->user_paths) {
+ XrUserPath *path_new = MEM_dupallocN(path);
+ BLI_addtail(&ami_dst->user_paths, path_new);
+ }
+
if (ami_dst->op_properties) {
ami_dst->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
WM_operator_properties_create(ami_dst->op_properties_ptr, ami_dst->op);
@@ -324,12 +332,6 @@ static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami_src)
ami_dst->op_properties_ptr = NULL;
}
- BLI_listbase_clear(&ami_dst->user_paths);
- LISTBASE_FOREACH (XrUserPath *, path, &ami_src->user_paths) {
- XrUserPath *path_new = MEM_dupallocN(path);
- BLI_addtail(&ami_dst->user_paths, path_new);
- }
-
return ami_dst;
}
@@ -352,9 +354,9 @@ bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami)
wm_xr_actionmap_item_clear(ami);
BLI_freelinkN(&actionmap->items, ami);
- if (idx <= actionmap->selitem) {
- if (--actionmap->selitem < 0) {
- actionmap->selitem = 0;
+ if (idx <= actionmap->sel_item) {
+ if (--actionmap->sel_item < 0) {
+ actionmap->sel_item = 0;
}
}
@@ -382,39 +384,49 @@ XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *n
* List of XR action map items.
* \{ */
-XrActionMap *WM_xr_actionmap_new(wmXrRuntimeData *runtime, const char *name, bool replace_existing)
+static void wm_xr_actionmap_clear(XrActionMap *actionmap)
+{
+ LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
+ wm_xr_actionmap_item_clear(ami);
+ }
+ BLI_freelistN(&actionmap->items);
+ actionmap->sel_item = 0;
+}
+
+XrActionMap *WM_xr_actionmap_new(XrSessionSettings *settings,
+ const char *name,
+ bool replace_existing)
{
- XrActionMap *am_prev = WM_xr_actionmap_find(runtime, name);
+ XrActionMap *am_prev = WM_xr_actionmap_find(settings, name);
if (am_prev && replace_existing) {
- WM_xr_actionmap_clear(am_prev);
+ wm_xr_actionmap_clear(am_prev);
return am_prev;
}
XrActionMap *am = MEM_callocN(sizeof(struct XrActionMap), __func__);
BLI_strncpy(am->name, name, MAX_NAME);
if (am_prev) {
- WM_xr_actionmap_ensure_unique(runtime, am);
+ WM_xr_actionmap_ensure_unique(settings, am);
}
- BLI_addtail(&runtime->actionmaps, am);
+ BLI_addtail(&settings->actionmaps, am);
return am;
}
-static XrActionMap *wm_xr_actionmap_find_except(wmXrRuntimeData *runtime,
+static XrActionMap *wm_xr_actionmap_find_except(XrSessionSettings *settings,
const char *name,
const XrActionMap *am_except)
{
- LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
+ LISTBASE_FOREACH (XrActionMap *, am, &settings->actionmaps) {
if (STREQLEN(name, am->name, MAX_NAME) && (am != am_except)) {
return am;
}
}
-
return NULL;
}
-void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *actionmap)
+void WM_xr_actionmap_ensure_unique(XrSessionSettings *settings, XrActionMap *actionmap)
{
char name[MAX_NAME];
char *suffix;
@@ -425,7 +437,7 @@ void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *action
baselen = BLI_strnlen(name, MAX_NAME);
suffix = &name[baselen];
- while (wm_xr_actionmap_find_except(runtime, name, actionmap)) {
+ while (wm_xr_actionmap_find_except(settings, name, actionmap)) {
if ((baselen + 1) + (log10(++idx) + 1) > MAX_NAME) {
/* Use default base name. */
BLI_strncpy(name, WM_XR_ACTIONMAP_STR_DEFAULT, MAX_NAME);
@@ -455,33 +467,33 @@ static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src)
return am_dst;
}
-XrActionMap *WM_xr_actionmap_add_copy(wmXrRuntimeData *runtime, XrActionMap *am_src)
+XrActionMap *WM_xr_actionmap_add_copy(XrSessionSettings *settings, XrActionMap *am_src)
{
XrActionMap *am_dst = wm_xr_actionmap_copy(am_src);
- WM_xr_actionmap_ensure_unique(runtime, am_dst);
+ WM_xr_actionmap_ensure_unique(settings, am_dst);
- BLI_addtail(&runtime->actionmaps, am_dst);
+ BLI_addtail(&settings->actionmaps, am_dst);
return am_dst;
}
-bool WM_xr_actionmap_remove(wmXrRuntimeData *runtime, XrActionMap *actionmap)
+bool WM_xr_actionmap_remove(XrSessionSettings *settings, XrActionMap *actionmap)
{
- int idx = BLI_findindex(&runtime->actionmaps, actionmap);
+ int idx = BLI_findindex(&settings->actionmaps, actionmap);
if (idx != -1) {
- WM_xr_actionmap_clear(actionmap);
- BLI_freelinkN(&runtime->actionmaps, actionmap);
+ wm_xr_actionmap_clear(actionmap);
+ BLI_freelinkN(&settings->actionmaps, actionmap);
- if (idx <= runtime->actactionmap) {
- if (--runtime->actactionmap < 0) {
- runtime->actactionmap = 0;
+ if (idx <= settings->act_actionmap) {
+ if (--settings->act_actionmap < 0) {
+ settings->act_actionmap = 0;
}
}
- if (idx <= runtime->selactionmap) {
- if (--runtime->selactionmap < 0) {
- runtime->selactionmap = 0;
+ if (idx <= settings->sel_actionmap) {
+ if (--settings->sel_actionmap < 0) {
+ settings->sel_actionmap = 0;
}
}
@@ -491,9 +503,9 @@ bool WM_xr_actionmap_remove(wmXrRuntimeData *runtime, XrActionMap *actionmap)
return false;
}
-XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name)
+XrActionMap *WM_xr_actionmap_find(XrSessionSettings *settings, const char *name)
{
- LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
+ LISTBASE_FOREACH (XrActionMap *, am, &settings->actionmaps) {
if (STREQLEN(name, am->name, MAX_NAME)) {
return am;
}
@@ -501,47 +513,13 @@ XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name)
return NULL;
}
-void WM_xr_actionmap_clear(XrActionMap *actionmap)
-{
- LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
- wm_xr_actionmap_item_clear(ami);
- }
- BLI_freelistN(&actionmap->items);
- actionmap->selitem = 0;
-}
-
-void WM_xr_actionmaps_clear(wmXrRuntimeData *runtime)
+void WM_xr_actionmaps_free(XrSessionSettings *settings)
{
- LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
- WM_xr_actionmap_clear(am);
+ LISTBASE_FOREACH (XrActionMap *, am, &settings->actionmaps) {
+ wm_xr_actionmap_clear(am);
}
- BLI_freelistN(&runtime->actionmaps);
- runtime->actactionmap = runtime->selactionmap = 0;
-}
-
-ListBase *WM_xr_actionmaps_get(wmXrRuntimeData *runtime)
-{
- return &runtime->actionmaps;
-}
-
-short WM_xr_actionmap_active_index_get(const wmXrRuntimeData *runtime)
-{
- return runtime->actactionmap;
-}
-
-void WM_xr_actionmap_active_index_set(wmXrRuntimeData *runtime, short idx)
-{
- runtime->actactionmap = idx;
-}
-
-short WM_xr_actionmap_selected_index_get(const wmXrRuntimeData *runtime)
-{
- return runtime->selactionmap;
-}
-
-void WM_xr_actionmap_selected_index_set(wmXrRuntimeData *runtime, short idx)
-{
- runtime->selactionmap = idx;
+ BLI_freelistN(&settings->actionmaps);
+ settings->act_actionmap = settings->sel_actionmap = 0;
}
/** \} */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
index 3b1acee2b99..d17d132708d 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c
@@ -227,7 +227,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;
@@ -246,7 +246,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,
@@ -289,7 +289,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) {
@@ -322,9 +322,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);
@@ -346,9 +346,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);
@@ -381,8 +381,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 bb24514457d..f450fc91e89 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
@@ -59,6 +61,10 @@ typedef struct wmXrSessionState {
struct wmXrActionSet *active_action_set;
/* Name of the action set (if any) to activate before the next actions sync. */
char active_action_set_next[64]; /* MAX_NAME */
+
+ /* Original poses for motion capture objects. Used to restore object transforms on session end.
+ */
+ ListBase mocap_orig_poses; /* #wmXrMotionCapturePose */
} wmXrSessionState;
typedef struct wmXrRuntimeData {
@@ -74,10 +80,6 @@ typedef struct wmXrRuntimeData {
/** Although this struct is internal, RNA gets a handle to this for state information queries. */
wmXrSessionState session_state;
wmXrSessionExitFn exit_fn;
-
- ListBase actionmaps; /* #XrActionMap */
- short actactionmap;
- short selactionmap;
} wmXrRuntimeData;
typedef struct wmXrViewportPair {
@@ -94,6 +96,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 {
@@ -178,13 +182,21 @@ 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 {
+ struct wmXrMotionCapturePose *next, *prev;
+ const Object *ob;
+ GHOST_XrPose pose;
+} wmXrMotionCapturePose;
+
/* wm_xr.c */
wmXrRuntimeData *wm_xr_runtime_data_create(void);
@@ -214,14 +226,15 @@ void *wm_xr_session_gpu_binding_context_create(void);
void wm_xr_session_gpu_binding_context_destroy(GHOST_ContextHandle context);
void wm_xr_session_actions_init(wmXrData *xr);
-void wm_xr_session_actions_update(wmWindowManager *wm);
+void wm_xr_session_actions_update(const struct bContext *C);
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]);
void wm_xr_pose_scale_to_mat(const GHOST_XrPose *pose, float scale, float r_mat[4][4]);
void wm_xr_pose_to_imat(const GHOST_XrPose *pose, float r_imat[4][4]);
@@ -234,3 +247,23 @@ 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);
+void wm_xr_mocap_orig_poses_restore(const wmXrSessionState *state, XrSessionSettings *settings);
+void wm_xr_mocap_object_autokey(struct bContext *C,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ wmWindow *win,
+ Object *ob,
+ bool notify);
+void wm_xr_mocap_objects_update(const char *user_path,
+ const GHOST_XrPose *pose,
+ struct bContext *C,
+ XrSessionSettings *settings,
+ struct Scene *scene,
+ struct ViewLayer *view_layer,
+ wmWindow *win,
+ struct bScreen *screen_anim,
+ bool *notify);
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_mocap.c b/source/blender/windowmanager/xr/intern/wm_xr_mocap.c
new file mode 100644
index 00000000000..a7086a3cfa8
--- /dev/null
+++ b/source/blender/windowmanager/xr/intern/wm_xr_mocap.c
@@ -0,0 +1,272 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/** \file
+ * \ingroup wm
+ *
+ * \name Window-Manager XR Motion Capture
+ *
+ * API for XR motion capture objects.
+ */
+
+#include "BKE_context.h"
+#include "BKE_layer.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math.h"
+
+#include "DEG_depsgraph.h"
+
+#include "DNA_object_types.h"
+
+#include "ED_keyframing.h"
+#include "ED_object.h"
+#include "ED_screen.h"
+#include "ED_transform.h"
+
+#include "GHOST_C-api.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "WM_api.h"
+
+#include "wm_xr_intern.h"
+
+/* -------------------------------------------------------------------- */
+/** \name XR Motion Capture Objects
+ *
+ * List of XR motion capture objects. Stored in session settings and can be written to files.
+ * \{ */
+
+XrMotionCaptureObject *WM_xr_mocap_object_new(XrSessionSettings *settings, Object *ob)
+{
+ XrMotionCaptureObject *mocap_ob = WM_xr_mocap_object_find(settings, ob);
+
+ if (!mocap_ob) {
+ mocap_ob = MEM_callocN(sizeof(XrMotionCaptureObject), __func__);
+ mocap_ob->ob = ob;
+ BLI_addtail(&settings->mocap_objects, mocap_ob);
+ }
+
+ return mocap_ob;
+}
+
+void WM_xr_mocap_object_ensure_unique(XrSessionSettings *settings, XrMotionCaptureObject *mocap_ob)
+{
+ LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob_other, &settings->mocap_objects) {
+ if ((mocap_ob_other != mocap_ob) && (mocap_ob_other->ob == mocap_ob->ob)) {
+ mocap_ob->ob = NULL;
+ return;
+ }
+ }
+}
+
+void WM_xr_mocap_object_remove(XrSessionSettings *settings, XrMotionCaptureObject *mocap_ob)
+{
+ int idx = BLI_findindex(&settings->mocap_objects, mocap_ob);
+
+ if (idx != -1) {
+ BLI_freelinkN(&settings->mocap_objects, mocap_ob);
+
+ if (idx <= settings->sel_mocap_object) {
+ if (--settings->sel_mocap_object < 0) {
+ settings->sel_mocap_object = 0;
+ }
+ }
+ }
+}
+
+XrMotionCaptureObject *WM_xr_mocap_object_find(const XrSessionSettings *settings, const Object *ob)
+{
+ return ob ? BLI_findptr(&settings->mocap_objects, ob, offsetof(XrMotionCaptureObject, ob)) :
+ NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Motion Capture Runtime
+ *
+ * Runtime functions for motion capture object poses and autokeying.
+ * \{ */
+
+static void wm_xr_mocap_object_pose_get(const XrMotionCaptureObject *mocap_ob, GHOST_XrPose *pose)
+{
+ BLI_assert(mocap_ob->ob);
+ copy_v3_v3(pose->position, mocap_ob->ob->loc);
+ eul_to_quat(pose->orientation_quat, mocap_ob->ob->rot);
+}
+
+static void wm_xr_mocap_object_pose_set(const GHOST_XrPose *pose,
+ XrMotionCaptureObject *mocap_ob,
+ bool apply_offset)
+{
+ BLI_assert(mocap_ob->ob);
+
+ if (apply_offset) {
+ /* Convert offsets to pose (device) space. */
+ float loc_ofs[3], rot_ofs[4];
+ copy_v3_v3(loc_ofs, mocap_ob->location_offset);
+ mul_qt_v3(pose->orientation_quat, loc_ofs);
+
+ eul_to_quat(rot_ofs, mocap_ob->rotation_offset);
+ normalize_qt(rot_ofs);
+ invert_qt_normalized(rot_ofs);
+ mul_qt_qtqt(rot_ofs, pose->orientation_quat, rot_ofs);
+ normalize_qt(rot_ofs);
+
+ add_v3_v3v3(mocap_ob->ob->loc, pose->position, loc_ofs);
+ quat_to_eul(mocap_ob->ob->rot, rot_ofs);
+ }
+ else {
+ copy_v3_v3(mocap_ob->ob->loc, pose->position);
+ quat_to_eul(mocap_ob->ob->rot, pose->orientation_quat);
+ }
+
+ DEG_id_tag_update(&mocap_ob->ob->id, ID_RECALC_TRANSFORM);
+}
+
+void wm_xr_mocap_orig_poses_store(const XrSessionSettings *settings, wmXrSessionState *state)
+{
+ ListBase *mocap_orig_poses = &state->mocap_orig_poses;
+
+ LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &settings->mocap_objects) {
+ wmXrMotionCapturePose *mocap_pose = MEM_callocN(sizeof(wmXrMotionCapturePose), __func__);
+ mocap_pose->ob = mocap_ob->ob;
+ if (mocap_ob->ob) {
+ wm_xr_mocap_object_pose_get(mocap_ob, &mocap_pose->pose);
+ }
+ BLI_addtail(mocap_orig_poses, mocap_pose);
+ }
+}
+
+void wm_xr_mocap_orig_poses_restore(const wmXrSessionState *state, XrSessionSettings *settings)
+{
+ ListBase *mocap_objects = &settings->mocap_objects;
+
+ LISTBASE_FOREACH (wmXrMotionCapturePose *, mocap_pose, &state->mocap_orig_poses) {
+ XrMotionCaptureObject *mocap_ob = BLI_findptr(
+ mocap_objects, mocap_pose->ob, offsetof(XrMotionCaptureObject, ob));
+ if (mocap_ob && mocap_ob->ob) {
+ wm_xr_mocap_object_pose_set(&mocap_pose->pose, mocap_ob, false);
+ }
+ }
+}
+
+void wm_xr_mocap_object_autokey(
+ bContext *C, Scene *scene, ViewLayer *view_layer, wmWindow *win, Object *ob, bool notify)
+{
+ /* Poll functions in keyingsets_utils.py require an active window and object. */
+ wmWindow *win_prev = win ? CTX_wm_window(C) : NULL;
+ if (win) {
+ CTX_wm_window_set(C, win);
+ }
+
+ Object *obact = CTX_data_active_object(C);
+ if (!obact) {
+ Base *base = BKE_view_layer_base_find(view_layer, ob);
+ if (base) {
+ ED_object_base_select(base, BA_SELECT);
+ ED_object_base_activate(C, base);
+ }
+ }
+
+ bScreen *screen = CTX_wm_screen(C);
+ if (screen && screen->animtimer && (IS_AUTOKEY_FLAG(scene, INSERTAVAIL) == 0) &&
+ ((scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA) != 0)) {
+ ED_transform_animrecord_check_state(scene, screen->animtimer, &ob->id);
+ }
+
+ ED_transform_autokeyframe_object(C, scene, view_layer, ob, TFM_TRANSLATION);
+ if (IS_AUTOKEY_FLAG(scene, INSERTNEEDED)) {
+ ED_transform_autokeyframe_object(C, scene, view_layer, ob, TFM_ROTATION);
+ }
+
+ if (ED_transform_motionpath_need_update_object(scene, ob)) {
+ ListBase lb = {NULL, NULL};
+ BLI_addtail(&lb, BLI_genericNodeN(ob));
+
+ ED_objects_recalculate_paths(C, scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME, &lb);
+
+ BLI_freelistN(&lb);
+ }
+
+ if (notify) {
+ WM_event_add_notifier(C, NC_OBJECT | ND_KEYS, NULL);
+ WM_main_add_notifier(NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL);
+ }
+
+ if (win) {
+ CTX_wm_window_set(C, win_prev);
+ }
+}
+
+void wm_xr_mocap_objects_update(const char *user_path,
+ const GHOST_XrPose *pose,
+ bContext *C,
+ XrSessionSettings *settings,
+ Scene *scene,
+ ViewLayer *view_layer,
+ wmWindow *win,
+ bScreen *screen_anim,
+ bool *notify)
+{
+ LISTBASE_FOREACH (XrMotionCaptureObject *, mocap_ob, &settings->mocap_objects) {
+ if (mocap_ob->ob && ((mocap_ob->flag & XR_MOCAP_OBJECT_ENABLE) != 0) &&
+ STREQ(mocap_ob->user_path, user_path)) {
+ wm_xr_mocap_object_pose_set(pose, mocap_ob, true);
+
+ if (((mocap_ob->flag & XR_MOCAP_OBJECT_AUTOKEY) != 0) && screen_anim &&
+ autokeyframe_cfra_can_key(scene, &mocap_ob->ob->id)) {
+ wm_xr_mocap_object_autokey(C, scene, view_layer, win, mocap_ob->ob, *notify);
+ *notify = false;
+ }
+ }
+ }
+}
+
+bool WM_xr_session_state_mocap_pose_get(const wmXrData *xr, XrMotionCaptureObject *mocap_ob)
+{
+ if (!WM_xr_session_exists(xr)) {
+ return false;
+ }
+
+ if (mocap_ob->ob) {
+ wmXrMotionCapturePose *mocap_pose = BLI_findptr(&xr->runtime->session_state.mocap_orig_poses,
+ mocap_ob->ob,
+ offsetof(wmXrMotionCapturePose, ob));
+ if (!mocap_pose) {
+ return false;
+ }
+ wm_xr_mocap_object_pose_set(&mocap_pose->pose, mocap_ob, false);
+ }
+
+ return true;
+}
+
+void WM_xr_session_state_mocap_pose_set(wmXrData *xr, const XrMotionCaptureObject *mocap_ob)
+{
+ if (WM_xr_session_exists(xr) && mocap_ob->ob) {
+ wmXrMotionCapturePose *mocap_pose = BLI_findptr(&xr->runtime->session_state.mocap_orig_poses,
+ mocap_ob->ob,
+ offsetof(wmXrMotionCapturePose, ob));
+ if (mocap_pose) {
+ wm_xr_mocap_object_pose_get(mocap_ob, &mocap_pose->pose);
+ }
+ }
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
index 3f0c72a4a05..8fbf0964e2d 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c
@@ -13,14 +13,21 @@
#include "BLI_math.h"
#include "BKE_context.h"
+#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
+#include "BKE_layer.h"
#include "BKE_main.h"
#include "BKE_screen.h"
#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+#include "ED_keyframing.h"
+#include "ED_mesh.h"
+#include "ED_object.h"
#include "ED_screen.h"
+#include "ED_select_utils.h"
#include "ED_space_api.h"
#include "ED_transform_snap_object_context.h"
#include "ED_view3d.h"
@@ -194,6 +201,30 @@ static void wm_xr_grab_update(wmOperator *op, const wmXrActionData *actiondata)
}
}
+static bool wm_xr_grab_can_do_bimanual(const wmXrActionData *actiondata, const XrGrabData *data)
+{
+ /* Returns true if: 1) Bimanual interaction is currently occurring (i.e. inputs on both
+ * controllers are pressed) and 2) bimanual interaction occurred on the last update. This second
+ * part is needed to avoid "jumpy" navigation/transform changes when transitioning from
+ * one-handed to two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how
+ * navigation/transform deltas are calculated). */
+ return (actiondata->bimanual && data->bimanual_prev);
+}
+
+static bool wm_xr_grab_is_bimanual_ending(const wmXrActionData *actiondata, const XrGrabData *data)
+{
+ return (!actiondata->bimanual && data->bimanual_prev);
+}
+
+static bool wm_xr_grab_is_locked(const XrGrabData *data, const bool bimanual)
+{
+ if (bimanual) {
+ return data->loc_lock && data->rot_lock && data->scale_lock;
+ }
+ /* Ignore scale lock, as one-handed interaction cannot change navigation/transform scale. */
+ return data->loc_lock && data->rot_lock;
+}
+
static void orient_mat_z_normalized(float R[4][4], const float z_axis[3])
{
const float scale = len_v3(R[0]);
@@ -254,6 +285,7 @@ static void wm_xr_grab_compute(const wmXrActionData *actiondata,
const XrGrabData *data,
const float nav_mat[4][4],
const float nav_inv[4][4],
+ const float ob_inv[4][4],
bool reverse,
float r_delta[4][4])
{
@@ -280,6 +312,11 @@ static void wm_xr_grab_compute(const wmXrActionData *actiondata,
nav_mat, nav_inv, data->loc_lock, data->locz_lock, data->rotz_lock, prev, curr);
}
+ if (ob_inv) {
+ mul_m4_m4m4(prev, ob_inv, prev);
+ mul_m4_m4m4(curr, ob_inv, curr);
+ }
+
if (reverse) {
invert_m4(curr);
mul_m4_m4m4(r_delta, prev, curr);
@@ -306,6 +343,7 @@ static void wm_xr_grab_compute_bimanual(const wmXrActionData *actiondata,
const XrGrabData *data,
const float nav_mat[4][4],
const float nav_inv[4][4],
+ const float ob_inv[4][4],
bool reverse,
float r_delta[4][4])
{
@@ -375,6 +413,11 @@ static void wm_xr_grab_compute_bimanual(const wmXrActionData *actiondata,
nav_mat, nav_inv, data->loc_lock, data->locz_lock, data->rotz_lock, prev, curr);
}
+ if (ob_inv) {
+ mul_m4_m4m4(prev, ob_inv, prev);
+ mul_m4_m4m4(curr, ob_inv, curr);
+ }
+
if (reverse) {
invert_m4(curr);
mul_m4_m4m4(r_delta, prev, curr);
@@ -414,32 +457,6 @@ static int wm_xr_navigation_grab_exec(bContext *UNUSED(C), wmOperator *UNUSED(op
return OPERATOR_CANCELLED;
}
-static bool wm_xr_navigation_grab_can_do_bimanual(const wmXrActionData *actiondata,
- const XrGrabData *data)
-{
- /* Returns true if: 1) Bimanual interaction is currently occurring (i.e. inputs on both
- * controllers are pressed) and 2) bimanual interaction occurred on the last update. This second
- * part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to
- * two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas
- * are calculated). */
- return (actiondata->bimanual && data->bimanual_prev);
-}
-
-static bool wm_xr_navigation_grab_is_bimanual_ending(const wmXrActionData *actiondata,
- const XrGrabData *data)
-{
- return (!actiondata->bimanual && data->bimanual_prev);
-}
-
-static bool wm_xr_navigation_grab_is_locked(const XrGrabData *data, const bool bimanual)
-{
- if (bimanual) {
- return data->loc_lock && data->rot_lock && data->scale_lock;
- }
- /* Ignore scale lock, as one-handed interaction cannot change navigation scale. */
- return data->loc_lock && data->rot_lock;
-}
-
static void wm_xr_navigation_grab_apply(wmXrData *xr,
const wmXrActionData *actiondata,
const XrGrabData *data,
@@ -461,12 +478,22 @@ static void wm_xr_navigation_grab_apply(wmXrData *xr,
}
if (bimanual) {
- wm_xr_grab_compute_bimanual(
- actiondata, data, need_navinv ? nav_mat : NULL, need_navinv ? nav_inv : NULL, true, delta);
+ wm_xr_grab_compute_bimanual(actiondata,
+ data,
+ need_navinv ? nav_mat : NULL,
+ need_navinv ? nav_inv : NULL,
+ NULL,
+ true,
+ delta);
}
else {
- wm_xr_grab_compute(
- actiondata, data, need_navinv ? nav_mat : NULL, need_navinv ? nav_inv : NULL, true, delta);
+ wm_xr_grab_compute(actiondata,
+ data,
+ need_navinv ? nav_mat : NULL,
+ need_navinv ? nav_inv : NULL,
+ NULL,
+ true,
+ delta);
}
mul_m4_m4m4(out, delta, nav_mat);
@@ -520,7 +547,7 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven
wmWindowManager *wm = CTX_wm_manager(C);
wmXrData *xr = &wm->xr;
- const bool do_bimanual = wm_xr_navigation_grab_can_do_bimanual(actiondata, data);
+ const bool do_bimanual = wm_xr_grab_can_do_bimanual(actiondata, data);
data->loc_lock = RNA_boolean_get(op->ptr, "lock_location");
data->locz_lock = RNA_boolean_get(op->ptr, "lock_location_z");
@@ -529,10 +556,10 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven
data->scale_lock = RNA_boolean_get(op->ptr, "lock_scale");
/* Check if navigation is locked. */
- if (!wm_xr_navigation_grab_is_locked(data, do_bimanual)) {
+ if (!wm_xr_grab_is_locked(data, do_bimanual)) {
/* Prevent unwanted snapping (i.e. "jumpy" navigation changes when transitioning from
* two-handed to one-handed interaction) at the end of a bimanual interaction. */
- if (!wm_xr_navigation_grab_is_bimanual_ending(actiondata, data)) {
+ if (!wm_xr_grab_is_bimanual_ending(actiondata, data)) {
wm_xr_navigation_grab_apply(xr, actiondata, data, do_bimanual);
}
}
@@ -714,10 +741,10 @@ static void wm_xr_raycast_update(wmOperator *op,
static void wm_xr_raycast(Scene *scene,
Depsgraph *depsgraph,
+ eSnapTargetSelect snap_target_select,
const float origin[3],
const float direction[3],
float *ray_dist,
- bool selectable_only,
float r_location[3],
float r_normal[3],
int *r_index,
@@ -731,9 +758,7 @@ static void wm_xr_raycast(Scene *scene,
sctx,
depsgraph,
NULL,
- &(const struct SnapObjectParams){.snap_target_select = (selectable_only ?
- SCE_SNAP_TARGET_ONLY_SELECTABLE :
- SCE_SNAP_TARGET_ALL)},
+ &(const struct SnapObjectParams){.snap_target_select = snap_target_select},
origin,
direction,
ray_dist,
@@ -1225,10 +1250,10 @@ static void wm_xr_navigation_teleport(bContext *C,
wm_xr_raycast(scene,
depsgraph,
+ selectable_only ? SCE_SNAP_TARGET_ONLY_SELECTABLE : SCE_SNAP_TARGET_ALL,
origin,
direction,
ray_dist,
- selectable_only,
location,
normal,
&index,
@@ -1277,7 +1302,7 @@ static int wm_xr_navigation_teleport_invoke(bContext *C, wmOperator *op, const w
wm_xr_raycast_init(op);
- int retval = op->type->modal(C, op, event);
+ const int retval = op->type->modal(C, op, event);
if ((retval & OPERATOR_RUNNING_MODAL) != 0) {
WM_event_add_modal_handler(C, op);
@@ -1509,6 +1534,845 @@ static void WM_OT_xr_navigation_reset(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
+/** \name XR Raycast Select
+ *
+ * Casts a ray from an XR controller's pose and selects any hit geometry.
+ * \{ */
+
+typedef enum eXrSelectElem {
+ XR_SEL_BASE = 0,
+ XR_SEL_VERTEX = 1,
+ XR_SEL_EDGE = 2,
+ XR_SEL_FACE = 3,
+} eXrSelectElem;
+
+static void wm_xr_select_op_apply(void *elem,
+ BMesh *bm,
+ eXrSelectElem select_elem,
+ eSelectOp select_op,
+ bool *r_changed,
+ bool *r_set)
+{
+ const bool selected_prev = (select_elem == XR_SEL_BASE) ?
+ (((Base *)elem)->flag & BASE_SELECTED) != 0 :
+ (((BMElem *)elem)->head.hflag & BM_ELEM_SELECT) != 0;
+
+ if (selected_prev) {
+ switch (select_op) {
+ case SEL_OP_SUB:
+ case SEL_OP_XOR: {
+ switch (select_elem) {
+ case XR_SEL_BASE:
+ ED_object_base_select((Base *)elem, BA_DESELECT);
+ *r_changed = true;
+ break;
+ case XR_SEL_VERTEX:
+ BM_vert_select_set(bm, (BMVert *)elem, false);
+ *r_changed = true;
+ break;
+ case XR_SEL_EDGE:
+ BM_edge_select_set(bm, (BMEdge *)elem, false);
+ *r_changed = true;
+ break;
+ case XR_SEL_FACE:
+ BM_face_select_set(bm, (BMFace *)elem, false);
+ *r_changed = true;
+ break;
+ }
+ break;
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ else {
+ switch (select_op) {
+ case SEL_OP_SET:
+ case SEL_OP_ADD:
+ case SEL_OP_XOR: {
+ switch (select_elem) {
+ case XR_SEL_BASE:
+ ED_object_base_select((Base *)elem, BA_SELECT);
+ *r_changed = true;
+ break;
+ case XR_SEL_VERTEX:
+ BM_vert_select_set(bm, (BMVert *)elem, true);
+ *r_changed = true;
+ break;
+ case XR_SEL_EDGE:
+ BM_edge_select_set(bm, (BMEdge *)elem, true);
+ *r_changed = true;
+ break;
+ case XR_SEL_FACE:
+ BM_face_select_set(bm, (BMFace *)elem, true);
+ *r_changed = true;
+ break;
+ }
+ }
+ default: {
+ break;
+ }
+ }
+
+ if (select_op == SEL_OP_SET) {
+ *r_set = true;
+ }
+ }
+}
+
+static bool wm_xr_select_raycast(bContext *C,
+ const float origin[3],
+ const float direction[3],
+ float *ray_dist,
+ bool selectable_only,
+ eSelectOp select_op,
+ bool deselect_all)
+{
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ ViewContext vc;
+ ED_view3d_viewcontext_init(C, &vc, depsgraph);
+ vc.em = (vc.obedit && (vc.obedit->type == OB_MESH)) ? BKE_editmesh_from_object(vc.obedit) : NULL;
+
+ float location[3];
+ float normal[3];
+ int index;
+ Object *ob = NULL;
+ float obmat[4][4];
+
+ wm_xr_raycast(vc.scene,
+ depsgraph,
+ selectable_only ? SCE_SNAP_TARGET_ONLY_SELECTABLE : SCE_SNAP_TARGET_ALL,
+ origin,
+ direction,
+ ray_dist,
+ location,
+ normal,
+ &index,
+ &ob,
+ obmat);
+
+ /* Select. */
+ bool hit = false;
+ bool changed = false;
+
+ if (ob && vc.em &&
+ ((ob == vc.obedit) || (ob->id.orig_id == &vc.obedit->id))) { /* TODO_XR: Non-mesh objects. */
+ BMesh *bm = vc.em->bm;
+ BMFace *f = NULL;
+ BMEdge *e = NULL;
+ BMVert *v = NULL;
+
+ if (index != -1) {
+ ToolSettings *ts = vc.scene->toolsettings;
+ float co[3];
+ f = BM_face_at_index(bm, index);
+
+ if ((ts->selectmode & SCE_SELECT_VERTEX) != 0) {
+ /* Find nearest vertex. */
+ float dist_max = *ray_dist;
+ float dist;
+ BMLoop *l = f->l_first;
+ for (int i = 0; i < f->len; ++i, l = l->next) {
+ mul_v3_m4v3(co, obmat, l->v->co);
+ if ((dist = len_manhattan_v3v3(location, co)) < dist_max) {
+ v = l->v;
+ dist_max = dist;
+ }
+ }
+ if (v) {
+ hit = true;
+ }
+ }
+ if ((ts->selectmode & SCE_SELECT_EDGE) != 0) {
+ /* Find nearest edge. */
+ float dist_max = *ray_dist;
+ float dist;
+ BMLoop *l = f->l_first;
+ for (int i = 0; i < f->len; ++i, l = l->next) {
+ add_v3_v3v3(co, l->e->v1->co, l->e->v2->co);
+ mul_v3_fl(co, 0.5f);
+ mul_m4_v3(obmat, co);
+ if ((dist = len_manhattan_v3v3(location, co)) < dist_max) {
+ e = l->e;
+ dist_max = dist;
+ }
+ }
+ if (e) {
+ hit = true;
+ }
+ }
+ if ((ts->selectmode & SCE_SELECT_FACE) != 0) {
+ hit = true;
+ }
+ else {
+ f = NULL;
+ }
+ }
+
+ if (!hit) {
+ if (deselect_all) {
+ changed = EDBM_mesh_deselect_all_multi(C);
+ }
+ }
+ else {
+ bool set_v = false;
+ bool set_e = false;
+ bool set_f = false;
+
+ if (v) {
+ wm_xr_select_op_apply(v, bm, XR_SEL_VERTEX, select_op, &changed, &set_v);
+ }
+ if (e) {
+ wm_xr_select_op_apply(e, bm, XR_SEL_EDGE, select_op, &changed, &set_e);
+ }
+ if (f) {
+ wm_xr_select_op_apply(f, bm, XR_SEL_FACE, select_op, &changed, &set_f);
+ }
+
+ if (set_v || set_e || set_f) {
+ EDBM_mesh_deselect_all_multi(C);
+ if (set_v) {
+ BM_vert_select_set(bm, v, true);
+ }
+ if (set_e) {
+ BM_edge_select_set(bm, e, true);
+ }
+ if (set_f) {
+ BM_face_select_set(bm, f, true);
+ }
+ }
+ }
+
+ if (changed) {
+ DEG_id_tag_update((ID *)vc.obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
+ }
+ }
+ else if (vc.em) {
+ if (deselect_all) {
+ changed = EDBM_mesh_deselect_all_multi(C);
+ }
+
+ if (changed) {
+ DEG_id_tag_update((ID *)vc.obedit->data, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_GEOM | ND_SELECT, vc.obedit->data);
+ }
+ }
+ else {
+ if (ob) {
+ hit = true;
+ }
+
+ if (!hit) {
+ if (deselect_all) {
+ changed = ED_view3d_object_deselect_all_except(vc.view_layer, NULL);
+ }
+ }
+ else {
+ Base *base = BKE_view_layer_base_find(vc.view_layer, DEG_get_original_object(ob));
+ if (base && BASE_SELECTABLE(vc.v3d, base)) {
+ bool set = false;
+ wm_xr_select_op_apply(base, NULL, XR_SEL_BASE, select_op, &changed, &set);
+ if (set) {
+ ED_view3d_object_deselect_all_except(vc.view_layer, base);
+ }
+ }
+ }
+
+ if (changed) {
+ DEG_id_tag_update(&vc.scene->id, ID_RECALC_SELECT);
+ WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, vc.scene);
+ }
+ }
+
+ return changed;
+}
+
+static int wm_xr_select_raycast_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ wm_xr_raycast_init(op);
+
+ const int retval = op->type->modal(C, op, event);
+
+ if ((retval & OPERATOR_RUNNING_MODAL) != 0) {
+ WM_event_add_modal_handler(C, op);
+ }
+
+ return retval;
+}
+
+static int wm_xr_select_raycast_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return OPERATOR_CANCELLED;
+}
+
+static int wm_xr_select_raycast_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrData *xr = &wm->xr;
+
+ wm_xr_raycast_update(op, xr, actiondata);
+
+ switch (event->val) {
+ case KM_PRESS:
+ return OPERATOR_RUNNING_MODAL;
+ case KM_RELEASE: {
+ XrRaycastData *data = op->customdata;
+ eSelectOp select_op = SEL_OP_SET;
+ bool deselect_all, selectable_only;
+ float ray_dist;
+
+ if (RNA_boolean_get(op->ptr, "toggle")) {
+ select_op = SEL_OP_XOR;
+ }
+ if (RNA_boolean_get(op->ptr, "deselect")) {
+ select_op = SEL_OP_SUB;
+ }
+ if (RNA_boolean_get(op->ptr, "extend")) {
+ select_op = SEL_OP_ADD;
+ }
+ deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
+ selectable_only = RNA_boolean_get(op->ptr, "selectable_only");
+ ray_dist = RNA_float_get(op->ptr, "distance");
+
+ const bool changed = wm_xr_select_raycast(
+ C, data->origin, data->direction, &ray_dist, selectable_only, select_op, deselect_all);
+
+ wm_xr_raycast_uninit(op);
+
+ return changed ? OPERATOR_FINISHED : OPERATOR_CANCELLED;
+ }
+ default:
+ /* XR events currently only support press and release. */
+ BLI_assert_unreachable();
+ wm_xr_raycast_uninit(op);
+ return OPERATOR_CANCELLED;
+ }
+}
+
+static void WM_OT_xr_select_raycast(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Raycast Select";
+ ot->idname = "WM_OT_xr_select_raycast";
+ ot->description = "Raycast select with a VR controller";
+
+ /* callbacks */
+ ot->invoke = wm_xr_select_raycast_invoke;
+ ot->exec = wm_xr_select_raycast_exec;
+ ot->modal = wm_xr_select_raycast_modal;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ WM_operator_properties_mouse_select(ot);
+
+ /* Override "deselect_all" default value. */
+ PropertyRNA *prop = RNA_struct_type_find_property(ot->srna, "deselect_all");
+ BLI_assert(prop != NULL);
+ RNA_def_property_boolean_default(prop, true);
+
+ RNA_def_boolean(ot->srna,
+ "selectable_only",
+ true,
+ "Selectable Only",
+ "Only allow selectable objects to influence raycast result");
+ RNA_def_float(ot->srna,
+ "distance",
+ BVH_RAYCAST_DIST_MAX,
+ 0.0,
+ BVH_RAYCAST_DIST_MAX,
+ "",
+ "Maximum raycast distance",
+ 0.0,
+ BVH_RAYCAST_DIST_MAX);
+ RNA_def_boolean(
+ ot->srna, "from_viewer", false, "From Viewer", "Use viewer pose as raycast origin");
+ RNA_def_float_vector(ot->srna,
+ "axis",
+ 3,
+ g_xr_default_raycast_axis,
+ -1.0f,
+ 1.0f,
+ "Axis",
+ "Raycast axis in controller/viewer space",
+ -1.0f,
+ 1.0f);
+ RNA_def_float_color(ot->srna,
+ "color",
+ 4,
+ g_xr_default_raycast_color,
+ 0.0f,
+ 1.0f,
+ "Color",
+ "Raycast color",
+ 0.0f,
+ 1.0f);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Transform Grab
+ *
+ * Transforms selected objects relative to an XR controller's pose.
+ * \{ */
+
+static int wm_xr_transform_grab_invoke(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ bool loc_lock, rot_lock, scale_lock;
+ float loc_t, rot_t, loc_ofs_orig[3], rot_ofs_orig[4];
+ bool loc_ofs_set = false;
+ bool rot_ofs_set = false;
+
+ loc_lock = RNA_boolean_get(op->ptr, "location_lock");
+ if (!loc_lock) {
+ loc_t = RNA_float_get(op->ptr, "location_interpolation");
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "location_offset");
+ if (prop && RNA_property_is_set(op->ptr, prop)) {
+ RNA_property_float_get_array(op->ptr, prop, loc_ofs_orig);
+ loc_ofs_set = true;
+ }
+ }
+
+ rot_lock = RNA_boolean_get(op->ptr, "rotation_lock");
+ if (!rot_lock) {
+ rot_t = RNA_float_get(op->ptr, "rotation_interpolation");
+ PropertyRNA *prop = RNA_struct_find_property(op->ptr, "rotation_offset");
+ if (prop && RNA_property_is_set(op->ptr, prop)) {
+ float eul[3];
+ RNA_property_float_get_array(op->ptr, prop, eul);
+ eul_to_quat(rot_ofs_orig, eul);
+ normalize_qt(rot_ofs_orig);
+ rot_ofs_set = true;
+ }
+ }
+
+ scale_lock = RNA_boolean_get(op->ptr, "scale_lock");
+
+ if (loc_lock && rot_lock && scale_lock) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = (obedit && (obedit->type == OB_MESH)) ? BKE_editmesh_from_object(obedit) : NULL;
+ bool selected = false;
+
+ if (em) { /* TODO_XR: Non-mesh objects. */
+ /* Check for selection. */
+ Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ BMesh *bm = em->bm;
+ BMIter iter;
+ if ((ts->selectmode & SCE_SELECT_FACE) != 0) {
+ BMFace *f;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ selected = true;
+ break;
+ }
+ }
+ }
+ if (!selected) {
+ if ((ts->selectmode & SCE_SELECT_EDGE) != 0) {
+ BMEdge *e;
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ selected = true;
+ break;
+ }
+ }
+ }
+ if (!selected) {
+ if ((ts->selectmode & SCE_SELECT_VERTEX) != 0) {
+ BMVert *v;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT)) {
+ selected = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+ else {
+ float controller_loc[3], controller_rot[4], controller_mat[4][4];
+ float loc_ofs[3], loc_ofs_controller[3], rot_ofs[4], rot_ofs_controller[4],
+ rot_ofs_orig_inv[4];
+ float q0[4], q1[4], q2[4], m0[4][4], m1[4][4], m2[4][4];
+
+ quat_to_mat4(controller_mat, actiondata->controller_rot);
+ copy_v3_v3(controller_mat[3], actiondata->controller_loc);
+
+ /* Convert offsets to controller space. */
+ if (loc_ofs_set) {
+ copy_v3_v3(loc_ofs_controller, loc_ofs_orig);
+ mul_qt_v3(actiondata->controller_rot, loc_ofs_controller);
+ }
+ if (rot_ofs_set) {
+ invert_qt_qt_normalized(rot_ofs_orig_inv, rot_ofs_orig);
+ mul_qt_qtqt(rot_ofs_controller, actiondata->controller_rot, rot_ofs_orig_inv);
+ normalize_qt(rot_ofs_controller);
+ }
+
+ /* Apply interpolation and offsets. */
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ bool update = false;
+
+ if (ob->parent) {
+ invert_m4_m4(m0, ob->parentinv);
+ mul_m4_m4m4(m1, ob->parent->imat, controller_mat);
+ mul_m4_m4m4(m2, m0, m1);
+ mat4_to_loc_quat(controller_loc, controller_rot, m2);
+
+ if (loc_ofs_set) {
+ copy_v3_v3(loc_ofs, loc_ofs_orig);
+ mul_qt_v3(controller_rot, loc_ofs);
+ }
+ if (rot_ofs_set) {
+ mul_qt_qtqt(rot_ofs, controller_rot, rot_ofs_orig_inv);
+ normalize_qt(rot_ofs);
+ }
+ }
+ else {
+ copy_v3_v3(controller_loc, actiondata->controller_loc);
+ copy_qt_qt(controller_rot, actiondata->controller_rot);
+
+ if (loc_ofs_set) {
+ copy_v3_v3(loc_ofs, loc_ofs_controller);
+ }
+ if (rot_ofs_set) {
+ copy_qt_qt(rot_ofs, rot_ofs_controller);
+ }
+ }
+
+ if (!loc_lock) {
+ if (loc_t > 0.0f) {
+ ob->loc[0] += loc_t * (controller_loc[0] - ob->loc[0]);
+ ob->loc[1] += loc_t * (controller_loc[1] - ob->loc[1]);
+ ob->loc[2] += loc_t * (controller_loc[2] - ob->loc[2]);
+ update = true;
+ }
+ if (loc_ofs_set) {
+ add_v3_v3(ob->loc, loc_ofs);
+ update = true;
+ }
+ }
+
+ if (!rot_lock) {
+ if (rot_t > 0.0f) {
+ eul_to_quat(q1, ob->rot);
+ interp_qt_qtqt(q0, q1, controller_rot, rot_t);
+ if (!rot_ofs_set) {
+ quat_to_eul(ob->rot, q0);
+ }
+ update = true;
+ }
+ else if (rot_ofs_set) {
+ eul_to_quat(q0, ob->rot);
+ }
+ if (rot_ofs_set) {
+ rotation_between_quats_to_quat(q1, rot_ofs, q0);
+ mul_qt_qtqt(q0, rot_ofs, q1);
+ normalize_qt(q0);
+ mul_qt_qtqt(q2, controller_rot, q1);
+ normalize_qt(q2);
+ rotation_between_quats_to_quat(q1, q0, q2);
+
+ mul_qt_qtqt(q2, q0, q1);
+ normalize_qt(q2);
+ quat_to_eul(ob->rot, q2);
+ update = true;
+ }
+ }
+
+ if (update) {
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+
+ selected = true;
+ }
+ CTX_DATA_END;
+ }
+
+ if (!selected) {
+ return OPERATOR_CANCELLED;
+ }
+
+ wm_xr_grab_init(op);
+ wm_xr_grab_update(op, actiondata);
+
+ WM_event_add_modal_handler(C, op);
+
+ return OPERATOR_RUNNING_MODAL;
+}
+
+static int wm_xr_transform_grab_exec(bContext *UNUSED(C), wmOperator *UNUSED(op))
+{
+ return OPERATOR_CANCELLED;
+}
+
+static void wm_xr_transform_grab_apply(bContext *C,
+ Scene *scene,
+ Object *obedit,
+ BMEditMesh *em,
+ const wmXrActionData *actiondata,
+ const XrGrabData *data,
+ bool bimanual,
+ bool apply_transform,
+ bool *r_selected)
+{
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ bScreen *screen_anim = ED_screen_animation_playing(wm);
+ float delta[4][4];
+
+ if (em) { /* TODO_XR: Non-mesh objects. */
+ if (apply_transform) {
+ ToolSettings *ts = scene->toolsettings;
+ BMesh *bm = em->bm;
+ BMIter iter;
+
+ if (bimanual) {
+ wm_xr_grab_compute_bimanual(actiondata, data, NULL, NULL, obedit->imat, false, delta);
+ }
+ else {
+ wm_xr_grab_compute(actiondata, data, NULL, NULL, obedit->imat, false, delta);
+ }
+
+ if ((ts->selectmode & SCE_SELECT_VERTEX) != 0) {
+ BMVert *v;
+ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) {
+ if (BM_elem_flag_test(v, BM_ELEM_SELECT) &&
+ !BM_elem_flag_test(v, BM_ELEM_INTERNAL_TAG)) {
+ mul_m4_v3(delta, v->co);
+ BM_elem_flag_enable(v, BM_ELEM_INTERNAL_TAG);
+ }
+ }
+ }
+ if ((ts->selectmode & SCE_SELECT_EDGE) != 0) {
+ BMEdge *e;
+ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ if (!BM_elem_flag_test(e->v1, BM_ELEM_INTERNAL_TAG)) {
+ mul_m4_v3(delta, e->v1->co);
+ BM_elem_flag_enable(e->v1, BM_ELEM_INTERNAL_TAG);
+ }
+ if (!BM_elem_flag_test(e->v2, BM_ELEM_INTERNAL_TAG)) {
+ mul_m4_v3(delta, e->v2->co);
+ BM_elem_flag_enable(e->v2, BM_ELEM_INTERNAL_TAG);
+ }
+ }
+ }
+ }
+ if ((ts->selectmode & SCE_SELECT_FACE) != 0) {
+ BMFace *f;
+ BMLoop *l;
+ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) {
+ if (BM_elem_flag_test(f, BM_ELEM_SELECT)) {
+ l = f->l_first;
+ for (int i = 0; i < f->len; ++i, l = l->next) {
+ if (!BM_elem_flag_test(l->v, BM_ELEM_INTERNAL_TAG)) {
+ mul_m4_v3(delta, l->v->co);
+ BM_elem_flag_enable(l->v, BM_ELEM_INTERNAL_TAG);
+ }
+ }
+ }
+ }
+ }
+
+ BM_mesh_elem_hflag_disable_all(bm, BM_VERT, BM_ELEM_INTERNAL_TAG, false);
+ EDBM_mesh_normals_update(em);
+ DEG_id_tag_update(&obedit->id, ID_RECALC_GEOMETRY);
+ }
+
+ *r_selected = true;
+ }
+ else {
+ float out[4][4], m0[4][4], m1[4][4];
+
+ if (apply_transform) {
+ if (bimanual) {
+ wm_xr_grab_compute_bimanual(actiondata, data, NULL, NULL, NULL, false, delta);
+ }
+ else {
+ wm_xr_grab_compute(actiondata, data, NULL, NULL, NULL, false, delta);
+ }
+ }
+
+ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) {
+ if (apply_transform) {
+ mul_m4_m4m4(out, delta, ob->obmat);
+
+ if (ob->parent) {
+ invert_m4_m4(m0, ob->parentinv);
+ mul_m4_m4m4(m1, ob->parent->imat, out);
+ mul_m4_m4m4(out, m0, m1);
+ }
+
+ if (!data->loc_lock) {
+ copy_v3_v3(ob->loc, out[3]);
+ }
+ if (!data->rot_lock) {
+ mat4_to_eul(ob->rot, out);
+ }
+ if (!data->scale_lock && bimanual) {
+ mat4_to_size(ob->scale, out);
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
+ }
+
+ if (screen_anim && autokeyframe_cfra_can_key(scene, &ob->id)) {
+ wm_xr_mocap_object_autokey(C, scene, view_layer, NULL, ob, true);
+ }
+
+ *r_selected = true;
+ }
+ CTX_DATA_END;
+ }
+}
+
+static int wm_xr_transform_grab_modal(bContext *C, wmOperator *op, const wmEvent *event)
+{
+ if (!wm_xr_operator_test_event(op, event)) {
+ return OPERATOR_PASS_THROUGH;
+ }
+
+ const wmXrActionData *actiondata = event->customdata;
+ XrGrabData *data = op->customdata;
+ Scene *scene = CTX_data_scene(C);
+ Object *obedit = CTX_data_edit_object(C);
+ BMEditMesh *em = (obedit && (obedit->type == OB_MESH)) ? BKE_editmesh_from_object(obedit) : NULL;
+ bool apply_transform = false;
+ bool selected = false;
+
+ const bool do_bimanual = wm_xr_grab_can_do_bimanual(actiondata, data);
+
+ data->loc_lock = RNA_boolean_get(op->ptr, "location_lock");
+ data->rot_lock = RNA_boolean_get(op->ptr, "rotation_lock");
+ data->scale_lock = RNA_boolean_get(op->ptr, "scale_lock");
+
+ /* Check if navigation is locked. */
+ if (!wm_xr_grab_is_locked(data, do_bimanual)) {
+ /* Prevent unwanted snapping (i.e. "jumpy" transform changes when transitioning from
+ * two-handed to one-handed interaction) at the end of a bimanual interaction. */
+ if (!wm_xr_grab_is_bimanual_ending(actiondata, data)) {
+ apply_transform = true;
+ }
+ }
+
+ wm_xr_transform_grab_apply(
+ C, scene, obedit, em, actiondata, data, do_bimanual, apply_transform, &selected);
+
+ wm_xr_grab_update(op, actiondata);
+
+ if (!selected || (event->val == KM_RELEASE)) {
+ wm_xr_grab_uninit(op);
+
+ if (obedit && em) {
+ WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);
+ }
+ else {
+ WM_event_add_notifier(C, NC_SCENE | ND_TRANSFORM_DONE, scene);
+ }
+ return OPERATOR_FINISHED;
+ }
+ else if (event->val == KM_PRESS) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ /* XR events currently only support press and release. */
+ BLI_assert_unreachable();
+ wm_xr_grab_uninit(op);
+ return OPERATOR_CANCELLED;
+}
+
+static void WM_OT_xr_transform_grab(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "XR Transform Grab";
+ ot->idname = "WM_OT_xr_transform_grab";
+ ot->description = "Transform selected objects relative to a VR controller's pose";
+
+ /* callbacks */
+ ot->invoke = wm_xr_transform_grab_invoke;
+ ot->exec = wm_xr_transform_grab_exec;
+ ot->modal = wm_xr_transform_grab_modal;
+ ot->poll = wm_xr_operator_sessionactive;
+
+ /* flags */
+ ot->flag = OPTYPE_UNDO;
+
+ /* properties */
+ static const float default_offset[3] = {0};
+
+ RNA_def_boolean(
+ ot->srna, "location_lock", false, "Lock Location", "Preserve objects' original location");
+ RNA_def_float(ot->srna,
+ "location_interpolation",
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ "Location Interpolation",
+ "Interpolation factor between object and controller locations",
+ 0.0f,
+ 1.0f);
+ RNA_def_float_translation(ot->srna,
+ "location_offset",
+ 3,
+ default_offset,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location Offset",
+ "Additional location offset in controller space",
+ -FLT_MAX,
+ FLT_MAX);
+ RNA_def_boolean(
+ ot->srna, "rotation_lock", false, "Lock Rotation", "Preserve objects' original rotation");
+ RNA_def_float(ot->srna,
+ "rotation_interpolation",
+ 0.0f,
+ 0.0f,
+ 1.0f,
+ "Rotation Interpolation",
+ "Interpolation factor between object and controller rotations",
+ 0.0f,
+ 1.0f);
+ RNA_def_float_rotation(ot->srna,
+ "rotation_offset",
+ 3,
+ default_offset,
+ -2 * M_PI,
+ 2 * M_PI,
+ "Rotation Offset",
+ "Additional rotation offset in controller space",
+ -2 * M_PI,
+ 2 * M_PI);
+ RNA_def_boolean(ot->srna, "scale_lock", false, "Lock Scale", "Preserve objects' original scale");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Operator Registration
* \{ */
@@ -1519,6 +2383,8 @@ void wm_xr_operatortypes_register(void)
WM_operatortype_append(WM_OT_xr_navigation_fly);
WM_operatortype_append(WM_OT_xr_navigation_teleport);
WM_operatortype_append(WM_OT_xr_navigation_reset);
+ WM_operatortype_append(WM_OT_xr_select_raycast);
+ WM_operatortype_append(WM_OT_xr_transform_grab);
}
/** \} */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c
index a4d2a65830f..9f511bc2fda 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_session.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c
@@ -43,6 +43,9 @@
#include "wm_window.h"
#include "wm_xr_intern.h"
+/* OpenXR user path identifying the headset. Used for motion capture objects. */
+#define XR_HEADSET_PATH "/user/head"
+
static wmSurface *g_xr_surface = NULL;
static CLG_LogRef LOG = {"wm.xr"};
@@ -67,24 +70,27 @@ static void wm_xr_session_create_cb(void)
settings->base_scale = 1.0f;
}
state->prev_base_scale = settings->base_scale;
+
+ /* Store motion capture object poses. */
+ 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);
}
static void wm_xr_session_exit_cb(void *customdata)
@@ -96,6 +102,9 @@ static void wm_xr_session_exit_cb(void *customdata)
xr_data->runtime->session_state.is_started = false;
+ /* Restore motion capture object poses. */
+ wm_xr_mocap_orig_poses_restore(&xr_data->runtime->session_state, &xr_data->session_settings);
+
if (xr_data->runtime->exit_fn) {
xr_data->runtime->exit_fn(xr_data);
}
@@ -499,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) {
@@ -606,16 +657,80 @@ static void wm_xr_session_controller_pose_calc(const GHOST_XrPose *raw_pose,
mat4_to_loc_quat(r_pose->position, r_pose->orientation_quat, r_mat);
}
-static void wm_xr_session_controller_data_update(const XrSessionSettings *settings,
- const wmXrAction *grip_action,
+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)
+ 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);
+ wmWindowManager *wm = CTX_wm_manager(C);
+ 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) {
@@ -631,30 +746,47 @@ static void wm_xr_session_controller_data_update(const XrSessionSettings *settin
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);
-
- 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,
+ &notify,
+ 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,
+ &notify,
+ tracker);
+ tracker = tracker->next;
}
}
}
@@ -1165,8 +1297,9 @@ static void wm_xr_session_events_dispatch(wmXrData *xr,
MEM_freeN(actions);
}
-void wm_xr_session_actions_update(wmWindowManager *wm)
+void wm_xr_session_actions_update(const bContext *C)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
wmXrData *xr = &wm->xr;
if (!xr->runtime) {
return;
@@ -1175,6 +1308,7 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
XrSessionSettings *settings = &xr->session_settings;
GHOST_XrContextHandle xr_context = xr->runtime->context;
wmXrSessionState *state = &xr->runtime->session_state;
+ wmWindow *win = wm_xr_session_root_window_or_fallback_get(wm, xr->runtime);
if (state->is_navigation_dirty) {
memcpy(&state->nav_pose_prev, &state->nav_pose, sizeof(state->nav_pose_prev));
@@ -1198,6 +1332,23 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
}
wmXrActionSet *active_action_set = state->active_action_set;
+ /* Update headset motion capture objects. */
+ {
+ Scene *scene = CTX_data_scene(C);
+ ViewLayer *view_layer = CTX_data_view_layer(C);
+ bScreen *screen_anim = ED_screen_animation_playing(wm);
+ bool notify = true;
+ wm_xr_mocap_objects_update(XR_HEADSET_PATH,
+ &state->viewer_pose,
+ (bContext *)C,
+ settings,
+ scene,
+ view_layer,
+ win,
+ screen_anim,
+ &notify);
+ }
+
const bool synced = GHOST_XrSyncActions(xr_context,
active_action_set ? active_action_set->name : NULL);
if (!synced) {
@@ -1206,14 +1357,16 @@ void wm_xr_session_actions_update(wmWindowManager *wm)
/* Only update controller data and dispatch events for active action set. */
if (active_action_set) {
- wmWindow *win = wm_xr_session_root_window_or_fallback_get(wm, xr->runtime);
-
- if (active_action_set->controller_grip_action && active_action_set->controller_aim_action) {
- wm_xr_session_controller_data_update(settings,
- active_action_set->controller_grip_action,
- active_action_set->controller_aim_action,
- xr_context,
- state);
+ 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) {
@@ -1240,15 +1393,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]);
@@ -1269,7 +1420,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) {
@@ -1283,6 +1434,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 */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/windowmanager/xr/wm_xr.h b/source/blender/windowmanager/xr/wm_xr.h
index 5eb17ceac4b..57adb4ff3c0 100644
--- a/source/blender/windowmanager/xr/wm_xr.h
+++ b/source/blender/windowmanager/xr/wm_xr.h
@@ -6,6 +6,7 @@
#pragma once
+struct bContext;
struct wmWindowManager;
struct wmXrData;
@@ -16,7 +17,7 @@ typedef void (*wmXrSessionExitFn)(const wmXrData *xr_data);
bool wm_xr_init(wmWindowManager *wm);
void wm_xr_exit(wmWindowManager *wm);
void wm_xr_session_toggle(wmWindowManager *wm, wmWindow *win, wmXrSessionExitFn session_exit_fn);
-bool wm_xr_events_handle(wmWindowManager *wm);
+bool wm_xr_events_handle(const struct bContext *C);
/* wm_xr_operators.c */