diff options
Diffstat (limited to 'servers/xr')
-rw-r--r-- | servers/xr/xr_interface.cpp | 130 | ||||
-rw-r--r-- | servers/xr/xr_interface.h | 79 | ||||
-rw-r--r-- | servers/xr/xr_interface_extension.cpp | 335 | ||||
-rw-r--r-- | servers/xr/xr_interface_extension.h | 126 | ||||
-rw-r--r-- | servers/xr/xr_pose.cpp | 110 | ||||
-rw-r--r-- | servers/xr/xr_pose.h | 68 | ||||
-rw-r--r-- | servers/xr/xr_positional_tracker.cpp | 269 | ||||
-rw-r--r-- | servers/xr/xr_positional_tracker.h | 64 |
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() {} |