summaryrefslogtreecommitdiff
path: root/servers/xr
diff options
context:
space:
mode:
Diffstat (limited to 'servers/xr')
-rw-r--r--servers/xr/xr_interface.cpp130
-rw-r--r--servers/xr/xr_interface.h79
-rw-r--r--servers/xr/xr_interface_extension.cpp335
-rw-r--r--servers/xr/xr_interface_extension.h126
-rw-r--r--servers/xr/xr_pose.cpp110
-rw-r--r--servers/xr/xr_pose.h68
-rw-r--r--servers/xr/xr_positional_tracker.cpp269
-rw-r--r--servers/xr/xr_positional_tracker.h64
8 files changed, 927 insertions, 254 deletions
diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp
index e9858416ec..ca11df439c 100644
--- a/servers/xr/xr_interface.cpp
+++ b/servers/xr/xr_interface.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -29,31 +29,41 @@
/*************************************************************************/
#include "xr_interface.h"
+// #include "servers/rendering/renderer_compositor.h"
void XRInterface::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("play_area_changed", PropertyInfo(Variant::INT, "mode")));
+
ClassDB::bind_method(D_METHOD("get_name"), &XRInterface::get_name);
ClassDB::bind_method(D_METHOD("get_capabilities"), &XRInterface::get_capabilities);
ClassDB::bind_method(D_METHOD("is_primary"), &XRInterface::is_primary);
- ClassDB::bind_method(D_METHOD("set_is_primary", "enable"), &XRInterface::set_is_primary);
+ ClassDB::bind_method(D_METHOD("set_primary", "primary"), &XRInterface::set_primary);
ClassDB::bind_method(D_METHOD("is_initialized"), &XRInterface::is_initialized);
- ClassDB::bind_method(D_METHOD("set_is_initialized", "initialized"), &XRInterface::set_is_initialized);
ClassDB::bind_method(D_METHOD("initialize"), &XRInterface::initialize);
ClassDB::bind_method(D_METHOD("uninitialize"), &XRInterface::uninitialize);
ClassDB::bind_method(D_METHOD("get_tracking_status"), &XRInterface::get_tracking_status);
- ClassDB::bind_method(D_METHOD("get_render_targetsize"), &XRInterface::get_render_targetsize);
- ClassDB::bind_method(D_METHOD("is_stereo"), &XRInterface::is_stereo);
+ ClassDB::bind_method(D_METHOD("get_render_target_size"), &XRInterface::get_render_target_size);
+ ClassDB::bind_method(D_METHOD("get_view_count"), &XRInterface::get_view_count);
+
+ ClassDB::bind_method(D_METHOD("trigger_haptic_pulse", "action_name", "tracker_name", "frequency", "amplitude", "duration_sec", "delay_sec"), &XRInterface::trigger_haptic_pulse);
ADD_GROUP("Interface", "interface_");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_is_primary", "is_primary");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_initialized"), "set_is_initialized", "is_initialized");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_primary", "is_primary");
+
+ // methods and properties specific to VR...
+ ClassDB::bind_method(D_METHOD("supports_play_area_mode", "mode"), &XRInterface::supports_play_area_mode);
+ ClassDB::bind_method(D_METHOD("get_play_area_mode"), &XRInterface::get_play_area_mode);
+ ClassDB::bind_method(D_METHOD("set_play_area_mode", "mode"), &XRInterface::set_play_area_mode);
+ ClassDB::bind_method(D_METHOD("get_play_area"), &XRInterface::get_play_area);
- // we don't have any properties specific to VR yet....
+ ADD_GROUP("XR", "xr_");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "xr_play_area_mode", PROPERTY_HINT_ENUM, "Unknown,3DOF,Sitting,Roomscale,Stage"), "set_play_area_mode", "get_play_area_mode");
- // but we do have properties specific to AR....
+ // methods and properties specific to AR....
ClassDB::bind_method(D_METHOD("get_anchor_detection_is_enabled"), &XRInterface::get_anchor_detection_is_enabled);
ClassDB::bind_method(D_METHOD("set_anchor_detection_is_enabled", "enable"), &XRInterface::set_anchor_detection_is_enabled);
ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &XRInterface::get_camera_feed_id);
@@ -64,22 +74,22 @@ void XRInterface::_bind_methods() {
BIND_ENUM_CONSTANT(XR_NONE);
BIND_ENUM_CONSTANT(XR_MONO);
BIND_ENUM_CONSTANT(XR_STEREO);
+ BIND_ENUM_CONSTANT(XR_QUAD);
+ BIND_ENUM_CONSTANT(XR_VR);
BIND_ENUM_CONSTANT(XR_AR);
BIND_ENUM_CONSTANT(XR_EXTERNAL);
- BIND_ENUM_CONSTANT(EYE_MONO);
- BIND_ENUM_CONSTANT(EYE_LEFT);
- BIND_ENUM_CONSTANT(EYE_RIGHT);
-
BIND_ENUM_CONSTANT(XR_NORMAL_TRACKING);
BIND_ENUM_CONSTANT(XR_EXCESSIVE_MOTION);
BIND_ENUM_CONSTANT(XR_INSUFFICIENT_FEATURES);
BIND_ENUM_CONSTANT(XR_UNKNOWN_TRACKING);
BIND_ENUM_CONSTANT(XR_NOT_TRACKING);
-};
-StringName XRInterface::get_name() const {
- return "Unknown";
+ BIND_ENUM_CONSTANT(XR_PLAY_AREA_UNKNOWN);
+ BIND_ENUM_CONSTANT(XR_PLAY_AREA_3DOF);
+ BIND_ENUM_CONSTANT(XR_PLAY_AREA_SITTING);
+ BIND_ENUM_CONSTANT(XR_PLAY_AREA_ROOMSCALE);
+ BIND_ENUM_CONSTANT(XR_PLAY_AREA_STAGE);
};
bool XRInterface::is_primary() {
@@ -87,59 +97,79 @@ bool XRInterface::is_primary() {
ERR_FAIL_NULL_V(xr_server, false);
return xr_server->get_primary_interface() == this;
-};
+}
-void XRInterface::set_is_primary(bool p_is_primary) {
+void XRInterface::set_primary(bool p_primary) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- if (p_is_primary) {
+ if (p_primary) {
ERR_FAIL_COND(!is_initialized());
xr_server->set_primary_interface(this);
- } else {
- xr_server->clear_primary_interface_if(this);
- };
-};
+ } else if (xr_server->get_primary_interface() == this) {
+ xr_server->set_primary_interface(nullptr);
+ }
+}
-void XRInterface::set_is_initialized(bool p_initialized) {
- if (p_initialized) {
- if (!is_initialized()) {
- initialize();
- };
- } else {
- if (is_initialized()) {
- uninitialize();
- };
- };
-};
+XRInterface::XRInterface() {}
-XRInterface::Tracking_status XRInterface::get_tracking_status() const {
- return tracking_state;
-};
+XRInterface::~XRInterface() {}
-XRInterface::XRInterface() {
- tracking_state = XR_UNKNOWN_TRACKING;
-};
+// query if this interface supports this play area mode
+bool XRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
+ return p_mode == XR_PLAY_AREA_UNKNOWN;
+}
-XRInterface::~XRInterface() {}
+// get the current play area mode
+XRInterface::PlayAreaMode XRInterface::get_play_area_mode() const {
+ return XR_PLAY_AREA_UNKNOWN;
+}
-// optional render to external texture which enhances performance on those platforms that require us to submit our end result into special textures.
-unsigned int XRInterface::get_external_texture_for_eye(XRInterface::Eyes p_eye) {
- return 0;
+// change the play area mode, note that this should return false if the mode is not available
+bool XRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
+ return p_mode == XR_PLAY_AREA_UNKNOWN;
+}
+
+// if available, returns an array of vectors denoting the play area the player can move around in
+PackedVector3Array XRInterface::get_play_area() const {
+ // Return an empty array by default.
+ // Note implementation is responsible for applying our reference frame and world scale to the raw data.
+ // `play_area_changed` should be emitted if play area data is available and either the reference frame or world scale changes.
+ return PackedVector3Array();
};
/** these will only be implemented on AR interfaces, so we want dummies for VR **/
bool XRInterface::get_anchor_detection_is_enabled() const {
return false;
-};
+}
void XRInterface::set_anchor_detection_is_enabled(bool p_enable) {
- // don't do anything here, this needs to be implemented on AR interface to enable/disable things like plane detection etc.
}
int XRInterface::get_camera_feed_id() {
- // don't do anything here, this needs to be implemented on AR interface to enable/disable things like plane detection etc.
-
return 0;
-};
+}
+
+/** these are optional, so we want dummies **/
+PackedStringArray XRInterface::get_suggested_tracker_names() const {
+ PackedStringArray arr;
+
+ return arr;
+}
+
+PackedStringArray XRInterface::get_suggested_pose_names(const StringName &p_tracker_name) const {
+ PackedStringArray arr;
+
+ return arr;
+}
+
+XRInterface::TrackingStatus XRInterface::get_tracking_status() const {
+ return XR_UNKNOWN_TRACKING;
+}
+
+void XRInterface::notification(int p_what) {
+}
+
+void XRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
+}
diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h
index 99fcef7925..b489481f75 100644
--- a/servers/xr/xr_interface.h
+++ b/servers/xr/xr_interface.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,13 +33,15 @@
#include "core/math/camera_matrix.h"
#include "core/os/thread_safe.h"
-#include "scene/main/window.h"
#include "servers/xr_server.h"
+// forward declaration
+struct BlitToScreen;
+
/**
@author Bastiaan Olij <mux213@gmail.com>
- The XR interface is a template class ontop of which we build interface to different AR, VR and tracking SDKs.
+ The XR interface is a template class on top of which we build interface to different AR, VR and tracking SDKs.
The idea is that we subclass this class, implement the logic, and then instantiate a singleton of each interface
when Godot starts. These instances do not initialize themselves but register themselves with the AR/VR server.
@@ -48,25 +50,21 @@
Note that we may make this into a fully instantiable class for GDNative support.
*/
-class XRInterface : public Reference {
- GDCLASS(XRInterface, Reference);
+class XRInterface : public RefCounted {
+ GDCLASS(XRInterface, RefCounted);
public:
enum Capabilities { /* purely meta data, provides some info about what this interface supports */
XR_NONE = 0, /* no capabilities */
XR_MONO = 1, /* can be used with mono output */
XR_STEREO = 2, /* can be used with stereo output */
- XR_AR = 4, /* offers a camera feed for AR */
- XR_EXTERNAL = 8 /* renders to external device */
- };
-
- enum Eyes {
- EYE_MONO, /* my son says we should call this EYE_CYCLOPS */
- EYE_LEFT,
- EYE_RIGHT
+ XR_QUAD = 4, /* can be used with quad output (not currently supported) */
+ XR_VR = 8, /* offers VR support */
+ XR_AR = 16, /* offers AR support */
+ XR_EXTERNAL = 32 /* renders to external device */
};
- enum Tracking_status { /* tracking status currently based on AR but we can start doing more with this for VR as well */
+ enum TrackingStatus { /* tracking status currently based on AR but we can start doing more with this for VR as well */
XR_NORMAL_TRACKING,
XR_EXCESSIVE_MOTION,
XR_INSUFFICIENT_FEATURES,
@@ -74,29 +72,43 @@ public:
XR_NOT_TRACKING
};
+ enum PlayAreaMode { /* defines the mode used by the XR interface for tracking */
+ XR_PLAY_AREA_UNKNOWN, /* Area mode not set or not available */
+ XR_PLAY_AREA_3DOF, /* Only support orientation tracking, no positional tracking, area will center around player */
+ XR_PLAY_AREA_SITTING, /* Player is in seated position, limited positional tracking, fixed guardian around player */
+ XR_PLAY_AREA_ROOMSCALE, /* Player is free to move around, full positional tracking */
+ XR_PLAY_AREA_STAGE, /* Same as roomscale but origin point is fixed to the center of the physical space, XRServer.center_on_hmd disabled */
+ };
+
protected:
_THREAD_SAFE_CLASS_
- Tracking_status tracking_state;
static void _bind_methods();
public:
/** general interface information **/
- virtual StringName get_name() const;
- virtual int get_capabilities() const = 0;
+ virtual StringName get_name() const = 0;
+ virtual uint32_t get_capabilities() const = 0;
bool is_primary();
- void set_is_primary(bool p_is_primary);
+ void set_primary(bool p_is_primary);
virtual bool is_initialized() const = 0; /* returns true if we've initialized this interface */
- void set_is_initialized(bool p_initialized); /* helper function, will call initialize or uninitialize */
virtual bool initialize() = 0; /* initialize this interface, if this has an HMD it becomes the primary interface */
virtual void uninitialize() = 0; /* deinitialize this interface */
- Tracking_status get_tracking_status() const; /* get the status of our current tracking */
+ /** input and output **/
+
+ virtual PackedStringArray get_suggested_tracker_names() const; /* return a list of likely/suggested tracker names */
+ virtual PackedStringArray get_suggested_pose_names(const StringName &p_tracker_name) const; /* return a list of likely/suggested action names for this tracker */
+ virtual TrackingStatus get_tracking_status() const; /* get the status of our current tracking */
+ virtual void trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0); /* trigger a haptic pulse */
/** specific to VR **/
- // nothing yet
+ virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode); /* query if this interface supports this play area mode */
+ virtual XRInterface::PlayAreaMode get_play_area_mode() const; /* get the current play area mode */
+ virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode); /* change the play area mode, note that this should return false if the mode is not available */
+ virtual PackedVector3Array get_play_area() const; /* if available, returns an array of vectors denoting the play area the player can move around in */
/** specific to AR **/
virtual bool get_anchor_detection_is_enabled() const;
@@ -105,22 +117,25 @@ public:
/** rendering and internal **/
- virtual Size2 get_render_targetsize() = 0; /* returns the recommended render target size per eye for this device */
- virtual bool is_stereo() = 0; /* returns true if this interface requires stereo rendering (for VR HMDs) or mono rendering (for mobile AR) */
- virtual Transform get_transform_for_eye(XRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */
- virtual CameraMatrix get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each eyes projection matrix */
- virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye); /* if applicable return external texture to render to */
- virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */
+ virtual Size2 get_render_target_size() = 0; /* returns the recommended render target size per eye for this device */
+ virtual uint32_t get_view_count() = 0; /* returns the view count we need (1 is monoscopic, 2 is stereoscopic but can be more) */
+ virtual Transform3D get_camera_transform() = 0; /* returns the position of our camera for updating our camera node. For monoscopic this is equal to the views transform, for stereoscopic this should be an average */
+ virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */
+ virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) = 0; /* get each view projection matrix */
+
+ // note, external color/depth/vrs texture support will be added here soon.
+
+ virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* commit rendered views to the XR interface */
virtual void process() = 0;
- virtual void notification(int p_what) = 0;
+ virtual void notification(int p_what);
XRInterface();
~XRInterface();
};
VARIANT_ENUM_CAST(XRInterface::Capabilities);
-VARIANT_ENUM_CAST(XRInterface::Eyes);
-VARIANT_ENUM_CAST(XRInterface::Tracking_status);
+VARIANT_ENUM_CAST(XRInterface::TrackingStatus);
+VARIANT_ENUM_CAST(XRInterface::PlayAreaMode);
-#endif
+#endif // !XR_INTERFACE_H
diff --git a/servers/xr/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp
new file mode 100644
index 0000000000..80576ac607
--- /dev/null
+++ b/servers/xr/xr_interface_extension.cpp
@@ -0,0 +1,335 @@
+/*************************************************************************/
+/* xr_interface_extension.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "xr_interface_extension.h"
+#include "servers/rendering/renderer_rd/renderer_storage_rd.h"
+#include "servers/rendering/renderer_storage.h"
+#include "servers/rendering/rendering_server_globals.h"
+
+void XRInterfaceExtension::_bind_methods() {
+ GDVIRTUAL_BIND(_get_name);
+ GDVIRTUAL_BIND(_get_capabilities);
+
+ GDVIRTUAL_BIND(_is_initialized);
+ GDVIRTUAL_BIND(_initialize);
+ GDVIRTUAL_BIND(_uninitialize);
+
+ GDVIRTUAL_BIND(_supports_play_area_mode, "mode");
+ GDVIRTUAL_BIND(_get_play_area_mode);
+ GDVIRTUAL_BIND(_set_play_area_mode, "mode");
+ GDVIRTUAL_BIND(_get_play_area);
+
+ GDVIRTUAL_BIND(_get_render_target_size);
+ GDVIRTUAL_BIND(_get_view_count);
+ GDVIRTUAL_BIND(_get_camera_transform);
+ GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform");
+ GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far");
+
+ GDVIRTUAL_BIND(_commit_views, "render_target", "screen_rect");
+
+ GDVIRTUAL_BIND(_process);
+ GDVIRTUAL_BIND(_notification, "what");
+
+ /** input and output **/
+
+ GDVIRTUAL_BIND(_get_suggested_tracker_names);
+ GDVIRTUAL_BIND(_get_suggested_pose_names, "tracker_name");
+ GDVIRTUAL_BIND(_get_tracking_status);
+ GDVIRTUAL_BIND(_trigger_haptic_pulse, "action_name", "tracker_name", "frequency", "amplitude", "duration_sec", "delay_sec");
+
+ // we don't have any properties specific to VR yet....
+
+ // but we do have properties specific to AR....
+ GDVIRTUAL_BIND(_get_anchor_detection_is_enabled);
+ GDVIRTUAL_BIND(_set_anchor_detection_is_enabled, "enabled");
+ GDVIRTUAL_BIND(_get_camera_feed_id);
+
+ // helper methods
+ ClassDB::bind_method(D_METHOD("add_blit", "render_target", "src_rect", "dst_rect", "use_layer", "layer", "apply_lens_distortion", "eye_center", "k1", "k2", "upscale", "aspect_ratio"), &XRInterfaceExtension::add_blit);
+ ClassDB::bind_method(D_METHOD("get_render_target_texture", "render_target"), &XRInterfaceExtension::get_render_target_texture);
+ // ClassDB::bind_method(D_METHOD("get_render_target_depth", "render_target"), &XRInterfaceExtension::get_render_target_depth);
+}
+
+StringName XRInterfaceExtension::get_name() const {
+ StringName name;
+
+ if (GDVIRTUAL_CALL(_get_name, name)) {
+ return name;
+ }
+
+ return "Unknown";
+}
+
+uint32_t XRInterfaceExtension::get_capabilities() const {
+ uint32_t capabilities;
+
+ if (GDVIRTUAL_CALL(_get_capabilities, capabilities)) {
+ return capabilities;
+ }
+
+ return 0;
+}
+
+bool XRInterfaceExtension::is_initialized() const {
+ bool initialised = false;
+
+ if (GDVIRTUAL_CALL(_is_initialized, initialised)) {
+ return initialised;
+ }
+
+ return false;
+}
+
+bool XRInterfaceExtension::initialize() {
+ bool initialised = false;
+
+ if (GDVIRTUAL_CALL(_initialize, initialised)) {
+ return initialised;
+ }
+
+ return false;
+}
+
+void XRInterfaceExtension::uninitialize() {
+ GDVIRTUAL_CALL(_uninitialize);
+}
+
+PackedStringArray XRInterfaceExtension::get_suggested_tracker_names() const {
+ PackedStringArray arr;
+
+ GDVIRTUAL_CALL(_get_suggested_tracker_names, arr);
+
+ return arr;
+}
+
+PackedStringArray XRInterfaceExtension::get_suggested_pose_names(const StringName &p_tracker_name) const {
+ PackedStringArray arr;
+
+ GDVIRTUAL_CALL(_get_suggested_pose_names, p_tracker_name, arr);
+
+ return arr;
+}
+
+XRInterface::TrackingStatus XRInterfaceExtension::get_tracking_status() const {
+ uint32_t status;
+
+ if (GDVIRTUAL_CALL(_get_tracking_status, status)) {
+ return TrackingStatus(status);
+ }
+
+ return XR_UNKNOWN_TRACKING;
+}
+
+void XRInterfaceExtension::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) {
+ GDVIRTUAL_CALL(_trigger_haptic_pulse, p_action_name, p_tracker_name, p_frequency, p_amplitude, p_duration_sec, p_delay_sec);
+}
+
+bool XRInterfaceExtension::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) {
+ bool is_supported;
+
+ if (GDVIRTUAL_CALL(_supports_play_area_mode, p_mode, is_supported)) {
+ return is_supported;
+ }
+
+ return false;
+}
+
+XRInterface::PlayAreaMode XRInterfaceExtension::get_play_area_mode() const {
+ uint32_t mode;
+
+ if (GDVIRTUAL_CALL(_get_play_area_mode, mode)) {
+ return XRInterface::PlayAreaMode(mode);
+ }
+
+ return XRInterface::XR_PLAY_AREA_UNKNOWN;
+}
+
+bool XRInterfaceExtension::set_play_area_mode(XRInterface::PlayAreaMode p_mode) {
+ bool success;
+
+ if (GDVIRTUAL_CALL(_set_play_area_mode, p_mode, success)) {
+ return success;
+ }
+
+ return false;
+}
+
+PackedVector3Array XRInterfaceExtension::get_play_area() const {
+ PackedVector3Array arr;
+
+ GDVIRTUAL_CALL(_get_play_area, arr);
+
+ return arr;
+}
+
+/** these will only be implemented on AR interfaces, so we want dummies for VR **/
+bool XRInterfaceExtension::get_anchor_detection_is_enabled() const {
+ bool enabled;
+
+ if (GDVIRTUAL_CALL(_get_anchor_detection_is_enabled, enabled)) {
+ return enabled;
+ }
+
+ return false;
+}
+
+void XRInterfaceExtension::set_anchor_detection_is_enabled(bool p_enable) {
+ // don't do anything here, this needs to be implemented on AR interface to enable/disable things like plane detection etc.
+ GDVIRTUAL_CALL(_set_anchor_detection_is_enabled, p_enable);
+}
+
+int XRInterfaceExtension::get_camera_feed_id() {
+ int feed_id;
+
+ if (GDVIRTUAL_CALL(_get_camera_feed_id, feed_id)) {
+ return feed_id;
+ }
+
+ return 0;
+}
+
+Size2 XRInterfaceExtension::get_render_target_size() {
+ Size2 size;
+
+ if (GDVIRTUAL_CALL(_get_render_target_size, size)) {
+ return size;
+ }
+
+ return Size2(0, 0);
+}
+
+uint32_t XRInterfaceExtension::get_view_count() {
+ uint32_t view_count;
+
+ if (GDVIRTUAL_CALL(_get_view_count, view_count)) {
+ return view_count;
+ }
+
+ return 1;
+}
+
+Transform3D XRInterfaceExtension::get_camera_transform() {
+ Transform3D transform;
+
+ if (GDVIRTUAL_CALL(_get_camera_transform, transform)) {
+ return transform;
+ }
+
+ return Transform3D();
+}
+
+Transform3D XRInterfaceExtension::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
+ Transform3D transform;
+
+ if (GDVIRTUAL_CALL(_get_transform_for_view, p_view, p_cam_transform, transform)) {
+ return transform;
+ }
+
+ return Transform3D();
+}
+
+CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) {
+ CameraMatrix cm;
+ PackedFloat64Array arr;
+
+ if (GDVIRTUAL_CALL(_get_projection_for_view, p_view, p_aspect, p_z_near, p_z_far, arr)) {
+ ERR_FAIL_COND_V_MSG(arr.size() != 16, CameraMatrix(), "Projection matrix must contain 16 floats");
+ real_t *m = (real_t *)cm.matrix;
+ for (int i = 0; i < 16; i++) {
+ m[i] = arr[i];
+ }
+ return cm;
+ }
+
+ return CameraMatrix();
+}
+
+void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, double p_k1, double p_k2, double p_upscale, double p_aspect_ratio) {
+ BlitToScreen blit;
+
+ ERR_FAIL_COND_MSG(!can_add_blits, "add_blit can only be called from an XR plugin from within _commit_views!");
+
+ blit.render_target = p_render_target;
+ blit.src_rect = p_src_rect;
+ blit.dst_rect = p_dst_rect;
+
+ blit.multi_view.use_layer = p_use_layer;
+ blit.multi_view.layer = p_layer;
+
+ blit.lens_distortion.apply = p_apply_lens_distortion;
+ blit.lens_distortion.eye_center = p_eye_center;
+ blit.lens_distortion.k1 = p_k1;
+ blit.lens_distortion.k2 = p_k2;
+ blit.lens_distortion.upscale = p_upscale;
+ blit.lens_distortion.aspect_ratio = p_aspect_ratio;
+
+ blits.push_back(blit);
+}
+
+Vector<BlitToScreen> XRInterfaceExtension::commit_views(RID p_render_target, const Rect2 &p_screen_rect) {
+ // This is just so our XR plugin can add blits...
+ blits.clear();
+ can_add_blits = true;
+
+ if (GDVIRTUAL_CALL(_commit_views, p_render_target, p_screen_rect)) {
+ return blits;
+ }
+
+ can_add_blits = false;
+ return blits;
+}
+
+void XRInterfaceExtension::process() {
+ GDVIRTUAL_CALL(_process);
+}
+
+void XRInterfaceExtension::notification(int p_what) {
+ GDVIRTUAL_CALL(_notification, p_what);
+}
+
+RID XRInterfaceExtension::get_render_target_texture(RID p_render_target) {
+ // In due time this will need to be enhance to return the correct INTERNAL RID for the chosen rendering engine.
+ // So once a GLES driver is implemented we'll return that and the implemented plugin needs to handle this correctly too.
+ RendererStorageRD *rd_storage = RendererStorageRD::base_singleton;
+ ERR_FAIL_NULL_V_MSG(rd_storage, RID(), "Renderer storage not setup");
+
+ return rd_storage->render_target_get_rd_texture(p_render_target);
+}
+
+/*
+RID XRInterfaceExtension::get_render_target_depth(RID p_render_target) {
+ // TODO implement this, the problem is that our depth texture isn't part of our render target as it is used for 3D rendering only
+ // but we don't have access to our render buffers from here....
+ RendererSceneRenderRD * rd_scene = ?????;
+ ERR_FAIL_NULL_V_MSG(rd_scene, RID(), "Renderer scene render not setup");
+
+ return rd_scene->render_buffers_get_depth_texture(????????????);
+}
+*/
diff --git a/servers/xr/xr_interface_extension.h b/servers/xr/xr_interface_extension.h
new file mode 100644
index 0000000000..763526de96
--- /dev/null
+++ b/servers/xr/xr_interface_extension.h
@@ -0,0 +1,126 @@
+/*************************************************************************/
+/* xr_interface_extension.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef XR_INTERFACE_EXTENSION_H
+#define XR_INTERFACE_EXTENSION_H
+
+#include "servers/xr/xr_interface.h"
+
+class XRInterfaceExtension : public XRInterface {
+ GDCLASS(XRInterfaceExtension, XRInterface);
+
+public:
+private:
+ bool can_add_blits = false;
+ Vector<BlitToScreen> blits;
+
+protected:
+ _THREAD_SAFE_CLASS_
+
+ static void _bind_methods();
+
+public:
+ /** general interface information **/
+ virtual StringName get_name() const override;
+ virtual uint32_t get_capabilities() const override;
+
+ GDVIRTUAL0RC(StringName, _get_name);
+ GDVIRTUAL0RC(uint32_t, _get_capabilities);
+
+ virtual bool is_initialized() const override;
+ virtual bool initialize() override;
+ virtual void uninitialize() override;
+
+ GDVIRTUAL0RC(bool, _is_initialized);
+ GDVIRTUAL0R(bool, _initialize);
+ GDVIRTUAL0(_uninitialize);
+
+ /** input and output **/
+
+ virtual PackedStringArray get_suggested_tracker_names() const override; /* return a list of likely/suggested tracker names */
+ virtual PackedStringArray get_suggested_pose_names(const StringName &p_tracker_name) const override; /* return a list of likely/suggested action names for this tracker */
+ virtual TrackingStatus get_tracking_status() const override;
+ virtual void trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0) override;
+
+ GDVIRTUAL0RC(PackedStringArray, _get_suggested_tracker_names);
+ GDVIRTUAL1RC(PackedStringArray, _get_suggested_pose_names, const StringName &);
+ GDVIRTUAL0RC(uint32_t, _get_tracking_status);
+ GDVIRTUAL6(_trigger_haptic_pulse, const String &, const StringName &, double, double, double, double);
+
+ /** specific to VR **/
+ virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override; /* query if this interface supports this play area mode */
+ virtual XRInterface::PlayAreaMode get_play_area_mode() const override; /* get the current play area mode */
+ virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override; /* change the play area mode, note that this should return false if the mode is not available */
+ virtual PackedVector3Array get_play_area() const override; /* if available, returns an array of vectors denoting the play area the player can move around in */
+
+ GDVIRTUAL1RC(bool, _supports_play_area_mode, XRInterface::PlayAreaMode);
+ GDVIRTUAL0RC(uint32_t, _get_play_area_mode);
+ GDVIRTUAL1RC(bool, _set_play_area_mode, uint32_t);
+ GDVIRTUAL0RC(PackedVector3Array, _get_play_area);
+
+ /** specific to AR **/
+ virtual bool get_anchor_detection_is_enabled() const override;
+ virtual void set_anchor_detection_is_enabled(bool p_enable) override;
+ virtual int get_camera_feed_id() override;
+
+ GDVIRTUAL0RC(bool, _get_anchor_detection_is_enabled);
+ GDVIRTUAL1(_set_anchor_detection_is_enabled, bool);
+ GDVIRTUAL0RC(int, _get_camera_feed_id);
+
+ /** rendering and internal **/
+
+ virtual Size2 get_render_target_size() override;
+ virtual uint32_t get_view_count() override;
+ virtual Transform3D get_camera_transform() override;
+ virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
+ virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override;
+
+ GDVIRTUAL0R(Size2, _get_render_target_size);
+ GDVIRTUAL0R(uint32_t, _get_view_count);
+ GDVIRTUAL0R(Transform3D, _get_camera_transform);
+ GDVIRTUAL2R(Transform3D, _get_transform_for_view, uint32_t, const Transform3D &);
+ GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, double, double, double);
+
+ void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), double p_k1 = 0.0, double p_k2 = 0.0, double p_upscale = 1.0, double p_aspect_ratio = 1.0);
+ virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
+ GDVIRTUAL2(_commit_views, RID, const Rect2 &);
+
+ virtual void process() override;
+ virtual void notification(int p_what) override;
+
+ GDVIRTUAL0(_process);
+ GDVIRTUAL1(_notification, int);
+
+ /* access to some internals we need */
+ RID get_render_target_texture(RID p_render_target);
+ // RID get_render_target_depth(RID p_render_target);
+};
+
+#endif // !XR_INTERFACE_EXTENSION_H
diff --git a/servers/xr/xr_pose.cpp b/servers/xr/xr_pose.cpp
new file mode 100644
index 0000000000..0d05e62b46
--- /dev/null
+++ b/servers/xr/xr_pose.cpp
@@ -0,0 +1,110 @@
+/*************************************************************************/
+/* xr_pose.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#include "xr_pose.h"
+
+#include "servers/xr_server.h"
+
+void XRPose::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_has_tracking_data", "has_tracking_data"), &XRPose::set_has_tracking_data);
+ ClassDB::bind_method(D_METHOD("get_has_tracking_data"), &XRPose::get_has_tracking_data);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "has_tracking_data"), "set_has_tracking_data", "get_has_tracking_data");
+
+ ClassDB::bind_method(D_METHOD("set_name", "name"), &XRPose::set_name);
+ ClassDB::bind_method(D_METHOD("get_name"), &XRPose::get_name);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_name", "get_name");
+
+ ClassDB::bind_method(D_METHOD("set_transform", "transform"), &XRPose::set_transform);
+ ClassDB::bind_method(D_METHOD("get_transform"), &XRPose::get_transform);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "transform"), "set_transform", "get_transform");
+ ClassDB::bind_method(D_METHOD("get_adjusted_transform"), &XRPose::get_adjusted_transform);
+
+ ClassDB::bind_method(D_METHOD("set_linear_velocity", "velocity"), &XRPose::set_linear_velocity);
+ ClassDB::bind_method(D_METHOD("get_linear_velocity"), &XRPose::get_linear_velocity);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "linear_velocity"), "set_linear_velocity", "get_linear_velocity");
+
+ ClassDB::bind_method(D_METHOD("set_angular_velocity", "velocity"), &XRPose::set_angular_velocity);
+ ClassDB::bind_method(D_METHOD("get_angular_velocity"), &XRPose::get_angular_velocity);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "angular_velocity"), "set_angular_velocity", "get_angular_velocity");
+}
+
+void XRPose::set_has_tracking_data(const bool p_has_tracking_data) {
+ has_tracking_data = p_has_tracking_data;
+}
+bool XRPose::get_has_tracking_data() const {
+ return has_tracking_data;
+}
+
+void XRPose::set_name(const StringName &p_name) {
+ name = p_name;
+}
+
+StringName XRPose::get_name() const {
+ return name;
+}
+
+void XRPose::set_transform(const Transform3D p_transform) {
+ transform = p_transform;
+}
+
+Transform3D XRPose::get_transform() const {
+ return transform;
+}
+
+Transform3D XRPose::get_adjusted_transform() const {
+ Transform3D adjusted_transform = transform;
+
+ XRServer *xr_server = XRServer::get_singleton();
+ ERR_FAIL_NULL_V(xr_server, transform);
+
+ // apply world scale
+ adjusted_transform.origin *= xr_server->get_world_scale();
+
+ // apply reference frame
+ adjusted_transform = xr_server->get_reference_frame() * adjusted_transform;
+
+ return adjusted_transform;
+}
+
+void XRPose::set_linear_velocity(const Vector3 p_velocity) {
+ linear_velocity = p_velocity;
+}
+
+Vector3 XRPose::get_linear_velocity() const {
+ return linear_velocity;
+}
+
+void XRPose::set_angular_velocity(const Vector3 p_velocity) {
+ angular_velocity = p_velocity;
+}
+
+Vector3 XRPose::get_angular_velocity() const {
+ return angular_velocity;
+}
diff --git a/servers/xr/xr_pose.h b/servers/xr/xr_pose.h
new file mode 100644
index 0000000000..223e95ddfe
--- /dev/null
+++ b/servers/xr/xr_pose.h
@@ -0,0 +1,68 @@
+/*************************************************************************/
+/* xr_pose.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifndef XR_POSE_H
+#define XR_POSE_H
+
+#include "core/object/ref_counted.h"
+
+class XRPose : public RefCounted {
+ GDCLASS(XRPose, RefCounted);
+
+public:
+private:
+ bool has_tracking_data = false;
+ StringName name;
+ Transform3D transform;
+ Vector3 linear_velocity;
+ Vector3 angular_velocity;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_has_tracking_data(const bool p_has_tracking_data);
+ bool get_has_tracking_data() const;
+
+ void set_name(const StringName &p_name);
+ StringName get_name() const;
+
+ void set_transform(const Transform3D p_transform);
+ Transform3D get_transform() const;
+ Transform3D get_adjusted_transform() const;
+
+ void set_linear_velocity(const Vector3 p_velocity);
+ Vector3 get_linear_velocity() const;
+
+ void set_angular_velocity(const Vector3 p_velocity);
+ Vector3 get_angular_velocity() const;
+};
+
+#endif
diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp
index ad5cee92ea..1313a91172 100644
--- a/servers/xr/xr_positional_tracker.cpp
+++ b/servers/xr/xr_positional_tracker.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -34,181 +34,176 @@
void XRPositionalTracker::_bind_methods() {
BIND_ENUM_CONSTANT(TRACKER_HAND_UNKNOWN);
- BIND_ENUM_CONSTANT(TRACKER_LEFT_HAND);
- BIND_ENUM_CONSTANT(TRACKER_RIGHT_HAND);
-
- // this class is read only from GDScript, so we only have access to getters..
- ClassDB::bind_method(D_METHOD("get_type"), &XRPositionalTracker::get_type);
- ClassDB::bind_method(D_METHOD("get_tracker_id"), &XRPositionalTracker::get_tracker_id);
- ClassDB::bind_method(D_METHOD("get_name"), &XRPositionalTracker::get_name);
- ClassDB::bind_method(D_METHOD("get_joy_id"), &XRPositionalTracker::get_joy_id);
- ClassDB::bind_method(D_METHOD("get_tracks_orientation"), &XRPositionalTracker::get_tracks_orientation);
- ClassDB::bind_method(D_METHOD("get_orientation"), &XRPositionalTracker::get_orientation);
- ClassDB::bind_method(D_METHOD("get_tracks_position"), &XRPositionalTracker::get_tracks_position);
- ClassDB::bind_method(D_METHOD("get_position"), &XRPositionalTracker::get_position);
- ClassDB::bind_method(D_METHOD("get_hand"), &XRPositionalTracker::get_hand);
- ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &XRPositionalTracker::get_transform);
- ClassDB::bind_method(D_METHOD("get_mesh"), &XRPositionalTracker::get_mesh);
-
- // these functions we don't want to expose to normal users but do need to be callable from GDNative
- ClassDB::bind_method(D_METHOD("_set_type", "type"), &XRPositionalTracker::set_type);
- ClassDB::bind_method(D_METHOD("_set_name", "name"), &XRPositionalTracker::set_name);
- ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &XRPositionalTracker::set_joy_id);
- ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &XRPositionalTracker::set_orientation);
- ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &XRPositionalTracker::set_rw_position);
- ClassDB::bind_method(D_METHOD("_set_mesh", "mesh"), &XRPositionalTracker::set_mesh);
+ BIND_ENUM_CONSTANT(TRACKER_HAND_LEFT);
+ BIND_ENUM_CONSTANT(TRACKER_HAND_RIGHT);
+
+ ClassDB::bind_method(D_METHOD("get_tracker_type"), &XRPositionalTracker::get_tracker_type);
+ ClassDB::bind_method(D_METHOD("set_tracker_type", "type"), &XRPositionalTracker::set_tracker_type);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_tracker_type", "get_tracker_type");
+
+ ClassDB::bind_method(D_METHOD("get_tracker_name"), &XRPositionalTracker::get_tracker_name);
+ ClassDB::bind_method(D_METHOD("set_tracker_name", "name"), &XRPositionalTracker::set_tracker_name);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_tracker_name", "get_tracker_name");
+
+ ClassDB::bind_method(D_METHOD("get_tracker_desc"), &XRPositionalTracker::get_tracker_desc);
+ ClassDB::bind_method(D_METHOD("set_tracker_desc", "description"), &XRPositionalTracker::set_tracker_desc);
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_tracker_desc", "get_tracker_desc");
+
+ ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRPositionalTracker::get_tracker_hand);
+ ClassDB::bind_method(D_METHOD("set_tracker_hand", "hand"), &XRPositionalTracker::set_tracker_hand);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Unknown,Left,Right"), "set_tracker_hand", "get_tracker_hand");
+
+ ClassDB::bind_method(D_METHOD("has_pose", "name"), &XRPositionalTracker::has_pose);
+ ClassDB::bind_method(D_METHOD("get_pose", "name"), &XRPositionalTracker::get_pose);
+ ClassDB::bind_method(D_METHOD("invalidate_pose", "name"), &XRPositionalTracker::invalidate_pose);
+ ClassDB::bind_method(D_METHOD("set_pose", "name", "transform", "linear_velocity", "angular_velocity"), &XRPositionalTracker::set_pose);
+ ADD_SIGNAL(MethodInfo("pose_changed", PropertyInfo(Variant::OBJECT, "pose", PROPERTY_HINT_RESOURCE_TYPE, "XRPose")));
+
+ ClassDB::bind_method(D_METHOD("get_input", "name"), &XRPositionalTracker::get_input);
+ ClassDB::bind_method(D_METHOD("set_input", "name", "value"), &XRPositionalTracker::set_input);
+ ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::STRING, "name")));
+ ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name")));
+ ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value")));
+ ADD_SIGNAL(MethodInfo("input_axis_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "vector")));
+
ClassDB::bind_method(D_METHOD("get_rumble"), &XRPositionalTracker::get_rumble);
ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRPositionalTracker::set_rumble);
-
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble"), "set_rumble", "get_rumble");
};
-void XRPositionalTracker::set_type(XRServer::TrackerType p_type) {
+void XRPositionalTracker::set_tracker_type(XRServer::TrackerType p_type) {
if (type != p_type) {
type = p_type;
hand = XRPositionalTracker::TRACKER_HAND_UNKNOWN;
-
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL(xr_server);
-
- // get a tracker id for our type
- // note if this is a controller this will be 3 or higher but we may change it later.
- tracker_id = xr_server->get_free_tracker_id_for_type(p_type);
};
};
-XRServer::TrackerType XRPositionalTracker::get_type() const {
+XRServer::TrackerType XRPositionalTracker::get_tracker_type() const {
return type;
};
-void XRPositionalTracker::set_name(const String &p_name) {
+void XRPositionalTracker::set_tracker_name(const StringName &p_name) {
+ // Note: this should not be changed after the tracker is registered with the XRServer!
name = p_name;
};
-StringName XRPositionalTracker::get_name() const {
+StringName XRPositionalTracker::get_tracker_name() const {
return name;
};
-int XRPositionalTracker::get_tracker_id() const {
- return tracker_id;
-};
-
-void XRPositionalTracker::set_joy_id(int p_joy_id) {
- joy_id = p_joy_id;
-};
+void XRPositionalTracker::set_tracker_desc(const String &p_desc) {
+ description = p_desc;
+}
-int XRPositionalTracker::get_joy_id() const {
- return joy_id;
-};
-
-bool XRPositionalTracker::get_tracks_orientation() const {
- return tracks_orientation;
-};
-
-void XRPositionalTracker::set_orientation(const Basis &p_orientation) {
- _THREAD_SAFE_METHOD_
-
- tracks_orientation = true; // obviously we have this
- orientation = p_orientation;
-};
+String XRPositionalTracker::get_tracker_desc() const {
+ return description;
+}
-Basis XRPositionalTracker::get_orientation() const {
- _THREAD_SAFE_METHOD_
-
- return orientation;
-};
-
-bool XRPositionalTracker::get_tracks_position() const {
- return tracks_position;
+XRPositionalTracker::TrackerHand XRPositionalTracker::get_tracker_hand() const {
+ return hand;
};
-void XRPositionalTracker::set_position(const Vector3 &p_position) {
- _THREAD_SAFE_METHOD_
-
+void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
- real_t world_scale = xr_server->get_world_scale();
- ERR_FAIL_COND(world_scale == 0);
-
- tracks_position = true; // obviously we have this
- rw_position = p_position / world_scale;
-};
-
-Vector3 XRPositionalTracker::get_position() const {
- _THREAD_SAFE_METHOD_
-
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, rw_position);
- real_t world_scale = xr_server->get_world_scale();
-
- return rw_position * world_scale;
-};
-void XRPositionalTracker::set_rw_position(const Vector3 &p_rw_position) {
- _THREAD_SAFE_METHOD_
-
- tracks_position = true; // obviously we have this
- rw_position = p_rw_position;
-};
-
-Vector3 XRPositionalTracker::get_rw_position() const {
- _THREAD_SAFE_METHOD_
+ if (hand != p_hand) {
+ // we can only set this if we've previously set this to be a controller!!
+ ERR_FAIL_COND((type != XRServer::TRACKER_CONTROLLER) && (p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN));
- return rw_position;
+ hand = p_hand;
+ };
};
-void XRPositionalTracker::set_mesh(const Ref<Mesh> &p_mesh) {
- _THREAD_SAFE_METHOD_
+bool XRPositionalTracker::has_pose(const StringName &p_action_name) const {
+ return poses.has(p_action_name);
+}
- mesh = p_mesh;
-};
+Ref<XRPose> XRPositionalTracker::get_pose(const StringName &p_action_name) const {
+ Ref<XRPose> pose;
-Ref<Mesh> XRPositionalTracker::get_mesh() const {
- _THREAD_SAFE_METHOD_
+ if (poses.has(p_action_name)) {
+ pose = poses[p_action_name];
+ }
- return mesh;
-};
+ return pose;
+}
-XRPositionalTracker::TrackerHand XRPositionalTracker::get_hand() const {
- return hand;
-};
+void XRPositionalTracker::invalidate_pose(const StringName &p_action_name) {
+ // only update this if we were tracking this pose
+ if (poses.has(p_action_name)) {
+ // We just set tracking data as invalid, we leave our current transform and velocity data as is so controllers don't suddenly jump to origin.
+ poses[p_action_name]->set_has_tracking_data(false);
+ }
+}
-void XRPositionalTracker::set_hand(const XRPositionalTracker::TrackerHand p_hand) {
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL(xr_server);
+void XRPositionalTracker::set_pose(const StringName &p_action_name, const Transform3D &p_transform, const Vector3 &p_linear_velocity, const Vector3 &p_angular_velocity) {
+ Ref<XRPose> new_pose;
- if (hand != p_hand) {
- // we can only set this if we've previously set this to be a controller!!
- ERR_FAIL_COND((type != XRServer::TRACKER_CONTROLLER) && (p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN));
+ new_pose.instantiate();
+ new_pose->set_name(p_action_name);
+ new_pose->set_has_tracking_data(true);
+ new_pose->set_transform(p_transform);
+ new_pose->set_linear_velocity(p_linear_velocity);
+ new_pose->set_angular_velocity(p_angular_velocity);
- hand = p_hand;
- if (hand == XRPositionalTracker::TRACKER_LEFT_HAND) {
- if (!xr_server->is_tracker_id_in_use_for_type(type, 1)) {
- tracker_id = 1;
- };
- } else if (hand == XRPositionalTracker::TRACKER_RIGHT_HAND) {
- if (!xr_server->is_tracker_id_in_use_for_type(type, 2)) {
- tracker_id = 2;
- };
- };
- };
-};
+ poses[p_action_name] = new_pose;
+ emit_signal("pose_changed", new_pose);
-Transform XRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const {
- Transform new_transform;
+ // TODO discuss whether we also want to create and emit an InputEventXRPose event
+}
- new_transform.basis = get_orientation();
- new_transform.origin = get_position();
+Variant XRPositionalTracker::get_input(const StringName &p_action_name) const {
+ if (inputs.has(p_action_name)) {
+ return inputs[p_action_name];
+ } else {
+ return Variant();
+ }
+}
- if (p_adjust_by_reference_frame) {
- XRServer *xr_server = XRServer::get_singleton();
- ERR_FAIL_NULL_V(xr_server, new_transform);
+void XRPositionalTracker::set_input(const StringName &p_action_name, const Variant &p_value) {
+ bool changed = false;
- new_transform = xr_server->get_reference_frame() * new_transform;
- };
+ // XR inputs
- return new_transform;
-};
+ if (inputs.has(p_action_name)) {
+ changed = inputs[p_action_name] != p_value;
+ } else {
+ changed = true;
+ }
+
+ if (changed) {
+ // store the new value
+ inputs[p_action_name] = p_value;
+
+ // emit signals to let the rest of the world know
+ switch (p_value.get_type()) {
+ case Variant::BOOL: {
+ bool pressed = p_value;
+ if (pressed) {
+ emit_signal("button_pressed", p_action_name);
+ } else {
+ emit_signal("button_released", p_action_name);
+ }
+
+ // TODO discuss whether we also want to create and emit an InputEventXRButton event
+ } break;
+ case Variant::FLOAT: {
+ emit_signal("input_value_changed", p_action_name, p_value);
+
+ // TODO discuss whether we also want to create and emit an InputEventXRValue event
+ } break;
+ case Variant::VECTOR2: {
+ emit_signal("input_axis_changed", p_action_name, p_value);
+
+ // TODO discuss whether we also want to create and emit an InputEventXRAxis event
+ } break;
+ default: {
+ // ???
+ } break;
+ }
+ }
+}
real_t XRPositionalTracker::get_rumble() const {
return rumble;
@@ -225,10 +220,6 @@ void XRPositionalTracker::set_rumble(real_t p_rumble) {
XRPositionalTracker::XRPositionalTracker() {
type = XRServer::TRACKER_UNKNOWN;
name = "Unknown";
- joy_id = -1;
- tracker_id = 0;
- tracks_orientation = false;
- tracks_position = false;
hand = TRACKER_HAND_UNKNOWN;
rumble = 0.0;
};
diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h
index 515359e9b1..69eb105b5a 100644
--- a/servers/xr/xr_positional_tracker.h
+++ b/servers/xr/xr_positional_tracker.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,7 @@
#include "core/os/thread_safe.h"
#include "scene/resources/mesh.h"
+#include "servers/xr/xr_pose.h"
#include "servers/xr_server.h"
/**
@@ -43,57 +44,54 @@
This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking.
*/
-class XRPositionalTracker : public Object {
- GDCLASS(XRPositionalTracker, Object);
+class XRPositionalTracker : public RefCounted {
+ GDCLASS(XRPositionalTracker, RefCounted);
_THREAD_SAFE_CLASS_
public:
enum TrackerHand {
TRACKER_HAND_UNKNOWN, /* unknown or not applicable */
- TRACKER_LEFT_HAND, /* controller is the left hand controller */
- TRACKER_RIGHT_HAND /* controller is the right hand controller */
+ TRACKER_HAND_LEFT, /* controller is the left hand controller */
+ TRACKER_HAND_RIGHT /* controller is the right hand controller */
};
private:
XRServer::TrackerType type; // type of tracker
StringName name; // (unique) name of the tracker
- int tracker_id; // tracker index id that is unique per type
+ String description; // description of the tracker, this is interface dependent, for OpenXR this will be the interaction profile bound for to the tracker
+ TrackerHand hand; // if known, the hand this tracker is held in
+
+ Map<StringName, Ref<XRPose>> poses;
+ Map<StringName, Variant> inputs;
+
int joy_id; // if we also have a related joystick entity, the id of the joystick
- bool tracks_orientation; // do we track orientation?
- Basis orientation; // our orientation
- bool tracks_position; // do we track position?
- Vector3 rw_position; // our position "in the real world, so without world_scale applied"
Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker
- TrackerHand hand; // if known, the hand this tracker is held in
real_t rumble; // rumble strength, 0.0 is off, 1.0 is maximum, note that we only record here, xr_interface is responsible for execution
protected:
static void _bind_methods();
public:
- void set_type(XRServer::TrackerType p_type);
- XRServer::TrackerType get_type() const;
- void set_name(const String &p_name);
- StringName get_name() const;
- int get_tracker_id() const;
- void set_joy_id(int p_joy_id);
- int get_joy_id() const;
- bool get_tracks_orientation() const;
- void set_orientation(const Basis &p_orientation);
- Basis get_orientation() const;
- bool get_tracks_position() const;
- void set_position(const Vector3 &p_position); // set position with world_scale applied
- Vector3 get_position() const; // get position with world_scale applied
- void set_rw_position(const Vector3 &p_rw_position);
- Vector3 get_rw_position() const;
- XRPositionalTracker::TrackerHand get_hand() const;
- void set_hand(const XRPositionalTracker::TrackerHand p_hand);
+ void set_tracker_type(XRServer::TrackerType p_type);
+ XRServer::TrackerType get_tracker_type() const;
+ void set_tracker_name(const StringName &p_name);
+ StringName get_tracker_name() const;
+ void set_tracker_desc(const String &p_desc);
+ String get_tracker_desc() const;
+ XRPositionalTracker::TrackerHand get_tracker_hand() const;
+ void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand);
+
+ bool has_pose(const StringName &p_action_name) const;
+ Ref<XRPose> get_pose(const StringName &p_action_name) const;
+ void invalidate_pose(const StringName &p_action_name);
+ void set_pose(const StringName &p_action_name, const Transform3D &p_transform, const Vector3 &p_linear_velocity, const Vector3 &p_angular_velocity);
+
+ Variant get_input(const StringName &p_action_name) const;
+ void set_input(const StringName &p_action_name, const Variant &p_value);
+
+ // TODO replace by new implementation
real_t get_rumble() const;
void set_rumble(real_t p_rumble);
- void set_mesh(const Ref<Mesh> &p_mesh);
- Ref<Mesh> get_mesh() const;
-
- Transform get_transform(bool p_adjust_by_reference_frame) const;
XRPositionalTracker();
~XRPositionalTracker() {}