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--intern/ghost/GHOST_C-api.h16
-rw-r--r--intern/ghost/intern/GHOST_C-api.cpp33
-rw-r--r--intern/ghost/intern/GHOST_XrAction.cpp64
-rw-r--r--intern/ghost/intern/GHOST_XrAction.h8
-rw-r--r--intern/ghost/intern/GHOST_XrSession.cpp31
-rw-r--r--intern/ghost/intern/GHOST_XrSession.h7
-rw-r--r--source/blender/makesdna/DNA_xr_types.h107
-rw-r--r--source/blender/makesrna/intern/rna_xr.c1536
-rw-r--r--source/blender/windowmanager/CMakeLists.txt1
-rw-r--r--source/blender/windowmanager/WM_api.h51
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr.c1
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_action.c99
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_actionmap.c565
-rw-r--r--source/blender/windowmanager/xr/intern/wm_xr_intern.h59
14 files changed, 2508 insertions, 70 deletions
diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h
index fea5a545807..83c67f83908 100644
--- a/intern/ghost/GHOST_C-api.h
+++ b/intern/ghost/GHOST_C-api.h
@@ -1102,6 +1102,7 @@ int GHOST_XrSyncActions(GHOST_XrContextHandle xr_context, const char *action_set
int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_context,
const char *action_set_name,
const char *action_name,
+ const char **subaction_path,
const int64_t *duration,
const float *frequency,
const float *amplitude);
@@ -1111,7 +1112,8 @@ int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_context,
*/
void GHOST_XrStopHapticAction(GHOST_XrContextHandle xr_context,
const char *action_set_name,
- const char *action_name);
+ const char *action_name,
+ const char **subaction_path);
/**
* Get action set custom data (owned by Blender, not GHOST).
@@ -1126,6 +1128,18 @@ void *GHOST_XrGetActionCustomdata(GHOST_XrContextHandle xr_context,
const char *action_set_name,
const char *action_name);
+/**
+ * Get the number of actions in an action set.
+ */
+unsigned int GHOST_XrGetActionCount(GHOST_XrContextHandle xr_context, const char *action_set_name);
+
+/**
+ * Get custom data for all actions in an action set.
+ */
+void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_context,
+ const char *action_set_name,
+ void **r_customdata_array);
+
#endif /* WITH_XR_OPENXR */
#ifdef __cplusplus
diff --git a/intern/ghost/intern/GHOST_C-api.cpp b/intern/ghost/intern/GHOST_C-api.cpp
index 0bc9be26eb1..b1af5c131ab 100644
--- a/intern/ghost/intern/GHOST_C-api.cpp
+++ b/intern/ghost/intern/GHOST_C-api.cpp
@@ -1005,25 +1005,29 @@ int GHOST_XrSyncActions(GHOST_XrContextHandle xr_contexthandle, const char *acti
int GHOST_XrApplyHapticAction(GHOST_XrContextHandle xr_contexthandle,
const char *action_set_name,
const char *action_name,
+ const char **subaction_path,
const int64_t *duration,
const float *frequency,
const float *amplitude)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XrSession *xr_session = xr_context->getSession();
- GHOST_XR_CAPI_CALL_RET(xr_session->applyHapticAction(
- action_set_name, action_name, *duration, *frequency, *amplitude),
- xr_context);
+ GHOST_XR_CAPI_CALL_RET(
+ xr_session->applyHapticAction(
+ action_set_name, action_name, subaction_path, *duration, *frequency, *amplitude),
+ xr_context);
return 0;
}
void GHOST_XrStopHapticAction(GHOST_XrContextHandle xr_contexthandle,
const char *action_set_name,
- const char *action_name)
+ const char *action_name,
+ const char **subaction_path)
{
GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
GHOST_XrSession *xr_session = xr_context->getSession();
- GHOST_XR_CAPI_CALL(xr_session->stopHapticAction(action_set_name, action_name), xr_context);
+ GHOST_XR_CAPI_CALL(xr_session->stopHapticAction(action_set_name, action_name, subaction_path),
+ xr_context);
}
void *GHOST_XrGetActionSetCustomdata(GHOST_XrContextHandle xr_contexthandle,
@@ -1046,4 +1050,23 @@ void *GHOST_XrGetActionCustomdata(GHOST_XrContextHandle xr_contexthandle,
return 0;
}
+unsigned int GHOST_XrGetActionCount(GHOST_XrContextHandle xr_contexthandle,
+ const char *action_set_name)
+{
+ GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
+ GHOST_XrSession *xr_session = xr_context->getSession();
+ GHOST_XR_CAPI_CALL_RET(xr_session->getActionCount(action_set_name), xr_context);
+ return 0;
+}
+
+void GHOST_XrGetActionCustomdataArray(GHOST_XrContextHandle xr_contexthandle,
+ const char *action_set_name,
+ void **r_customdata_array)
+{
+ GHOST_IXrContext *xr_context = (GHOST_IXrContext *)xr_contexthandle;
+ GHOST_XrSession *xr_session = xr_context->getSession();
+ GHOST_XR_CAPI_CALL(xr_session->getActionCustomdataArray(action_set_name, r_customdata_array),
+ xr_context);
+}
+
#endif /* WITH_XR_OPENXR */
diff --git a/intern/ghost/intern/GHOST_XrAction.cpp b/intern/ghost/intern/GHOST_XrAction.cpp
index 676a3367ee1..07eb42c14e6 100644
--- a/intern/ghost/intern/GHOST_XrAction.cpp
+++ b/intern/ghost/intern/GHOST_XrAction.cpp
@@ -208,8 +208,10 @@ GHOST_XrAction::GHOST_XrAction(XrInstance instance,
m_subaction_paths.resize(info.count_subaction_paths);
for (uint32_t i = 0; i < info.count_subaction_paths; ++i) {
- CHECK_XR(xrStringToPath(instance, info.subaction_paths[i], &m_subaction_paths[i]),
- (std::string("Failed to get user path \"") + info.subaction_paths[i] + "\".").data());
+ const char *subaction_path_str = info.subaction_paths[i];
+ CHECK_XR(xrStringToPath(instance, subaction_path_str, &m_subaction_paths[i]),
+ (std::string("Failed to get user path \"") + subaction_path_str + "\".").data());
+ m_subaction_indices.insert({subaction_path_str, i});
}
XrActionCreateInfo action_info{XR_TYPE_ACTION_CREATE_INFO};
@@ -373,6 +375,7 @@ void GHOST_XrAction::updateState(XrSession session,
void GHOST_XrAction::applyHapticFeedback(XrSession session,
const char *action_name,
+ const char **subaction_path_str,
const int64_t &duration,
const float &frequency,
const float &amplitude)
@@ -386,24 +389,46 @@ void GHOST_XrAction::applyHapticFeedback(XrSession session,
XrHapticActionInfo haptic_info{XR_TYPE_HAPTIC_ACTION_INFO};
haptic_info.action = m_action;
- for (std::vector<XrPath>::iterator it = m_subaction_paths.begin(); it != m_subaction_paths.end();
- ++it) {
- haptic_info.subactionPath = *it;
- CHECK_XR(xrApplyHapticFeedback(session, &haptic_info, (const XrHapticBaseHeader *)&vibration),
- (std::string("Failed to apply haptic action \"") + action_name + "\".").data());
+ if (subaction_path_str != nullptr) {
+ SubactionIndexMap::iterator it = m_subaction_indices.find(*subaction_path_str);
+ if (it != m_subaction_indices.end()) {
+ haptic_info.subactionPath = m_subaction_paths[it->second];
+ CHECK_XR(
+ xrApplyHapticFeedback(session, &haptic_info, (const XrHapticBaseHeader *)&vibration),
+ (std::string("Failed to apply haptic action \"") + action_name + "\".").data());
+ }
+ }
+ else {
+ for (const XrPath &subaction_path : m_subaction_paths) {
+ haptic_info.subactionPath = subaction_path;
+ CHECK_XR(
+ xrApplyHapticFeedback(session, &haptic_info, (const XrHapticBaseHeader *)&vibration),
+ (std::string("Failed to apply haptic action \"") + action_name + "\".").data());
+ }
}
}
-void GHOST_XrAction::stopHapticFeedback(XrSession session, const char *action_name)
+void GHOST_XrAction::stopHapticFeedback(XrSession session,
+ const char *action_name,
+ const char **subaction_path_str)
{
XrHapticActionInfo haptic_info{XR_TYPE_HAPTIC_ACTION_INFO};
haptic_info.action = m_action;
- for (std::vector<XrPath>::iterator it = m_subaction_paths.begin(); it != m_subaction_paths.end();
- ++it) {
- haptic_info.subactionPath = *it;
- CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
- (std::string("Failed to stop haptic action \"") + action_name + "\".").data());
+ if (subaction_path_str != nullptr) {
+ SubactionIndexMap::iterator it = m_subaction_indices.find(*subaction_path_str);
+ if (it != m_subaction_indices.end()) {
+ haptic_info.subactionPath = m_subaction_paths[it->second];
+ CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
+ (std::string("Failed to stop haptic action \"") + action_name + "\".").data());
+ }
+ }
+ else {
+ for (const XrPath &subaction_path : m_subaction_paths) {
+ haptic_info.subactionPath = subaction_path;
+ CHECK_XR(xrStopHapticFeedback(session, &haptic_info),
+ (std::string("Failed to stop haptic action \"") + action_name + "\".").data());
+ }
}
}
@@ -511,6 +536,19 @@ void *GHOST_XrActionSet::getCustomdata()
return m_custom_data_->custom_data_;
}
+uint32_t GHOST_XrActionSet::getActionCount() const
+{
+ return (uint32_t)m_actions.size();
+}
+
+void GHOST_XrActionSet::getActionCustomdataArray(void **r_customdata_array)
+{
+ uint32_t i = 0;
+ for (auto &[name, action] : m_actions) {
+ r_customdata_array[i++] = action.getCustomdata();
+ }
+}
+
void GHOST_XrActionSet::getBindings(
std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const
{
diff --git a/intern/ghost/intern/GHOST_XrAction.h b/intern/ghost/intern/GHOST_XrAction.h
index e2a89e87278..73a1cd9cd6a 100644
--- a/intern/ghost/intern/GHOST_XrAction.h
+++ b/intern/ghost/intern/GHOST_XrAction.h
@@ -103,17 +103,21 @@ class GHOST_XrAction {
const XrTime &predicted_display_time);
void applyHapticFeedback(XrSession session,
const char *action_name,
+ const char **subaction_path,
const int64_t &duration,
const float &frequency,
const float &amplitude);
- void stopHapticFeedback(XrSession session, const char *action_name);
+ void stopHapticFeedback(XrSession session, const char *action_name, const char **subaction_path);
void *getCustomdata();
void getBindings(std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;
private:
+ using SubactionIndexMap = std::map<std::string, uint32_t>;
+
XrAction m_action = XR_NULL_HANDLE;
GHOST_XrActionType m_type;
+ SubactionIndexMap m_subaction_indices;
std::vector<XrPath> m_subaction_paths;
/** States for each subaction path. */
void *m_states;
@@ -145,6 +149,8 @@ class GHOST_XrActionSet {
XrActionSet getActionSet() const;
void *getCustomdata();
+ uint32_t getActionCount() const;
+ void getActionCustomdataArray(void **r_customdata_array);
void getBindings(std::map<XrPath, std::vector<XrActionSuggestedBinding>> &r_bindings) const;
private:
diff --git a/intern/ghost/intern/GHOST_XrSession.cpp b/intern/ghost/intern/GHOST_XrSession.cpp
index a29ec1cc560..a63ce5c9344 100644
--- a/intern/ghost/intern/GHOST_XrSession.cpp
+++ b/intern/ghost/intern/GHOST_XrSession.cpp
@@ -754,6 +754,7 @@ bool GHOST_XrSession::syncActions(const char *action_set_name)
bool GHOST_XrSession::applyHapticAction(const char *action_set_name,
const char *action_name,
+ const char **subaction_path,
const int64_t &duration,
const float &frequency,
const float &amplitude)
@@ -768,12 +769,15 @@ bool GHOST_XrSession::applyHapticAction(const char *action_set_name,
return false;
}
- action->applyHapticFeedback(m_oxr->session, action_name, duration, frequency, amplitude);
+ action->applyHapticFeedback(
+ m_oxr->session, action_name, subaction_path, duration, frequency, amplitude);
return true;
}
-void GHOST_XrSession::stopHapticAction(const char *action_set_name, const char *action_name)
+void GHOST_XrSession::stopHapticAction(const char *action_set_name,
+ const char *action_name,
+ const char **subaction_path)
{
GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
if (action_set == nullptr) {
@@ -785,7 +789,7 @@ void GHOST_XrSession::stopHapticAction(const char *action_set_name, const char *
return;
}
- action->stopHapticFeedback(m_oxr->session, action_name);
+ action->stopHapticFeedback(m_oxr->session, action_name, subaction_path);
}
void *GHOST_XrSession::getActionSetCustomdata(const char *action_set_name)
@@ -813,4 +817,25 @@ void *GHOST_XrSession::getActionCustomdata(const char *action_set_name, const ch
return action->getCustomdata();
}
+uint32_t GHOST_XrSession::getActionCount(const char *action_set_name)
+{
+ GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
+ if (action_set == nullptr) {
+ return 0;
+ }
+
+ return action_set->getActionCount();
+}
+
+void GHOST_XrSession::getActionCustomdataArray(const char *action_set_name,
+ void **r_customdata_array)
+{
+ GHOST_XrActionSet *action_set = find_action_set(m_oxr.get(), action_set_name);
+ if (action_set == nullptr) {
+ return;
+ }
+
+ action_set->getActionCustomdataArray(r_customdata_array);
+}
+
/** \} */ /* Actions */
diff --git a/intern/ghost/intern/GHOST_XrSession.h b/intern/ghost/intern/GHOST_XrSession.h
index cdeef153fb1..ec15897058f 100644
--- a/intern/ghost/intern/GHOST_XrSession.h
+++ b/intern/ghost/intern/GHOST_XrSession.h
@@ -76,14 +76,19 @@ class GHOST_XrSession {
bool syncActions(const char *action_set_name = nullptr);
bool applyHapticAction(const char *action_set_name,
const char *action_name,
+ const char **subaction_path,
const int64_t &duration,
const float &frequency,
const float &amplitude);
- void stopHapticAction(const char *action_set_name, const char *action_name);
+ void stopHapticAction(const char *action_set_name,
+ const char *action_name,
+ const char **subaction_path);
/* Custom data (owned by Blender, not GHOST) accessors. */
void *getActionSetCustomdata(const char *action_set_name);
void *getActionCustomdata(const char *action_set_name, const char *action_name);
+ uint32_t getActionCount(const char *action_set_name);
+ void getActionCustomdataArray(const char *action_set_name, void **r_customdata_array);
private:
/** Pointer back to context managing this session. Would be nice to avoid, but needed to access
diff --git a/source/blender/makesdna/DNA_xr_types.h b/source/blender/makesdna/DNA_xr_types.h
index c0928e1519f..2e348ce6855 100644
--- a/source/blender/makesdna/DNA_xr_types.h
+++ b/source/blender/makesdna/DNA_xr_types.h
@@ -26,6 +26,8 @@
extern "C" {
#endif
+/* -------------------------------------------------------------------- */
+
typedef struct XrSessionSettings {
/** Shading settings, struct shared with 3D-View so settings are the same. */
struct View3DShading shading;
@@ -68,21 +70,122 @@ typedef enum eXrActionType {
XR_VIBRATION_OUTPUT = 100,
} eXrActionType;
+/** Determines how XR action operators are executed. */
typedef enum eXrOpFlag {
XR_OP_PRESS = 0,
XR_OP_RELEASE = 1,
XR_OP_MODAL = 2,
} eXrOpFlag;
+typedef enum eXrActionFlag {
+ /** Action depends on two subaction paths (i.e. two-handed/bimanual action). */
+ XR_ACTION_BIMANUAL = (1 << 0),
+} eXrActionFlag;
+
+typedef enum eXrHapticFlag {
+ /** Whether to apply haptics to corresponding user paths for an action and its haptic action. */
+ XR_HAPTIC_MATCHUSERPATHS = (1 << 0),
+ /** Determines how haptics will be applied ("repeat" is mutually exclusive with
+ "press"/"release"). */
+ XR_HAPTIC_PRESS = (1 << 1),
+ XR_HAPTIC_RELEASE = (1 << 2),
+ XR_HAPTIC_REPEAT = (1 << 3),
+} eXrHapticFlag;
+
+/** For axis-based inputs (thumbstick/trackpad/etc). Determines the region for action execution
+ * (mutually exclusive per axis). */
typedef enum eXrAxisFlag {
- /** For axis-based inputs (thumbstick/trackpad/etc). Determines the region for action execution
- (mutually exclusive per axis). */
XR_AXIS0_POS = (1 << 0),
XR_AXIS0_NEG = (1 << 1),
XR_AXIS1_POS = (1 << 2),
XR_AXIS1_NEG = (1 << 3),
} eXrAxisFlag;
+typedef enum eXrPoseFlag {
+ /* Pose represents controller grip/aim. */
+ XR_POSE_GRIP = (1 << 0),
+ XR_POSE_AIM = (1 << 1),
+} eXrPoseFlag;
+
+/* -------------------------------------------------------------------- */
+
+typedef struct XrActionMapBinding {
+ struct XrActionMapBinding *next, *prev;
+
+ /** Unique name. */
+ char name[64]; /* MAX_NAME */
+
+ /** OpenXR interaction profile path. */
+ char profile[256];
+ /** OpenXR component paths. */
+ char component_path0[192];
+ char component_path1[192];
+
+ /** Input threshold/region. */
+ float float_threshold;
+ short axis_flag; /* eXrAxisFlag */
+ char _pad[2];
+
+ /** Pose action properties. */
+ float pose_location[3];
+ float pose_rotation[3];
+} XrActionMapBinding;
+
+/* -------------------------------------------------------------------- */
+
+typedef struct XrActionMapItem {
+ struct XrActionMapItem *next, *prev;
+
+ /** Unique name. */
+ char name[64]; /* MAX_NAME */
+ /** Type. */
+ char type; /** eXrActionType */
+ char _pad[7];
+
+ /** OpenXR user paths. */
+ char user_path0[64];
+ char user_path1[64];
+
+ /** Operator to be called on XR events. */
+ char op[64]; /* OP_MAX_TYPENAME */
+ /** Operator properties, assigned to ptr->data and can be written to a file. */
+ IDProperty *op_properties;
+ /** RNA pointer to access properties. */
+ struct PointerRNA *op_properties_ptr;
+
+ short op_flag; /* eXrOpFlag */
+ short action_flag; /* eXrActionFlag */
+ short haptic_flag; /* eXrHapticFlag */
+
+ /** Pose action properties. */
+ short pose_flag; /* eXrPoseFlag */
+
+ /** Haptic properties. */
+ char haptic_name[64]; /* MAX_NAME */
+ float haptic_duration;
+ float haptic_frequency;
+ float haptic_amplitude;
+
+ short selbinding;
+ char _pad3[2];
+ ListBase bindings; /* XrActionMapBinding */
+} XrActionMapItem;
+
+/* -------------------------------------------------------------------- */
+
+typedef struct XrActionMap {
+ struct XrActionMap *next, *prev;
+
+ /** Unique name. */
+ char name[64]; /* MAX_NAME */
+
+ ListBase items; /* XrActionMapItem */
+ short selitem;
+ char _pad[6];
+} XrActionMap;
+
+/* -------------------------------------------------------------------- */
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesrna/intern/rna_xr.c b/source/blender/makesrna/intern/rna_xr.c
index 56e8418972c..358db14c298 100644
--- a/source/blender/makesrna/intern/rna_xr.c
+++ b/source/blender/makesrna/intern/rna_xr.c
@@ -18,9 +18,14 @@
* \ingroup RNA
*/
+#include "BLI_math.h"
+
+#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
+#include "DNA_windowmanager_types.h"
#include "DNA_xr_types.h"
+#include "RNA_access.h"
#include "RNA_define.h"
#include "RNA_enum_types.h"
@@ -30,10 +35,462 @@
#ifdef RNA_RUNTIME
-# include "BLI_math.h"
+# include "BLI_listbase.h"
# include "WM_api.h"
+/* -------------------------------------------------------------------- */
+/** \name XR Action Map
+ * \{ */
+
+static XrActionMapBinding *rna_XrActionMapBinding_new(XrActionMapItem *ami,
+ const char *name,
+ bool replace_existing)
+{
+# ifdef WITH_XR_OPENXR
+ return WM_xr_actionmap_binding_new(ami, name, replace_existing);
+# else
+ UNUSED_VARS(ami, name, replace_existing);
+ return NULL;
+# endif
+}
+
+static XrActionMapBinding *rna_XrActionMapBinding_new_from_binding(XrActionMapItem *ami,
+ XrActionMapBinding *amb_src)
+{
+# ifdef WITH_XR_OPENXR
+ return WM_xr_actionmap_binding_add_copy(ami, amb_src);
+# else
+ UNUSED_VARS(ami, amb_src);
+ return NULL;
+# endif
+}
+
+static void rna_XrActionMapBinding_remove(XrActionMapItem *ami,
+ ReportList *reports,
+ PointerRNA *amb_ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapBinding *amb = amb_ptr->data;
+ if (WM_xr_actionmap_binding_remove(ami, amb) == false) {
+ BKE_reportf(reports,
+ RPT_ERROR,
+ "ActionMapBinding '%s' cannot be removed from '%s'",
+ amb->name,
+ ami->name);
+ return;
+ }
+ RNA_POINTER_INVALIDATE(amb_ptr);
+# else
+ UNUSED_VARS(ami, reports, amb_ptr);
+# endif
+}
+
+static XrActionMapBinding *rna_XrActionMapBinding_find(XrActionMapItem *ami, const char *name)
+{
+# ifdef WITH_XR_OPENXR
+ return WM_xr_actionmap_binding_find(ami, name);
+# else
+ UNUSED_VARS(ami, name);
+ return NULL;
+# endif
+}
+
+static int rna_XrActionMapBinding_axis0_flag_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapBinding *amb = ptr->data;
+ if ((amb->axis_flag & XR_AXIS0_POS) != 0) {
+ return XR_AXIS0_POS;
+ }
+ if ((amb->axis_flag & XR_AXIS0_NEG) != 0) {
+ return XR_AXIS0_NEG;
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ return 0;
+}
+
+static void rna_XrActionMapBinding_axis0_flag_set(PointerRNA *ptr, int value)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapBinding *amb = ptr->data;
+ amb->axis_flag &= ~(XR_AXIS0_POS | XR_AXIS0_NEG);
+ amb->axis_flag |= value;
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+static int rna_XrActionMapBinding_axis1_flag_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapBinding *amb = ptr->data;
+ if ((amb->axis_flag & XR_AXIS1_POS) != 0) {
+ return XR_AXIS1_POS;
+ }
+ if ((amb->axis_flag & XR_AXIS1_NEG) != 0) {
+ return XR_AXIS1_NEG;
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ return 0;
+}
+
+static void rna_XrActionMapBinding_axis1_flag_set(PointerRNA *ptr, int value)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapBinding *amb = ptr->data;
+ amb->axis_flag &= ~(XR_AXIS1_POS | XR_AXIS1_NEG);
+ amb->axis_flag |= value;
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+static void rna_XrActionMapBinding_name_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+# 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 (actionmap) {
+ XrActionMapItem *ami = BLI_findlink(&actionmap->items, actionmap->selitem);
+ if (ami) {
+ XrActionMapBinding *amb = ptr->data;
+ WM_xr_actionmap_binding_ensure_unique(ami, amb);
+ }
+ }
+ }
+# else
+ UNUSED_VARS(bmain, ptr);
+# endif
+}
+
+static XrActionMapItem *rna_XrActionMapItem_new(XrActionMap *am,
+ const char *name,
+ bool replace_existing)
+{
+# ifdef WITH_XR_OPENXR
+ return WM_xr_actionmap_item_new(am, name, replace_existing);
+# else
+ UNUSED_VARS(am, name, replace_existing);
+ return NULL;
+# endif
+}
+
+static XrActionMapItem *rna_XrActionMapItem_new_from_item(XrActionMap *am,
+ XrActionMapItem *ami_src)
+{
+# ifdef WITH_XR_OPENXR
+ return WM_xr_actionmap_item_add_copy(am, ami_src);
+# else
+ UNUSED_VARS(am, ami_src);
+ return NULL;
+# endif
+}
+
+static void rna_XrActionMapItem_remove(XrActionMap *am, ReportList *reports, PointerRNA *ami_ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ami_ptr->data;
+ if (WM_xr_actionmap_item_remove(am, ami) == false) {
+ BKE_reportf(
+ reports, RPT_ERROR, "ActionMapItem '%s' cannot be removed from '%s'", ami->name, am->name);
+ return;
+ }
+ RNA_POINTER_INVALIDATE(ami_ptr);
+# else
+ UNUSED_VARS(am, reports, ami_ptr);
+# endif
+}
+
+static XrActionMapItem *rna_XrActionMapItem_find(XrActionMap *am, const char *name)
+{
+# ifdef WITH_XR_OPENXR
+ return WM_xr_actionmap_item_find(am, name);
+# else
+ UNUSED_VARS(am, name);
+ return NULL;
+# endif
+}
+
+static void rna_XrActionMapItem_op_name_get(PointerRNA *ptr, char *value)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if (ami->op[0]) {
+ if (ami->op_properties_ptr) {
+ wmOperatorType *ot = WM_operatortype_find(ami->op, 1);
+ if (ot) {
+ strcpy(value, WM_operatortype_name(ot, ami->op_properties_ptr));
+ return;
+ }
+ }
+ strcpy(value, ami->op);
+ return;
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ value[0] = '\0';
+}
+
+static int rna_XrActionMapItem_op_name_length(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if (ami->op[0]) {
+ if (ami->op_properties_ptr) {
+ wmOperatorType *ot = WM_operatortype_find(ami->op, 1);
+ if (ot) {
+ return strlen(WM_operatortype_name(ot, ami->op_properties_ptr));
+ }
+ }
+ return strlen(ami->op);
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ return 0;
+}
+
+static PointerRNA rna_XrActionMapItem_op_properties_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if (ami->op_properties_ptr) {
+ return *(ami->op_properties_ptr);
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ return PointerRNA_NULL;
+}
+
+static bool rna_XrActionMapItem_bimanual_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if ((ami->action_flag & XR_ACTION_BIMANUAL) != 0) {
+ return true;
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ return false;
+}
+
+static void rna_XrActionMapItem_bimanual_set(PointerRNA *ptr, bool value)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if (value) {
+ ami->action_flag |= XR_ACTION_BIMANUAL;
+ }
+ else {
+ ami->action_flag &= ~XR_ACTION_BIMANUAL;
+ }
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+static bool rna_XrActionMapItem_haptic_match_user_paths_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if ((ami->haptic_flag & XR_HAPTIC_MATCHUSERPATHS) != 0) {
+ return true;
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ return false;
+}
+
+static void rna_XrActionMapItem_haptic_match_user_paths_set(PointerRNA *ptr, bool value)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if (value) {
+ ami->haptic_flag |= XR_HAPTIC_MATCHUSERPATHS;
+ }
+ else {
+ ami->haptic_flag &= ~XR_HAPTIC_MATCHUSERPATHS;
+ }
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+static int rna_XrActionMapItem_haptic_flag_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if ((ami->haptic_flag & XR_HAPTIC_RELEASE) != 0) {
+ return ((ami->haptic_flag & XR_HAPTIC_PRESS) != 0) ? (XR_HAPTIC_PRESS | XR_HAPTIC_RELEASE) :
+ XR_HAPTIC_RELEASE;
+ }
+ if ((ami->haptic_flag & XR_HAPTIC_REPEAT) != 0) {
+ return XR_HAPTIC_REPEAT;
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ return XR_HAPTIC_PRESS;
+}
+
+static void rna_XrActionMapItem_haptic_flag_set(PointerRNA *ptr, int value)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ ami->haptic_flag &= ~(XR_HAPTIC_PRESS | XR_HAPTIC_RELEASE | XR_HAPTIC_REPEAT);
+ ami->haptic_flag |= value;
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+static bool rna_XrActionMapItem_pose_is_controller_grip_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if ((ami->pose_flag & XR_POSE_GRIP) != 0) {
+ return true;
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ return false;
+}
+
+static void rna_XrActionMapItem_pose_is_controller_grip_set(PointerRNA *ptr, bool value)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ SET_FLAG_FROM_TEST(ami->pose_flag, value, XR_POSE_GRIP);
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+static bool rna_XrActionMapItem_pose_is_controller_aim_get(PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ if ((ami->pose_flag & XR_POSE_AIM) != 0) {
+ return true;
+ }
+# else
+ UNUSED_VARS(ptr);
+# endif
+ return false;
+}
+
+static void rna_XrActionMapItem_pose_is_controller_aim_set(PointerRNA *ptr, bool value)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ SET_FLAG_FROM_TEST(ami->pose_flag, value, XR_POSE_AIM);
+# else
+ UNUSED_VARS(ptr, value);
+# endif
+}
+
+static void rna_XrActionMapItem_name_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+# 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 (actionmap) {
+ XrActionMapItem *ami = ptr->data;
+ WM_xr_actionmap_item_ensure_unique(actionmap, ami);
+ }
+ }
+# else
+ UNUSED_VARS(bmain, ptr);
+# endif
+}
+
+static void rna_XrActionMapItem_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMapItem *ami = ptr->data;
+ WM_xr_actionmap_item_properties_update_ot(ami);
+# else
+ UNUSED_VARS(ptr);
+# endif
+}
+
+static XrActionMap *rna_XrActionMap_new(wmXrData *xr, const char *name, bool replace_existing)
+{
+# ifdef WITH_XR_OPENXR
+ return WM_xr_actionmap_new(xr->runtime, name, replace_existing);
+# else
+ UNUSED_VARS(xr, name, replace_existing);
+ return NULL;
+# endif
+}
+
+static XrActionMap *rna_XrActionMap_new_from_actionmap(wmXrData *xr, XrActionMap *am_src)
+{
+# ifdef WITH_XR_OPENXR
+ return WM_xr_actionmap_add_copy(xr->runtime, am_src);
+# else
+ UNUSED_VARS(xr, am_src);
+ return NULL;
+# endif
+}
+
+static void rna_XrActionMap_remove(wmXrData *xr, ReportList *reports, PointerRNA *actionmap_ptr)
+{
+# ifdef WITH_XR_OPENXR
+ XrActionMap *actionmap = actionmap_ptr->data;
+ if (WM_xr_actionmap_remove(xr->runtime, actionmap) == false) {
+ BKE_reportf(reports, RPT_ERROR, "ActionMap '%s' cannot be removed", actionmap->name);
+ return;
+ }
+ RNA_POINTER_INVALIDATE(actionmap_ptr);
+# else
+ UNUSED_VARS(xr, reports, actionmap_ptr);
+# endif
+}
+
+static XrActionMap *rna_XrActionMap_find(wmXrData *xr, const char *name)
+{
+# ifdef WITH_XR_OPENXR
+ return WM_xr_actionmap_find(xr->runtime, name);
+# else
+ UNUSED_VARS(xr, name);
+ return NULL;
+# endif
+}
+
+static void rna_XrActionMap_name_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = bmain->wm.first;
+ if (wm && wm->xr.runtime) {
+ XrActionMap *actionmap = ptr->data;
+ WM_xr_actionmap_ensure_unique(wm->xr.runtime, actionmap);
+ }
+# else
+ UNUSED_VARS(bmain, ptr);
+# endif
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+
# ifdef WITH_XR_OPENXR
static wmXrData *rna_XrSession_wm_xr_data_get(PointerRNA *ptr)
{
@@ -49,6 +506,10 @@ static wmXrData *rna_XrSession_wm_xr_data_get(PointerRNA *ptr)
}
# endif
+/* -------------------------------------------------------------------- */
+/** \name XR Session Settings
+ * \{ */
+
static bool rna_XrSessionSettings_use_positional_tracking_get(PointerRNA *ptr)
{
# ifdef WITH_XR_OPENXR
@@ -91,6 +552,12 @@ static void rna_XrSessionSettings_use_absolute_tracking_set(PointerRNA *ptr, boo
# endif
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Session State
+ * \{ */
+
static bool rna_XrSessionState_is_running(bContext *C)
{
# ifdef WITH_XR_OPENXR
@@ -112,6 +579,304 @@ static void rna_XrSessionState_reset_to_base_pose(bContext *C)
# endif
}
+static bool rna_XrSessionState_action_set_create(bContext *C, XrActionMap *actionmap)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ return WM_xr_action_set_create(&wm->xr, actionmap->name);
+# else
+ UNUSED_VARS(C, actionmap);
+ return false;
+# endif
+}
+
+static bool rna_XrSessionState_action_create(bContext *C,
+ XrActionMap *actionmap,
+ XrActionMapItem *ami)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ unsigned int count_subaction_paths = 0;
+ const char *subaction_paths[2];
+
+ if (ami->user_path0[0]) {
+ subaction_paths[0] = ami->user_path0;
+ ++count_subaction_paths;
+
+ if (ami->user_path1[0]) {
+ subaction_paths[1] = ami->user_path1;
+ ++count_subaction_paths;
+ }
+ }
+ else {
+ if (ami->user_path1[0]) {
+ subaction_paths[0] = ami->user_path1;
+ ++count_subaction_paths;
+ }
+ else {
+ return false;
+ }
+ }
+
+ const bool is_float_action = (ami->type == XR_FLOAT_INPUT || ami->type == XR_VECTOR2F_INPUT);
+ const bool is_button_action = (is_float_action || ami->type == XR_BOOLEAN_INPUT);
+ wmOperatorType *ot = NULL;
+ IDProperty *op_properties = NULL;
+ const char *haptic_name = NULL;
+ int64_t haptic_duration_msec;
+
+ if (is_button_action) {
+ if (ami->op[0]) {
+ char idname[OP_MAX_TYPENAME];
+ WM_operator_bl_idname(idname, ami->op);
+ ot = WM_operatortype_find(idname, true);
+ if (ot) {
+ op_properties = ami->op_properties;
+ }
+ }
+
+ haptic_name = &ami->haptic_name[0];
+ haptic_duration_msec = (int64_t)(ami->haptic_duration * 1000.0f);
+ }
+
+ return WM_xr_action_create(&wm->xr,
+ actionmap->name,
+ ami->name,
+ ami->type,
+ count_subaction_paths,
+ subaction_paths,
+ ot,
+ op_properties,
+ is_button_action ? &haptic_name : NULL,
+ is_button_action ? &haptic_duration_msec : NULL,
+ is_button_action ? &ami->haptic_frequency : NULL,
+ is_button_action ? &ami->haptic_amplitude : NULL,
+ ami->op_flag,
+ ami->action_flag,
+ ami->haptic_flag);
+# else
+ UNUSED_VARS(C, actionmap, ami);
+ return false;
+# endif
+}
+
+static bool rna_XrSessionState_action_binding_create(bContext *C,
+ XrActionMap *actionmap,
+ XrActionMapItem *ami,
+ XrActionMapBinding *amb)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ unsigned int count_subaction_paths = 0;
+ const char *subaction_paths[2];
+ const char *component_paths[2];
+
+ if (ami->user_path0[0]) {
+ subaction_paths[0] = ami->user_path0;
+ component_paths[0] = amb->component_path0;
+ ++count_subaction_paths;
+
+ if (ami->user_path1[0]) {
+ subaction_paths[1] = ami->user_path1;
+ component_paths[1] = amb->component_path1;
+ ++count_subaction_paths;
+ }
+ }
+ else {
+ if (ami->user_path1[0]) {
+ subaction_paths[0] = ami->user_path1;
+ component_paths[0] = amb->component_path1;
+ ++count_subaction_paths;
+ }
+ else {
+ return false;
+ }
+ }
+
+ const bool is_float_action = (ami->type == XR_FLOAT_INPUT || ami->type == XR_VECTOR2F_INPUT);
+ const bool is_button_action = (is_float_action || ami->type == XR_BOOLEAN_INPUT);
+ const bool is_pose_action = (ami->type == XR_POSE_INPUT);
+ float float_thresholds[2];
+ eXrAxisFlag axis_flags[2];
+ wmXrPose poses[2];
+
+ if (is_float_action) {
+ float_thresholds[0] = float_thresholds[1] = amb->float_threshold;
+ }
+ if (is_button_action) {
+ axis_flags[0] = axis_flags[1] = amb->axis_flag;
+ }
+ if (is_pose_action) {
+ copy_v3_v3(poses[0].position, amb->pose_location);
+ eul_to_quat(poses[0].orientation_quat, amb->pose_rotation);
+ normalize_qt(poses[0].orientation_quat);
+ memcpy(&poses[1], &poses[0], sizeof(poses[1]));
+ }
+
+ return WM_xr_action_binding_create(&wm->xr,
+ actionmap->name,
+ ami->name,
+ amb->profile,
+ count_subaction_paths,
+ subaction_paths,
+ component_paths,
+ is_float_action ? float_thresholds : NULL,
+ is_button_action ? axis_flags : NULL,
+ is_pose_action ? poses : NULL);
+# else
+ UNUSED_VARS(C, actionmap, ami, amb);
+ return false;
+# endif
+}
+
+bool rna_XrSessionState_active_action_set_set(bContext *C, const char *action_set_name)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ return WM_xr_active_action_set_set(&wm->xr, action_set_name);
+# else
+ UNUSED_VARS(C, action_set_name);
+ return false;
+# endif
+}
+
+bool rna_XrSessionState_controller_pose_actions_set(bContext *C,
+ const char *action_set_name,
+ const char *grip_action_name,
+ const char *aim_action_name)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ return WM_xr_controller_pose_actions_set(
+ &wm->xr, action_set_name, grip_action_name, aim_action_name);
+# else
+ UNUSED_VARS(C, action_set_name, grip_action_name, aim_action_name);
+ return false;
+# endif
+}
+
+void rna_XrSessionState_action_state_get(bContext *C,
+ const char *action_set_name,
+ const char *action_name,
+ const char *user_path,
+ float r_state[2])
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ wmXrActionState state;
+ if (WM_xr_action_state_get(&wm->xr, action_set_name, action_name, user_path, &state)) {
+ switch (state.type) {
+ case XR_BOOLEAN_INPUT:
+ r_state[0] = (float)state.state_boolean;
+ r_state[1] = 0.0f;
+ return;
+ case XR_FLOAT_INPUT:
+ r_state[0] = state.state_float;
+ r_state[1] = 0.0f;
+ return;
+ case XR_VECTOR2F_INPUT:
+ copy_v2_v2(r_state, state.state_vector2f);
+ return;
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ BLI_assert_unreachable();
+ break;
+ }
+ }
+# else
+ UNUSED_VARS(C, action_set_name, action_name, user_path);
+# endif
+ zero_v2(r_state);
+}
+
+bool rna_XrSessionState_haptic_action_apply(bContext *C,
+ const char *action_set_name,
+ const char *action_name,
+ const char *user_path,
+ float duration,
+ float frequency,
+ float amplitude)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ int64_t duration_msec = (int64_t)(duration * 1000.0f);
+ return WM_xr_haptic_action_apply(&wm->xr,
+ action_set_name,
+ action_name,
+ user_path[0] ? &user_path : NULL,
+ &duration_msec,
+ &frequency,
+ &amplitude);
+# else
+ UNUSED_VARS(C, action_set_name, action_name, user_path, duration, frequency, amplitude);
+ return false;
+# endif
+}
+
+void rna_XrSessionState_haptic_action_stop(bContext *C,
+ const char *action_set_name,
+ const char *action_name,
+ const char *user_path)
+{
+# ifdef WITH_XR_OPENXR
+ wmWindowManager *wm = CTX_wm_manager(C);
+ WM_xr_haptic_action_stop(
+ &wm->xr, action_set_name, action_name, user_path[0] ? &user_path : NULL);
+# else
+ UNUSED_VARS(C, action_set_name, action_name, user_path);
+# endif
+}
+
+static void rna_XrSessionState_controller_grip_location_get(bContext *C,
+ int *index,
+ float *r_values)
+{
+# ifdef WITH_XR_OPENXR
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ WM_xr_session_state_controller_grip_location_get(&wm->xr, *index, r_values);
+# else
+ UNUSED_VARS(C, index);
+ zero_v3(r_values);
+# endif
+}
+
+static void rna_XrSessionState_controller_grip_rotation_get(bContext *C,
+ int index,
+ float *r_values)
+{
+# ifdef WITH_XR_OPENXR
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ WM_xr_session_state_controller_grip_rotation_get(&wm->xr, index, r_values);
+# else
+ UNUSED_VARS(C, index);
+ unit_qt(r_values);
+# endif
+}
+
+static void rna_XrSessionState_controller_aim_location_get(bContext *C,
+ int *index,
+ float *r_values)
+{
+# ifdef WITH_XR_OPENXR
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ WM_xr_session_state_controller_aim_location_get(&wm->xr, *index, r_values);
+# else
+ UNUSED_VARS(C, index);
+ zero_v3(r_values);
+# endif
+}
+
+static void rna_XrSessionState_controller_aim_rotation_get(bContext *C, int index, float *r_values)
+{
+# ifdef WITH_XR_OPENXR
+ const wmWindowManager *wm = CTX_wm_manager(C);
+ WM_xr_session_state_controller_aim_rotation_get(&wm->xr, index, r_values);
+# else
+ UNUSED_VARS(C, index);
+ unit_qt(r_values);
+# endif
+}
+
static void rna_XrSessionState_viewer_pose_location_get(PointerRNA *ptr, float *r_values)
{
# ifdef WITH_XR_OPENXR
@@ -134,8 +899,486 @@ static void rna_XrSessionState_viewer_pose_rotation_get(PointerRNA *ptr, float *
# endif
}
+static void rna_XrSessionState_actionmaps_begin(CollectionPropertyIterator *iter, PointerRNA *ptr)
+{
+ wmXrData *xr = rna_XrSession_wm_xr_data_get(ptr);
+ ListBase *lb = WM_xr_actionmaps_get(xr->runtime);
+ rna_iterator_listbase_begin(iter, lb, NULL);
+}
+
+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
+}
+
+/** \} */
+
#else /* RNA_RUNTIME */
+/* -------------------------------------------------------------------- */
+
+static const EnumPropertyItem rna_enum_xr_action_types[] = {
+ {XR_FLOAT_INPUT,
+ "FLOAT",
+ 0,
+ "Float",
+ "Float action, representing either a digital or analog button"},
+ {XR_VECTOR2F_INPUT,
+ "VECTOR2D",
+ 0,
+ "Vector2D",
+ "2D float vector action, representing a thumbstick or trackpad"},
+ {XR_POSE_INPUT,
+ "POSE",
+ 0,
+ "Pose",
+ "3D pose action, representing a controller's location and rotation"},
+ {XR_VIBRATION_OUTPUT,
+ "VIBRATION",
+ 0,
+ "Vibration",
+ "Haptic vibration output action, to be applied with a duration, frequency, and amplitude"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static const EnumPropertyItem rna_enum_xr_op_flags[] = {
+ {XR_OP_PRESS,
+ "PRESS",
+ 0,
+ "Press",
+ "Execute operator on button press (non-modal operators only)"},
+ {XR_OP_RELEASE,
+ "RELEASE",
+ 0,
+ "Release",
+ "Execute operator on button release (non-modal operators only)"},
+ {XR_OP_MODAL, "MODAL", 0, "Modal", "Use modal execution (modal operators only)"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static const EnumPropertyItem rna_enum_xr_haptic_flags[] = {
+ {XR_HAPTIC_PRESS, "PRESS", 0, "Press", "Apply haptics on button press"},
+ {XR_HAPTIC_RELEASE, "RELEASE", 0, "Release", "Apply haptics on button release"},
+ {XR_HAPTIC_PRESS | XR_HAPTIC_RELEASE,
+ "PRESS_RELEASE",
+ 0,
+ "Press Release",
+ "Apply haptics on button press and release"},
+ {XR_HAPTIC_REPEAT,
+ "REPEAT",
+ 0,
+ "Repeat",
+ "Apply haptics repeatedly for the duration of the button press"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static const EnumPropertyItem rna_enum_xr_axis0_flags[] = {
+ {0, "ANY", 0, "Any", "Use any axis region for operator execution"},
+ {XR_AXIS0_POS,
+ "POSITIVE",
+ 0,
+ "Positive",
+ "Use positive axis region only for operator execution"},
+ {XR_AXIS0_NEG,
+ "NEGATIVE",
+ 0,
+ "Negative",
+ "Use negative axis region only for operator execution"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+static const EnumPropertyItem rna_enum_xr_axis1_flags[] = {
+ {0, "ANY", 0, "Any", "Use any axis region for operator execution"},
+ {XR_AXIS1_POS,
+ "POSITIVE",
+ 0,
+ "Positive",
+ "Use positive axis region only for operator execution"},
+ {XR_AXIS1_NEG,
+ "NEGATIVE",
+ 0,
+ "Negative",
+ "Use negative axis region only for operator execution"},
+ {0, NULL, 0, NULL, NULL},
+};
+
+/* -------------------------------------------------------------------- */
+/** \name XR Action Map
+ * \{ */
+
+static void rna_def_xr_actionmap_bindings(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "XrActionMapBindings");
+ srna = RNA_def_struct(brna, "XrActionMapBindings", NULL);
+ RNA_def_struct_sdna(srna, "XrActionMapItem");
+ RNA_def_struct_ui_text(srna, "XR Action Map Bindings", "Collection of XR action map bindings");
+
+ func = RNA_def_function(srna, "new", "rna_XrActionMapBinding_new");
+ parm = RNA_def_string(func, "name", NULL, 0, "Name of the action map binding", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func,
+ "replace_existing",
+ true,
+ "Replace Existing",
+ "Replace any existing binding with the same name");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(
+ func, "binding", "XrActionMapBinding", "Binding", "Added action map binding");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "new_from_binding", "rna_XrActionMapBinding_new_from_binding");
+ parm = RNA_def_pointer(
+ func, "binding", "XrActionMapBinding", "Binding", "Binding to use as a reference");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(
+ func, "result", "XrActionMapBinding", "Binding", "Added action map binding");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_XrActionMapBinding_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "binding", "XrActionMapBinding", "Binding", "");
+ 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_XrActionMapBinding_find");
+ parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func,
+ "binding",
+ "XrActionMapBinding",
+ "Binding",
+ "The action map binding with the given name");
+ RNA_def_function_return(func, parm);
+}
+
+static void rna_def_xr_actionmap_items(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "XrActionMapItems");
+ srna = RNA_def_struct(brna, "XrActionMapItems", NULL);
+ RNA_def_struct_sdna(srna, "XrActionMap");
+ RNA_def_struct_ui_text(srna, "XR Action Map Items", "Collection of XR action map items");
+
+ func = RNA_def_function(srna, "new", "rna_XrActionMapItem_new");
+ parm = RNA_def_string(func, "name", NULL, 0, "Name of the action map item", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func,
+ "replace_existing",
+ true,
+ "Replace Existing",
+ "Replace any existing item with the same name");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "item", "XrActionMapItem", "Item", "Added action map item");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "new_from_item", "rna_XrActionMapItem_new_from_item");
+ parm = RNA_def_pointer(func, "item", "XrActionMapItem", "Item", "Item to use as a reference");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "result", "XrActionMapItem", "Item", "Added action map item");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_XrActionMapItem_remove");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+ parm = RNA_def_pointer(func, "item", "XrActionMapItem", "Item", "");
+ 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_XrActionMapItem_find");
+ parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(
+ func, "item", "XrActionMapItem", "Item", "The action map item with the given name");
+ RNA_def_function_return(func, parm);
+}
+
+static void rna_def_xr_actionmaps(BlenderRNA *brna, PropertyRNA *cprop)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ RNA_def_property_srna(cprop, "XrActionMaps");
+ srna = RNA_def_struct(brna, "XrActionMaps", NULL);
+ RNA_def_struct_sdna(srna, "wmXrData");
+ RNA_def_struct_ui_text(srna, "XR Action Maps", "Collection of XR action maps");
+
+ func = RNA_def_function(srna, "new", "rna_XrActionMap_new");
+ parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func,
+ "replace_existing",
+ true,
+ "Replace Existing",
+ "Replace any existing actionmap with the same name");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "actionmap", "XrActionMap", "Action Map", "Added action map");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "new_from_actionmap", "rna_XrActionMap_new_from_actionmap");
+ 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);
+ parm = RNA_def_pointer(func, "result", "XrActionMap", "Action Map", "Added action map");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "remove", "rna_XrActionMap_remove");
+ 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");
+ parm = RNA_def_string(func, "name", NULL, MAX_NAME, "Name", "");
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_pointer(
+ func, "actionmap", "XrActionMap", "Action Map", "The action map with the given name");
+ RNA_def_function_return(func, parm);
+}
+
+static void rna_def_xr_actionmap(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ PropertyRNA *prop;
+
+ /* XrActionMap */
+ srna = RNA_def_struct(brna, "XrActionMap", NULL);
+ RNA_def_struct_sdna(srna, "XrActionMap");
+ RNA_def_struct_ui_text(srna, "XR Action Map", "");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "Name of the action map");
+ RNA_def_property_update(prop, 0, "rna_XrActionMap_name_update");
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "actionmap_items", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_sdna(prop, NULL, "items", NULL);
+ RNA_def_property_struct_type(prop, "XrActionMapItem");
+ RNA_def_property_ui_text(
+ prop,
+ "Items",
+ "Items in the action map, mapping an XR event to an operator, pose, or haptic output");
+ 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_ui_text(prop, "Selected Item", "");
+
+ /* XrActionMapItem */
+ srna = RNA_def_struct(brna, "XrActionMapItem", NULL);
+ RNA_def_struct_sdna(srna, "XrActionMapItem");
+ RNA_def_struct_ui_text(srna, "XR Action Map Item", "");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "Name of the action map item");
+ RNA_def_property_update(prop, 0, "rna_XrActionMapItem_name_update");
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_xr_action_types);
+ RNA_def_property_ui_text(prop, "Type", "Action type");
+ RNA_def_property_update(prop, 0, "rna_XrActionMapItem_update");
+
+ prop = RNA_def_property(srna, "user_path0", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_maxlength(prop, 64);
+ RNA_def_property_ui_text(prop, "User Path 0", "OpenXR user path");
+
+ prop = RNA_def_property(srna, "user_path1", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_maxlength(prop, 64);
+ RNA_def_property_ui_text(prop, "User Path 1", "OpenXR user path");
+
+ prop = RNA_def_property(srna, "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");
+ RNA_def_property_update(prop, 0, "rna_XrActionMapItem_update");
+
+ prop = RNA_def_property(srna, "op_name", PROP_STRING, PROP_NONE);
+ RNA_def_property_clear_flag(prop, PROP_EDITABLE);
+ RNA_def_property_ui_text(
+ prop, "Operator Name", "Name of operator (translated) to call on action event");
+ RNA_def_property_string_funcs(
+ prop, "rna_XrActionMapItem_op_name_get", "rna_XrActionMapItem_op_name_length", NULL);
+
+ prop = RNA_def_property(srna, "op_properties", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "OperatorProperties");
+ RNA_def_property_pointer_funcs(prop, "rna_XrActionMapItem_op_properties_get", NULL, NULL, NULL);
+ RNA_def_property_ui_text(
+ prop, "Operator Properties", "Properties to set when the operator is called");
+ RNA_def_property_update(prop, 0, "rna_XrActionMapItem_update");
+
+ prop = RNA_def_property(srna, "op_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_sdna(prop, NULL, "op_flag");
+ RNA_def_property_enum_items(prop, rna_enum_xr_op_flags);
+ RNA_def_property_ui_text(prop, "Operator Mode", "Operator execution mode");
+
+ prop = RNA_def_property(srna, "bimanual", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(
+ prop, "rna_XrActionMapItem_bimanual_get", "rna_XrActionMapItem_bimanual_set");
+ RNA_def_property_ui_text(
+ prop, "Bimanual", "The action depends on the states/poses of both user paths");
+
+ prop = RNA_def_property(srna, "pose_is_controller_grip", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop,
+ "rna_XrActionMapItem_pose_is_controller_grip_get",
+ "rna_XrActionMapItem_pose_is_controller_grip_set");
+ RNA_def_property_ui_text(
+ prop, "Is Controller Grip", "The action poses will be used for the VR controller grips");
+
+ prop = RNA_def_property(srna, "pose_is_controller_aim", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop,
+ "rna_XrActionMapItem_pose_is_controller_aim_get",
+ "rna_XrActionMapItem_pose_is_controller_aim_set");
+ 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, "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");
+
+ prop = RNA_def_property(srna, "haptic_match_user_paths", PROP_BOOLEAN, PROP_NONE);
+ RNA_def_property_boolean_funcs(prop,
+ "rna_XrActionMapItem_haptic_match_user_paths_get",
+ "rna_XrActionMapItem_haptic_match_user_paths_set");
+ RNA_def_property_ui_text(
+ prop,
+ "Haptic Match User Paths",
+ "Apply haptics to the same user paths for the haptic action and this action");
+
+ prop = RNA_def_property(srna, "haptic_duration", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_text(prop,
+ "Haptic Duration",
+ "Haptic duration in seconds. 0.0 is the minimum supported duration");
+
+ prop = RNA_def_property(srna, "haptic_frequency", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, FLT_MAX);
+ RNA_def_property_ui_text(prop,
+ "Haptic Frequency",
+ "Frequency of the haptic vibration in hertz. 0.0 specifies the OpenXR "
+ "runtime's default frequency");
+
+ prop = RNA_def_property(srna, "haptic_amplitude", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_text(
+ prop, "Haptic Amplitude", "Intensity of the haptic vibration, ranging from 0.0 to 1.0");
+
+ prop = RNA_def_property(srna, "haptic_mode", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_xr_haptic_flags);
+ RNA_def_property_enum_funcs(
+ prop, "rna_XrActionMapItem_haptic_flag_get", "rna_XrActionMapItem_haptic_flag_set", NULL);
+ RNA_def_property_ui_text(prop, "Haptic mode", "Haptic application mode");
+
+ prop = RNA_def_property(srna, "bindings", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_struct_type(prop, "XrActionMapBinding");
+ RNA_def_property_ui_text(
+ prop, "Bindings", "Bindings for the action map item, mapping the action to an XR input");
+ rna_def_xr_actionmap_bindings(brna, prop);
+
+ prop = RNA_def_property(srna, "selected_binding", PROP_INT, PROP_NONE);
+ RNA_def_property_int_sdna(prop, NULL, "selbinding");
+ RNA_def_property_ui_text(prop, "Selected Binding", "Currently selected binding");
+
+ /* XrActionMapBinding */
+ srna = RNA_def_struct(brna, "XrActionMapBinding", NULL);
+ RNA_def_struct_sdna(srna, "XrActionMapBinding");
+ RNA_def_struct_ui_text(srna, "XR Action Map Binding", "Binding in an XR action map item");
+
+ prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Name", "Name of the action map binding");
+ RNA_def_property_update(prop, 0, "rna_XrActionMapBinding_name_update");
+ RNA_def_struct_name_property(srna, prop);
+
+ prop = RNA_def_property(srna, "profile", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_maxlength(prop, 256);
+ RNA_def_property_ui_text(prop, "Profile", "OpenXR interaction profile path");
+
+ prop = RNA_def_property(srna, "component_path0", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_maxlength(prop, 192);
+ RNA_def_property_ui_text(prop, "Component Path 0", "OpenXR component path");
+
+ prop = RNA_def_property(srna, "component_path1", PROP_STRING, PROP_NONE);
+ RNA_def_property_string_maxlength(prop, 192);
+ RNA_def_property_ui_text(prop, "Component Path 1", "OpenXR component path");
+
+ prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_NONE);
+ RNA_def_property_float_sdna(prop, NULL, "float_threshold");
+ RNA_def_property_range(prop, 0.0, 1.0);
+ RNA_def_property_ui_text(prop, "Threshold", "Input threshold for button/axis actions");
+
+ prop = RNA_def_property(srna, "axis0_region", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_xr_axis0_flags);
+ RNA_def_property_enum_funcs(prop,
+ "rna_XrActionMapBinding_axis0_flag_get",
+ "rna_XrActionMapBinding_axis0_flag_set",
+ NULL);
+ RNA_def_property_ui_text(
+ prop, "Axis 0 Region", "Action execution region for the first input axis");
+
+ prop = RNA_def_property(srna, "axis1_region", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, rna_enum_xr_axis1_flags);
+ RNA_def_property_enum_funcs(prop,
+ "rna_XrActionMapBinding_axis1_flag_get",
+ "rna_XrActionMapBinding_axis1_flag_set",
+ NULL);
+ RNA_def_property_ui_text(
+ prop, "Axis 1 Region", "Action execution region for the second input axis");
+
+ prop = RNA_def_property(srna, "pose_location", PROP_FLOAT, PROP_TRANSLATION);
+ RNA_def_property_ui_text(prop, "Pose Location Offset", "");
+
+ prop = RNA_def_property(srna, "pose_rotation", PROP_FLOAT, PROP_EULER);
+ RNA_def_property_ui_text(prop, "Pose Rotation Offset", "");
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Session Settings
+ * \{ */
+
static void rna_def_xr_session_settings(BlenderRNA *brna)
{
StructRNA *srna;
@@ -241,6 +1484,12 @@ static void rna_def_xr_session_settings(BlenderRNA *brna)
RNA_def_property_update(prop, NC_WM | ND_XR_DATA_CHANGED, NULL);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name XR Session State
+ * \{ */
+
static void rna_def_xr_session_state(BlenderRNA *brna)
{
StructRNA *srna;
@@ -265,6 +1514,260 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
parm = RNA_def_pointer(func, "context", "Context", "", "");
RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ func = RNA_def_function(srna, "action_set_create", "rna_XrSessionState_action_set_create");
+ RNA_def_function_ui_description(func, "Create a VR action set");
+ 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_pointer(func, "actionmap", "XrActionMap", "", "");
+ 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_create", "rna_XrSessionState_action_create");
+ RNA_def_function_ui_description(func, "Create a VR action");
+ 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_pointer(func, "actionmap", "XrActionMap", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "actionmap_item", "XrActionMapItem", "", "");
+ 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_binding_create", "rna_XrSessionState_action_binding_create");
+ RNA_def_function_ui_description(func, "Create a VR action binding");
+ 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_pointer(func, "actionmap", "XrActionMap", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "actionmap_item", "XrActionMapItem", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_pointer(func, "actionmap_binding", "XrActionMapBinding", "", "");
+ 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, "active_action_set_set", "rna_XrSessionState_active_action_set_set");
+ RNA_def_function_ui_description(func, "Set the active VR action set");
+ RNA_def_function_flag(func, FUNC_NO_SELF);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func, "action_set", NULL, 64, "Action Set", "Action set name");
+ 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, "controller_pose_actions_set", "rna_XrSessionState_controller_pose_actions_set");
+ RNA_def_function_ui_description(func, "Set the actions that determine the VR controller poses");
+ RNA_def_function_flag(func, FUNC_NO_SELF);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func, "action_set", NULL, 64, "Action Set", "Action set name");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func,
+ "grip_action",
+ NULL,
+ 64,
+ "Grip Action",
+ "Name of the action representing the controller grips");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func,
+ "aim_action",
+ NULL,
+ 64,
+ "Aim Action",
+ "Name of the action representing the controller aims");
+ 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);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func, "action_set_name", NULL, 64, "Action Set", "Action set name");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func, "action_name", NULL, 64, "Action", "Action name");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func, "user_path", NULL, 64, "User Path", "OpenXR user path");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_float_array(
+ func,
+ "state",
+ 2,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Action State",
+ "Current state of the VR action. Second float value is only set for 2D vector type actions",
+ -FLT_MAX,
+ FLT_MAX);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_OUTPUT);
+
+ func = RNA_def_function(srna, "haptic_action_apply", "rna_XrSessionState_haptic_action_apply");
+ RNA_def_function_ui_description(func, "Apply a VR haptic action");
+ RNA_def_function_flag(func, FUNC_NO_SELF);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func, "action_set_name", NULL, 64, "Action Set", "Action set name");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func, "action_name", NULL, 64, "Action", "Action name");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(
+ func,
+ "user_path",
+ NULL,
+ 64,
+ "User Path",
+ "Optional OpenXR user path. If not set, the action will be applied to all paths");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_float(func,
+ "duration",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Duration",
+ "Haptic duration in seconds. 0.0 is the minimum supported duration",
+ 0.0f,
+ FLT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float(func,
+ "frequency",
+ 0.0f,
+ 0.0f,
+ FLT_MAX,
+ "Frequency",
+ "Frequency of the haptic vibration in hertz. 0.0 specifies the OpenXR "
+ "runtime's default frequency",
+ 0.0f,
+ FLT_MAX);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float(func,
+ "amplitude",
+ 1.0f,
+ 0.0f,
+ 1.0f,
+ "Amplitude",
+ "Haptic amplitude, ranging from 0.0 to 1.0",
+ 0.0f,
+ 1.0f);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_boolean(func, "result", 0, "Result", "");
+ RNA_def_function_return(func, parm);
+
+ func = RNA_def_function(srna, "haptic_action_stop", "rna_XrSessionState_haptic_action_stop");
+ RNA_def_function_ui_description(func, "Stop a VR haptic action");
+ RNA_def_function_flag(func, FUNC_NO_SELF);
+ parm = RNA_def_pointer(func, "context", "Context", "", "");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func, "action_set_name", NULL, 64, "Action Set", "Action set name");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(func, "action_name", NULL, 64, "Action", "Action name");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+ parm = RNA_def_string(
+ func,
+ "user_path",
+ NULL,
+ 64,
+ "User Path",
+ "Optional OpenXR user path. If not set, the action will be stopped for all paths");
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_REQUIRED);
+
+ func = RNA_def_function(
+ srna, "controller_grip_location_get", "rna_XrSessionState_controller_grip_location_get");
+ RNA_def_function_ui_description(func,
+ "Get the last known controller grip 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_int(func, "index", 0, 0, 255, "Index", "Controller index", 0, 255);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_float_translation(func,
+ "location",
+ 3,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Controller grip location",
+ -FLT_MAX,
+ FLT_MAX);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_OUTPUT);
+
+ func = RNA_def_function(
+ srna, "controller_grip_rotation_get", "rna_XrSessionState_controller_grip_rotation_get");
+ RNA_def_function_ui_description(
+ func, "Get the last known controller grip 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_int(func, "index", 0, 0, 255, "Index", "Controller index", 0, 255);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float_vector(func,
+ "rotation",
+ 4,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Rotation",
+ "Controller grip 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);
+
+ func = RNA_def_function(
+ srna, "controller_aim_location_get", "rna_XrSessionState_controller_aim_location_get");
+ RNA_def_function_ui_description(func,
+ "Get the last known controller aim 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_int(func, "index", 0, 0, 255, "Index", "Controller index", 0, 255);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ RNA_def_float_translation(func,
+ "location",
+ 3,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Location",
+ "Controller aim location",
+ -FLT_MAX,
+ FLT_MAX);
+ RNA_def_parameter_flags(parm, PROP_NEVER_NULL, PARM_OUTPUT);
+
+ func = RNA_def_function(
+ srna, "controller_aim_rotation_get", "rna_XrSessionState_controller_aim_rotation_get");
+ RNA_def_function_ui_description(
+ func, "Get the last known controller aim 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_int(func, "index", 0, 0, 255, "Index", "Controller index", 0, 255);
+ RNA_def_parameter_flags(parm, 0, PARM_REQUIRED);
+ parm = RNA_def_float_vector(func,
+ "rotation",
+ 4,
+ NULL,
+ -FLT_MAX,
+ FLT_MAX,
+ "Rotation",
+ "Controller aim 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);
@@ -282,12 +1785,43 @@ static void rna_def_xr_session_state(BlenderRNA *brna)
prop,
"Viewer Pose Rotation",
"Last known rotation of the viewer pose (center between the eyes) in world space");
+
+ prop = RNA_def_property(srna, "actionmaps", PROP_COLLECTION, PROP_NONE);
+ RNA_def_property_collection_funcs(prop,
+ "rna_XrSessionState_actionmaps_begin",
+ "rna_iterator_listbase_next",
+ "rna_iterator_listbase_end",
+ "rna_iterator_listbase_get",
+ NULL,
+ 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_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", "");
}
+/** \} */
+
void RNA_def_xr(BlenderRNA *brna)
{
RNA_define_animate_sdna(false);
+ rna_def_xr_actionmap(brna);
rna_def_xr_session_settings(brna);
rna_def_xr_session_state(brna);
diff --git a/source/blender/windowmanager/CMakeLists.txt b/source/blender/windowmanager/CMakeLists.txt
index 8b0ceb02b5f..b7fbb9bb82b 100644
--- a/source/blender/windowmanager/CMakeLists.txt
+++ b/source/blender/windowmanager/CMakeLists.txt
@@ -204,6 +204,7 @@ if(WITH_XR_OPENXR)
list(APPEND SRC
xr/intern/wm_xr.c
xr/intern/wm_xr_action.c
+ xr/intern/wm_xr_actionmap.c
xr/intern/wm_xr_draw.c
xr/intern/wm_xr_session.c
diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h
index 7e26d921bd7..02e8d42e0ff 100644
--- a/source/blender/windowmanager/WM_api.h
+++ b/source/blender/windowmanager/WM_api.h
@@ -74,8 +74,7 @@ struct wmNDOFMotionData;
#endif
#ifdef WITH_XR_OPENXR
-struct wmXrActionState;
-struct wmXrPose;
+struct wmXrRuntimeData;
#endif
typedef struct wmGizmo wmGizmo;
@@ -988,7 +987,13 @@ bool WM_xr_action_create(wmXrData *xr,
const char **subaction_paths,
struct wmOperatorType *ot,
struct IDProperty *op_properties,
- eXrOpFlag op_flag);
+ const char **haptic_name,
+ const int64_t *haptic_duration,
+ const float *haptic_frequency,
+ const float *haptic_amplitude,
+ eXrOpFlag op_flag,
+ eXrActionFlag action_flag,
+ eXrHapticFlag haptic_flag);
void WM_xr_action_destroy(wmXrData *xr, const char *action_set_name, const char *action_name);
bool WM_xr_action_binding_create(wmXrData *xr,
const char *action_set_name,
@@ -1022,10 +1027,48 @@ bool WM_xr_action_state_get(const wmXrData *xr,
bool WM_xr_haptic_action_apply(wmXrData *xr,
const char *action_set_name,
const char *action_name,
+ const char **subaction_path,
const int64_t *duration,
const float *frequency,
const float *amplitude);
-void WM_xr_haptic_action_stop(wmXrData *xr, const char *action_set_name, const char *action_name);
+void WM_xr_haptic_action_stop(wmXrData *xr,
+ const char *action_set_name,
+ const char *action_name,
+ const char **subaction_path);
+
+/* wm_xr_actionmap.c */
+XrActionMap *WM_xr_actionmap_new(struct wmXrRuntimeData *runtime,
+ const char *name,
+ bool replace_existing);
+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);
+
+XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
+ const char *name,
+ bool replace_existing);
+void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami);
+XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src);
+bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami);
+XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *name);
+void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami);
+
+XrActionMapBinding *WM_xr_actionmap_binding_new(XrActionMapItem *ami,
+ const char *name,
+ bool replace_existing);
+void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb);
+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);
#endif /* WITH_XR_OPENXR */
#ifdef __cplusplus
diff --git a/source/blender/windowmanager/xr/intern/wm_xr.c b/source/blender/windowmanager/xr/intern/wm_xr.c
index 2a67c2bee9f..716a0936a24 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr.c
@@ -115,6 +115,7 @@ bool wm_xr_init(wmWindowManager *wm)
void wm_xr_exit(wmWindowManager *wm)
{
if (wm->xr.runtime != NULL) {
+ WM_xr_actionmaps_clear(wm->xr.runtime);
wm_xr_runtime_data_free(&wm->xr.runtime);
}
if (wm->xr.session_settings.shading.prop) {
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_action.c b/source/blender/windowmanager/xr/intern/wm_xr_action.c
index 8f2de4bbbad..2712fde51a8 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_action.c
+++ b/source/blender/windowmanager/xr/intern/wm_xr_action.c
@@ -23,6 +23,7 @@
* All functions are designed to be usable by RNA / the Python API.
*/
+#include "BLI_listbase.h"
#include "BLI_math.h"
#include "GHOST_C-api.h"
@@ -56,6 +57,9 @@ static void action_set_destroy(void *val)
MEM_SAFE_FREE(action_set->name);
+ BLI_freelistN(&action_set->active_modal_actions);
+ BLI_freelistN(&action_set->active_haptic_actions);
+
MEM_freeN(action_set);
}
@@ -70,7 +74,13 @@ static wmXrAction *action_create(const char *action_name,
const char **subaction_paths,
wmOperatorType *ot,
IDProperty *op_properties,
- eXrOpFlag op_flag)
+ const char **haptic_name,
+ const int64_t *haptic_duration,
+ const float *haptic_frequency,
+ const float *haptic_amplitude,
+ eXrOpFlag op_flag,
+ eXrActionFlag action_flag,
+ eXrHapticFlag haptic_flag)
{
wmXrAction *action = MEM_callocN(sizeof(*action), __func__);
action->name = MEM_mallocN(strlen(action_name) + 1, "XrAction_Name");
@@ -121,7 +131,19 @@ static wmXrAction *action_create(const char *action_name,
action->ot = ot;
action->op_properties = op_properties;
+
+ if (haptic_name) {
+ BLI_assert(is_button_action);
+ action->haptic_name = MEM_mallocN(strlen(*haptic_name) + 1, "XrAction_HapticName");
+ strcpy(action->haptic_name, *haptic_name);
+ action->haptic_duration = *haptic_duration;
+ action->haptic_frequency = *haptic_frequency;
+ action->haptic_amplitude = *haptic_amplitude;
+ }
+
action->op_flag = op_flag;
+ action->action_flag = action_flag;
+ action->haptic_flag = haptic_flag;
return action;
}
@@ -147,6 +169,8 @@ static void action_destroy(void *val)
MEM_SAFE_FREE(action->float_thresholds);
MEM_SAFE_FREE(action->axis_flags);
+ MEM_SAFE_FREE(action->haptic_name);
+
MEM_freeN(action);
}
@@ -190,9 +214,10 @@ void WM_xr_action_set_destroy(wmXrData *xr, const char *action_set_name)
wm_xr_session_controller_data_clear(session_state);
action_set->controller_grip_action = action_set->controller_aim_action = NULL;
}
- if (action_set->active_modal_action) {
- action_set->active_modal_action = NULL;
- }
+
+ BLI_freelistN(&action_set->active_modal_actions);
+ BLI_freelistN(&action_set->active_haptic_actions);
+
session_state->active_action_set = NULL;
}
@@ -207,14 +232,31 @@ bool WM_xr_action_create(wmXrData *xr,
const char **subaction_paths,
wmOperatorType *ot,
IDProperty *op_properties,
- eXrOpFlag op_flag)
+ const char **haptic_name,
+ const int64_t *haptic_duration,
+ const float *haptic_frequency,
+ const float *haptic_amplitude,
+ eXrOpFlag op_flag,
+ eXrActionFlag action_flag,
+ eXrHapticFlag haptic_flag)
{
if (action_find(xr, action_set_name, action_name)) {
return false;
}
- wmXrAction *action = action_create(
- action_name, type, count_subaction_paths, subaction_paths, ot, op_properties, op_flag);
+ wmXrAction *action = action_create(action_name,
+ type,
+ count_subaction_paths,
+ subaction_paths,
+ ot,
+ op_properties,
+ haptic_name,
+ haptic_duration,
+ haptic_frequency,
+ haptic_amplitude,
+ op_flag,
+ action_flag,
+ haptic_flag);
GHOST_XrActionInfo info = {
.name = action_name,
@@ -274,9 +316,18 @@ 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;
}
- if (action_set->active_modal_action &&
- STREQ(action_set->active_modal_action->name, action_name)) {
- action_set->active_modal_action = NULL;
+ LISTBASE_FOREACH (LinkData *, ld, &action_set->active_modal_actions) {
+ wmXrAction *active_modal_action = ld->data;
+ if (STREQ(active_modal_action->name, action_name)) {
+ BLI_freelinkN(&action_set->active_modal_actions, ld);
+ break;
+ }
+ }
+
+ LISTBASE_FOREACH_MUTABLE (wmXrHapticAction *, ha, &action_set->active_haptic_actions) {
+ if (STREQ(ha->action->name, action_name)) {
+ BLI_freelinkN(&action_set->active_haptic_actions, ha);
+ }
}
GHOST_XrDestroyActions(xr->runtime->context, action_set_name, 1, &action_name);
@@ -342,16 +393,11 @@ bool WM_xr_active_action_set_set(wmXrData *xr, const char *action_set_name)
}
{
- /* Unset active modal action (if any). */
+ /* Clear any active modal/haptic actions. */
wmXrActionSet *active_action_set = xr->runtime->session_state.active_action_set;
if (active_action_set) {
- wmXrAction *active_modal_action = active_action_set->active_modal_action;
- if (active_modal_action) {
- if (active_modal_action->active_modal_path) {
- active_modal_action->active_modal_path = NULL;
- }
- active_action_set->active_modal_action = NULL;
- }
+ BLI_freelistN(&active_action_set->active_modal_actions);
+ BLI_freelistN(&active_action_set->active_haptic_actions);
}
}
@@ -456,19 +502,28 @@ bool WM_xr_action_state_get(const wmXrData *xr,
bool WM_xr_haptic_action_apply(wmXrData *xr,
const char *action_set_name,
const char *action_name,
+ const char **subaction_path,
const int64_t *duration,
const float *frequency,
const float *amplitude)
{
- return GHOST_XrApplyHapticAction(
- xr->runtime->context, action_set_name, action_name, duration, frequency, amplitude) ?
+ return GHOST_XrApplyHapticAction(xr->runtime->context,
+ action_set_name,
+ action_name,
+ subaction_path,
+ duration,
+ frequency,
+ amplitude) ?
true :
false;
}
-void WM_xr_haptic_action_stop(wmXrData *xr, const char *action_set_name, const char *action_name)
+void WM_xr_haptic_action_stop(wmXrData *xr,
+ const char *action_set_name,
+ const char *action_name,
+ const char **subaction_path)
{
- GHOST_XrStopHapticAction(xr->runtime->context, action_set_name, action_name);
+ GHOST_XrStopHapticAction(xr->runtime->context, action_set_name, action_name, subaction_path);
}
/** \} */ /* XR-Action API */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
new file mode 100644
index 00000000000..7673f2aa212
--- /dev/null
+++ b/source/blender/windowmanager/xr/intern/wm_xr_actionmap.c
@@ -0,0 +1,565 @@
+/*
+ * 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 Action Maps
+ *
+ * XR actionmap API, similar to WM keymap API.
+ */
+
+#include <math.h>
+#include <string.h>
+
+#include "BKE_context.h"
+#include "BKE_idprop.h"
+
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+
+#include "GHOST_Types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+#include "wm_xr_intern.h"
+
+#define WM_XR_ACTIONMAP_STR_DEFAULT "actionmap"
+#define WM_XR_ACTIONMAP_ITEM_STR_DEFAULT "action"
+#define WM_XR_ACTIONMAP_BINDING_STR_DEFAULT "binding"
+
+/* -------------------------------------------------------------------- */
+/** \name Action Map Binding
+ *
+ * Binding in an XR action map item, that maps an action to an XR input.
+ * \{ */
+
+XrActionMapBinding *WM_xr_actionmap_binding_new(XrActionMapItem *ami,
+ const char *name,
+ bool replace_existing)
+{
+ XrActionMapBinding *amb_prev = WM_xr_actionmap_binding_find(ami, name);
+ if (amb_prev && replace_existing) {
+ return amb_prev;
+ }
+
+ XrActionMapBinding *amb = MEM_callocN(sizeof(XrActionMapBinding), __func__);
+ BLI_strncpy(amb->name, name, MAX_NAME);
+ if (amb_prev) {
+ WM_xr_actionmap_binding_ensure_unique(ami, amb);
+ }
+
+ BLI_addtail(&ami->bindings, amb);
+
+ /* Set non-zero threshold by default. */
+ amb->float_threshold = 0.3f;
+
+ return amb;
+}
+
+static XrActionMapBinding *wm_xr_actionmap_binding_find_except(XrActionMapItem *ami,
+ const char *name,
+ XrActionMapBinding *ambexcept)
+{
+ LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) {
+ if (STREQLEN(name, amb->name, MAX_NAME) && (amb != ambexcept)) {
+ return amb;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Ensure unique name among all action map bindings.
+ */
+void WM_xr_actionmap_binding_ensure_unique(XrActionMapItem *ami, XrActionMapBinding *amb)
+{
+ char name[MAX_NAME];
+ char *suffix;
+ size_t baselen;
+ size_t idx = 0;
+
+ BLI_strncpy(name, amb->name, MAX_NAME);
+ baselen = BLI_strnlen(name, MAX_NAME);
+ suffix = &name[baselen];
+
+ while (wm_xr_actionmap_binding_find_except(ami, name, amb)) {
+ if ((baselen + 1) + (log10(++idx) + 1) > MAX_NAME) {
+ /* Use default base name. */
+ BLI_strncpy(name, WM_XR_ACTIONMAP_BINDING_STR_DEFAULT, MAX_NAME);
+ baselen = BLI_strnlen(name, MAX_NAME);
+ suffix = &name[baselen];
+ idx = 0;
+ }
+ else {
+ BLI_snprintf(suffix, MAX_NAME, "%zu", idx);
+ }
+ }
+
+ BLI_strncpy(amb->name, name, MAX_NAME);
+}
+
+static XrActionMapBinding *wm_xr_actionmap_binding_copy(XrActionMapBinding *amb_src)
+{
+ XrActionMapBinding *amb_dst = MEM_dupallocN(amb_src);
+
+ amb_dst->prev = amb_dst->next = NULL;
+
+ return amb_dst;
+}
+
+XrActionMapBinding *WM_xr_actionmap_binding_add_copy(XrActionMapItem *ami,
+ XrActionMapBinding *amb_src)
+{
+ XrActionMapBinding *amb_dst = wm_xr_actionmap_binding_copy(amb_src);
+
+ WM_xr_actionmap_binding_ensure_unique(ami, amb_dst);
+
+ BLI_addtail(&ami->bindings, amb_dst);
+
+ return amb_dst;
+}
+
+bool WM_xr_actionmap_binding_remove(XrActionMapItem *ami, XrActionMapBinding *amb)
+{
+ int idx = BLI_findindex(&ami->bindings, amb);
+
+ if (idx != -1) {
+ BLI_freelinkN(&ami->bindings, amb);
+
+ if (BLI_listbase_is_empty(&ami->bindings)) {
+ ami->selbinding = -1;
+ }
+ else {
+ if (idx <= ami->selbinding) {
+ if (--ami->selbinding < 0) {
+ ami->selbinding = 0;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+XrActionMapBinding *WM_xr_actionmap_binding_find(XrActionMapItem *ami, const char *name)
+{
+ LISTBASE_FOREACH (XrActionMapBinding *, amb, &ami->bindings) {
+ if (STREQLEN(name, amb->name, MAX_NAME)) {
+ return amb;
+ }
+ }
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Action Map Item
+ *
+ * Item in an XR action map, that maps an XR event to an operator, pose, or haptic output.
+ * \{ */
+
+static void wm_xr_actionmap_item_properties_set(XrActionMapItem *ami)
+{
+ WM_operator_properties_alloc(&(ami->op_properties_ptr), &(ami->op_properties), ami->op);
+ WM_operator_properties_sanitize(ami->op_properties_ptr, 1);
+}
+
+static void wm_xr_actionmap_item_properties_free(XrActionMapItem *ami)
+{
+ if (ami->op_properties_ptr) {
+ WM_operator_properties_free(ami->op_properties_ptr);
+ MEM_freeN(ami->op_properties_ptr);
+ ami->op_properties_ptr = NULL;
+ ami->op_properties = NULL;
+ }
+ else {
+ BLI_assert(ami->op_properties == NULL);
+ }
+}
+
+/**
+ * Similar to #wm_xr_actionmap_item_properties_set()
+ * but checks for the #eXrActionType and #wmOperatorType having changed.
+ */
+void WM_xr_actionmap_item_properties_update_ot(XrActionMapItem *ami)
+{
+ switch (ami->type) {
+ case XR_BOOLEAN_INPUT:
+ case XR_FLOAT_INPUT:
+ case XR_VECTOR2F_INPUT:
+ break;
+ case XR_POSE_INPUT:
+ case XR_VIBRATION_OUTPUT:
+ wm_xr_actionmap_item_properties_free(ami);
+ memset(ami->op, 0, sizeof(ami->op));
+ return;
+ }
+
+ if (ami->op[0] == 0) {
+ wm_xr_actionmap_item_properties_free(ami);
+ return;
+ }
+
+ if (ami->op_properties_ptr == NULL) {
+ wm_xr_actionmap_item_properties_set(ami);
+ }
+ else {
+ wmOperatorType *ot = WM_operatortype_find(ami->op, 0);
+ if (ot) {
+ if (ot->srna != ami->op_properties_ptr->type) {
+ /* Matches wm_xr_actionmap_item_properties_set() but doesn't alloc new ptr. */
+ WM_operator_properties_create_ptr(ami->op_properties_ptr, ot);
+ if (ami->op_properties) {
+ ami->op_properties_ptr->data = ami->op_properties;
+ }
+ WM_operator_properties_sanitize(ami->op_properties_ptr, 1);
+ }
+ }
+ else {
+ wm_xr_actionmap_item_properties_free(ami);
+ }
+ }
+}
+
+XrActionMapItem *WM_xr_actionmap_item_new(XrActionMap *actionmap,
+ const char *name,
+ bool replace_existing)
+{
+ XrActionMapItem *ami_prev = WM_xr_actionmap_item_find(actionmap, name);
+ if (ami_prev && replace_existing) {
+ wm_xr_actionmap_item_properties_free(ami_prev);
+ return ami_prev;
+ }
+
+ XrActionMapItem *ami = MEM_callocN(sizeof(XrActionMapItem), __func__);
+ BLI_strncpy(ami->name, name, MAX_NAME);
+ if (ami_prev) {
+ WM_xr_actionmap_item_ensure_unique(actionmap, ami);
+ }
+
+ BLI_addtail(&actionmap->items, ami);
+
+ /* Set type to float (button) input by default. */
+ ami->type = XR_FLOAT_INPUT;
+
+ return ami;
+}
+
+static XrActionMapItem *wm_xr_actionmap_item_find_except(XrActionMap *actionmap,
+ const char *name,
+ const XrActionMapItem *amiexcept)
+{
+ LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
+ if (STREQLEN(name, ami->name, MAX_NAME) && (ami != amiexcept)) {
+ return ami;
+ }
+ }
+ return NULL;
+}
+
+/**
+ * Ensure unique name among all action map items.
+ */
+void WM_xr_actionmap_item_ensure_unique(XrActionMap *actionmap, XrActionMapItem *ami)
+{
+ char name[MAX_NAME];
+ char *suffix;
+ size_t baselen;
+ size_t idx = 0;
+
+ BLI_strncpy(name, ami->name, MAX_NAME);
+ baselen = BLI_strnlen(name, MAX_NAME);
+ suffix = &name[baselen];
+
+ while (wm_xr_actionmap_item_find_except(actionmap, name, ami)) {
+ if ((baselen + 1) + (log10(++idx) + 1) > MAX_NAME) {
+ /* Use default base name. */
+ BLI_strncpy(name, WM_XR_ACTIONMAP_ITEM_STR_DEFAULT, MAX_NAME);
+ baselen = BLI_strnlen(name, MAX_NAME);
+ suffix = &name[baselen];
+ idx = 0;
+ }
+ else {
+ BLI_snprintf(suffix, MAX_NAME, "%zu", idx);
+ }
+ }
+
+ BLI_strncpy(ami->name, name, MAX_NAME);
+}
+
+static XrActionMapItem *wm_xr_actionmap_item_copy(XrActionMapItem *ami)
+{
+ XrActionMapItem *amin = MEM_dupallocN(ami);
+
+ amin->prev = amin->next = NULL;
+
+ if (amin->op_properties) {
+ amin->op_properties_ptr = MEM_callocN(sizeof(PointerRNA), "wmOpItemPtr");
+ WM_operator_properties_create(amin->op_properties_ptr, amin->op);
+
+ amin->op_properties = IDP_CopyProperty(amin->op_properties);
+ amin->op_properties_ptr->data = amin->op_properties;
+ }
+ else {
+ amin->op_properties = NULL;
+ amin->op_properties_ptr = NULL;
+ }
+
+ return amin;
+}
+
+XrActionMapItem *WM_xr_actionmap_item_add_copy(XrActionMap *actionmap, XrActionMapItem *ami_src)
+{
+ XrActionMapItem *ami_dst = wm_xr_actionmap_item_copy(ami_src);
+
+ WM_xr_actionmap_item_ensure_unique(actionmap, ami_dst);
+
+ BLI_addtail(&actionmap->items, ami_dst);
+
+ return ami_dst;
+}
+
+bool WM_xr_actionmap_item_remove(XrActionMap *actionmap, XrActionMapItem *ami)
+{
+ int idx = BLI_findindex(&actionmap->items, ami);
+
+ if (idx != -1) {
+ if (ami->op_properties_ptr) {
+ WM_operator_properties_free(ami->op_properties_ptr);
+ MEM_freeN(ami->op_properties_ptr);
+ }
+ BLI_freelinkN(&actionmap->items, ami);
+
+ if (BLI_listbase_is_empty(&actionmap->items)) {
+ actionmap->selitem = -1;
+ }
+ else {
+ if (idx <= actionmap->selitem) {
+ if (--actionmap->selitem < 0) {
+ actionmap->selitem = 0;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+XrActionMapItem *WM_xr_actionmap_item_find(XrActionMap *actionmap, const char *name)
+{
+ LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
+ if (STREQLEN(name, ami->name, MAX_NAME)) {
+ return ami;
+ }
+ }
+ return NULL;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Action Map
+ *
+ * List of XR action map items.
+ * \{ */
+
+XrActionMap *WM_xr_actionmap_new(wmXrRuntimeData *runtime, const char *name, bool replace_existing)
+{
+ XrActionMap *am_prev = WM_xr_actionmap_find(runtime, name);
+ if (am_prev && replace_existing) {
+ 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);
+ }
+
+ BLI_addtail(&runtime->actionmaps, am);
+
+ return am;
+}
+
+static XrActionMap *wm_xr_actionmap_find_except(wmXrRuntimeData *runtime,
+ const char *name,
+ const XrActionMap *am_except)
+{
+ LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
+ if (STREQLEN(name, am->name, MAX_NAME) && (am != am_except)) {
+ return am;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ * Ensure unique name among all action maps.
+ */
+void WM_xr_actionmap_ensure_unique(wmXrRuntimeData *runtime, XrActionMap *actionmap)
+{
+ char name[MAX_NAME];
+ char *suffix;
+ size_t baselen;
+ size_t idx = 0;
+
+ BLI_strncpy(name, actionmap->name, MAX_NAME);
+ baselen = BLI_strnlen(name, MAX_NAME);
+ suffix = &name[baselen];
+
+ while (wm_xr_actionmap_find_except(runtime, name, actionmap)) {
+ if ((baselen + 1) + (log10(++idx) + 1) > MAX_NAME) {
+ /* Use default base name. */
+ BLI_strncpy(name, WM_XR_ACTIONMAP_STR_DEFAULT, MAX_NAME);
+ baselen = BLI_strnlen(name, MAX_NAME);
+ suffix = &name[baselen];
+ idx = 0;
+ }
+ else {
+ BLI_snprintf(suffix, MAX_NAME, "%zu", idx);
+ }
+ }
+
+ BLI_strncpy(actionmap->name, name, MAX_NAME);
+}
+
+static XrActionMap *wm_xr_actionmap_copy(XrActionMap *am_src)
+{
+ XrActionMap *am_dst = MEM_dupallocN(am_src);
+
+ am_dst->prev = am_dst->next = NULL;
+ BLI_listbase_clear(&am_dst->items);
+
+ LISTBASE_FOREACH (XrActionMapItem *, ami, &am_src->items) {
+ XrActionMapItem *ami_new = wm_xr_actionmap_item_copy(ami);
+ BLI_addtail(&am_dst->items, ami_new);
+ }
+
+ return am_dst;
+}
+
+XrActionMap *WM_xr_actionmap_add_copy(wmXrRuntimeData *runtime, XrActionMap *am_src)
+{
+ XrActionMap *am_dst = wm_xr_actionmap_copy(am_src);
+
+ WM_xr_actionmap_ensure_unique(runtime, am_dst);
+
+ BLI_addtail(&runtime->actionmaps, am_dst);
+
+ return am_dst;
+}
+
+bool WM_xr_actionmap_remove(wmXrRuntimeData *runtime, XrActionMap *actionmap)
+{
+ int idx = BLI_findindex(&runtime->actionmaps, actionmap);
+
+ if (idx != -1) {
+ WM_xr_actionmap_clear(actionmap);
+ BLI_freelinkN(&runtime->actionmaps, actionmap);
+
+ if (BLI_listbase_is_empty(&runtime->actionmaps)) {
+ runtime->actactionmap = runtime->selactionmap = -1;
+ }
+ else {
+ if (idx <= runtime->actactionmap) {
+ if (--runtime->actactionmap < 0) {
+ runtime->actactionmap = 0;
+ }
+ }
+ if (idx <= runtime->selactionmap) {
+ if (--runtime->selactionmap < 0) {
+ runtime->selactionmap = 0;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+XrActionMap *WM_xr_actionmap_find(wmXrRuntimeData *runtime, const char *name)
+{
+ LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
+ if (STREQLEN(name, am->name, MAX_NAME)) {
+ return am;
+ }
+ }
+ return NULL;
+}
+
+void WM_xr_actionmap_clear(XrActionMap *actionmap)
+{
+ LISTBASE_FOREACH (XrActionMapItem *, ami, &actionmap->items) {
+ wm_xr_actionmap_item_properties_free(ami);
+ }
+
+ BLI_freelistN(&actionmap->items);
+
+ actionmap->selitem = -1;
+}
+
+void WM_xr_actionmaps_clear(wmXrRuntimeData *runtime)
+{
+ LISTBASE_FOREACH (XrActionMap *, am, &runtime->actionmaps) {
+ WM_xr_actionmap_clear(am);
+ }
+
+ BLI_freelistN(&runtime->actionmaps);
+
+ runtime->actactionmap = runtime->selactionmap = -1;
+}
+
+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)
+{
+ BLI_assert(idx < BLI_listbase_count(&runtime->actionmaps));
+ 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)
+{
+ BLI_assert(idx < BLI_listbase_count(&runtime->actionmaps));
+ runtime->selactionmap = idx;
+}
+
+/** \} */
diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
index b6aff1f71f9..4b1605d0f68 100644
--- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h
+++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h
@@ -70,6 +70,10 @@ 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 {
@@ -99,6 +103,22 @@ typedef struct wmXrDrawData {
float eye_position_ofs[3]; /* Local/view space. */
} wmXrDrawData;
+typedef struct wmXrController {
+ struct wmXrController *next, *prev;
+ /** OpenXR path identifier. Length is dependent on OpenXR's XR_MAX_PATH_LENGTH (256).
+ This subaction path will later be combined with a component path, and that combined path should
+ also have a max of XR_MAX_PATH_LENGTH (e.g. subaction_path = /user/hand/left, component_path =
+ /input/trigger/value, interaction_path = /user/hand/left/input/trigger/value).
+ */
+ char subaction_path[64];
+ /* Pose (in world space) that represents the user's hand when holding the controller.*/
+ GHOST_XrPose grip_pose;
+ float grip_mat[4][4];
+ /* Pose (in world space) that represents the controller's aiming source. */
+ GHOST_XrPose aim_pose;
+ float aim_mat[4][4];
+} wmXrController;
+
typedef struct wmXrAction {
char *name;
eXrActionType type;
@@ -119,32 +139,37 @@ typedef struct wmXrAction {
/** Operator to be called on XR events. */
struct wmOperatorType *ot;
IDProperty *op_properties;
+
+ /** Haptics. */
+ char *haptic_name;
+ int64_t haptic_duration;
+ float haptic_frequency;
+ float haptic_amplitude;
+
+ /** Flags. */
eXrOpFlag op_flag;
+ eXrActionFlag action_flag;
+ eXrHapticFlag haptic_flag;
} wmXrAction;
-typedef struct wmXrController {
- struct wmXrController *next, *prev;
- /** OpenXR path identifier. Length is dependent on OpenXR's XR_MAX_PATH_LENGTH (256).
- This subaction path will later be combined with a component path, and that combined path should
- also have a max of XR_MAX_PATH_LENGTH (e.g. subaction_path = /user/hand/left, component_path =
- /input/trigger/value, interaction_path = /user/hand/left/input/trigger/value).
- */
- char subaction_path[64];
- /* Pose (in world space) that represents the user's hand when holding the controller.*/
- GHOST_XrPose grip_pose;
- float grip_mat[4][4];
- /* Pose (in world space) that represents the controller's aiming source. */
- GHOST_XrPose aim_pose;
- float aim_mat[4][4];
-} wmXrController;
+typedef struct wmXrHapticAction {
+ struct wmXrHapticAction *next, *prev;
+ wmXrAction *action;
+ const char **subaction_path;
+ int64_t time_start;
+} wmXrHapticAction;
typedef struct wmXrActionSet {
char *name;
+
/** XR pose actions that determine the controller grip/aim transforms. */
wmXrAction *controller_grip_action;
wmXrAction *controller_aim_action;
- /** The currently active modal action (if any). */
- wmXrAction *active_modal_action;
+
+ /** Currently active modal actions. */
+ ListBase active_modal_actions;
+ /** Currently active haptic actions. */
+ ListBase active_haptic_actions;
} wmXrActionSet;
wmXrRuntimeData *wm_xr_runtime_data_create(void);