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:
authorPeter Kim <pk15950@gmail.com>2021-08-05 17:40:17 +0300
committerPeter Kim <pk15950@gmail.com>2021-08-05 17:40:17 +0300
commite844e9e8f3bb6814e24749316003814156e2e2ce (patch)
tree3c3ef939b10a84b2de5c2f5fb2e713a0b49e3dca
parent0cff7c2a228589505bd2d66e966e5e84613b2786 (diff)
XR Controller Support Step 2: Action Maps
Addresses the remaining portions of T77137 (Python API for Controller Interaction), which was partially completed by D10942. Adds an XR "action maps" system for loading XR action data from a Python script. Action maps are accessible via the Python API, and are used to pass default actions to the VR session during the xr_session_start_pre() callback. Since action maps are stored only as runtime data, they will be cleaned up with the rest of the VR runtime data on file read or exit. Reviewed By: Julian Eisel, Hans Goudey Differential Revision: https://developer.blender.org/D10943
-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);