From afc8c6391ccc2d3d69dcad0d93b2639bfe77dc55 Mon Sep 17 00:00:00 2001 From: Bastiaan Olij Date: Thu, 9 Apr 2020 00:47:36 +1000 Subject: Renaming all ARVR nodes to XR --- servers/SCsub | 2 +- servers/arvr/SCsub | 5 - servers/arvr/arvr_interface.cpp | 145 --------- servers/arvr/arvr_interface.h | 126 -------- servers/arvr/arvr_positional_tracker.cpp | 237 --------------- servers/arvr/arvr_positional_tracker.h | 104 ------- servers/arvr_server.cpp | 386 ------------------------ servers/arvr_server.h | 192 ------------ servers/register_server_types.cpp | 18 +- servers/rendering/rendering_server_raster.h | 2 +- servers/rendering/rendering_server_scene.cpp | 12 +- servers/rendering/rendering_server_scene.h | 4 +- servers/rendering/rendering_server_viewport.cpp | 53 ++-- servers/rendering/rendering_server_viewport.h | 12 +- servers/rendering/rendering_server_wrap_mt.h | 2 +- servers/rendering_server.cpp | 2 +- servers/rendering_server.h | 2 +- servers/xr/SCsub | 5 + servers/xr/xr_interface.cpp | 145 +++++++++ servers/xr/xr_interface.h | 126 ++++++++ servers/xr/xr_positional_tracker.cpp | 237 +++++++++++++++ servers/xr/xr_positional_tracker.h | 104 +++++++ servers/xr_server.cpp | 386 ++++++++++++++++++++++++ servers/xr_server.h | 192 ++++++++++++ 24 files changed, 1251 insertions(+), 1248 deletions(-) delete mode 100644 servers/arvr/SCsub delete mode 100644 servers/arvr/arvr_interface.cpp delete mode 100644 servers/arvr/arvr_interface.h delete mode 100644 servers/arvr/arvr_positional_tracker.cpp delete mode 100644 servers/arvr/arvr_positional_tracker.h delete mode 100644 servers/arvr_server.cpp delete mode 100644 servers/arvr_server.h create mode 100644 servers/xr/SCsub create mode 100644 servers/xr/xr_interface.cpp create mode 100644 servers/xr/xr_interface.h create mode 100644 servers/xr/xr_positional_tracker.cpp create mode 100644 servers/xr/xr_positional_tracker.h create mode 100644 servers/xr_server.cpp create mode 100644 servers/xr_server.h (limited to 'servers') diff --git a/servers/SCsub b/servers/SCsub index 7080a110da..121990f2e1 100644 --- a/servers/SCsub +++ b/servers/SCsub @@ -5,7 +5,7 @@ Import("env") env.servers_sources = [] env.add_source_files(env.servers_sources, "*.cpp") -SConscript("arvr/SCsub") +SConscript("xr/SCsub") SConscript("camera/SCsub") SConscript("physics_3d/SCsub") SConscript("physics_2d/SCsub") diff --git a/servers/arvr/SCsub b/servers/arvr/SCsub deleted file mode 100644 index 86681f9c74..0000000000 --- a/servers/arvr/SCsub +++ /dev/null @@ -1,5 +0,0 @@ -#!/usr/bin/env python - -Import("env") - -env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/arvr/arvr_interface.cpp b/servers/arvr/arvr_interface.cpp deleted file mode 100644 index 577b4cdd8a..0000000000 --- a/servers/arvr/arvr_interface.cpp +++ /dev/null @@ -1,145 +0,0 @@ -/*************************************************************************/ -/* arvr_interface.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 "arvr_interface.h" - -void ARVRInterface::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_name"), &ARVRInterface::get_name); - ClassDB::bind_method(D_METHOD("get_capabilities"), &ARVRInterface::get_capabilities); - - ClassDB::bind_method(D_METHOD("is_primary"), &ARVRInterface::is_primary); - ClassDB::bind_method(D_METHOD("set_is_primary", "enable"), &ARVRInterface::set_is_primary); - - ClassDB::bind_method(D_METHOD("is_initialized"), &ARVRInterface::is_initialized); - ClassDB::bind_method(D_METHOD("set_is_initialized", "initialized"), &ARVRInterface::set_is_initialized); - ClassDB::bind_method(D_METHOD("initialize"), &ARVRInterface::initialize); - ClassDB::bind_method(D_METHOD("uninitialize"), &ARVRInterface::uninitialize); - - ClassDB::bind_method(D_METHOD("get_tracking_status"), &ARVRInterface::get_tracking_status); - - ClassDB::bind_method(D_METHOD("get_render_targetsize"), &ARVRInterface::get_render_targetsize); - ClassDB::bind_method(D_METHOD("is_stereo"), &ARVRInterface::is_stereo); - - 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"); - - // we don't have any properties specific to VR yet.... - - // but we do have properties specific to AR.... - ClassDB::bind_method(D_METHOD("get_anchor_detection_is_enabled"), &ARVRInterface::get_anchor_detection_is_enabled); - ClassDB::bind_method(D_METHOD("set_anchor_detection_is_enabled", "enable"), &ARVRInterface::set_anchor_detection_is_enabled); - ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &ARVRInterface::get_camera_feed_id); - - ADD_GROUP("AR", "ar_"); - ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ar_is_anchor_detection_enabled"), "set_anchor_detection_is_enabled", "get_anchor_detection_is_enabled"); - - BIND_ENUM_CONSTANT(ARVR_NONE); - BIND_ENUM_CONSTANT(ARVR_MONO); - BIND_ENUM_CONSTANT(ARVR_STEREO); - BIND_ENUM_CONSTANT(ARVR_AR); - BIND_ENUM_CONSTANT(ARVR_EXTERNAL); - - BIND_ENUM_CONSTANT(EYE_MONO); - BIND_ENUM_CONSTANT(EYE_LEFT); - BIND_ENUM_CONSTANT(EYE_RIGHT); - - BIND_ENUM_CONSTANT(ARVR_NORMAL_TRACKING); - BIND_ENUM_CONSTANT(ARVR_EXCESSIVE_MOTION); - BIND_ENUM_CONSTANT(ARVR_INSUFFICIENT_FEATURES); - BIND_ENUM_CONSTANT(ARVR_UNKNOWN_TRACKING); - BIND_ENUM_CONSTANT(ARVR_NOT_TRACKING); -}; - -StringName ARVRInterface::get_name() const { - return "Unknown"; -}; - -bool ARVRInterface::is_primary() { - ARVRServer *arvr_server = ARVRServer::get_singleton(); - ERR_FAIL_NULL_V(arvr_server, false); - - return arvr_server->get_primary_interface() == this; -}; - -void ARVRInterface::set_is_primary(bool p_is_primary) { - ARVRServer *arvr_server = ARVRServer::get_singleton(); - ERR_FAIL_NULL(arvr_server); - - if (p_is_primary) { - ERR_FAIL_COND(!is_initialized()); - - arvr_server->set_primary_interface(this); - } else { - arvr_server->clear_primary_interface_if(this); - }; -}; - -void ARVRInterface::set_is_initialized(bool p_initialized) { - if (p_initialized) { - if (!is_initialized()) { - initialize(); - }; - } else { - if (is_initialized()) { - uninitialize(); - }; - }; -}; - -ARVRInterface::Tracking_status ARVRInterface::get_tracking_status() const { - return tracking_state; -}; - -ARVRInterface::ARVRInterface() { - tracking_state = ARVR_UNKNOWN_TRACKING; -}; - -ARVRInterface::~ARVRInterface(){}; - -// optional render to external texture which enhances performance on those platforms that require us to submit our end result into special textures. -unsigned int ARVRInterface::get_external_texture_for_eye(ARVRInterface::Eyes p_eye) { - return 0; -}; - -/** these will only be implemented on AR interfaces, so we want dummies for VR **/ -bool ARVRInterface::get_anchor_detection_is_enabled() const { - return false; -}; - -void ARVRInterface::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 ARVRInterface::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; -}; diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h deleted file mode 100644 index 861061cbf5..0000000000 --- a/servers/arvr/arvr_interface.h +++ /dev/null @@ -1,126 +0,0 @@ -/*************************************************************************/ -/* arvr_interface.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 ARVR_INTERFACE_H -#define ARVR_INTERFACE_H - -#include "core/math/camera_matrix.h" -#include "core/os/thread_safe.h" -#include "scene/main/window.h" -#include "servers/arvr_server.h" - -/** - @author Bastiaan Olij - - The ARVR interface is a template class ontop 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. - - If the user wants to enable AR/VR the choose the interface they want to use and initialize it. - - Note that we may make this into a fully instantiable class for GDNative support. -*/ - -class ARVRInterface : public Reference { - GDCLASS(ARVRInterface, Reference); - -public: - enum Capabilities { /* purely meta data, provides some info about what this interface supports */ - ARVR_NONE = 0, /* no capabilities */ - ARVR_MONO = 1, /* can be used with mono output */ - ARVR_STEREO = 2, /* can be used with stereo output */ - ARVR_AR = 4, /* offers a camera feed for AR */ - ARVR_EXTERNAL = 8 /* renders to external device */ - }; - - enum Eyes { - EYE_MONO, /* my son says we should call this EYE_CYCLOPS */ - EYE_LEFT, - EYE_RIGHT - }; - - enum Tracking_status { /* tracking status currently based on AR but we can start doing more with this for VR as well */ - ARVR_NORMAL_TRACKING, - ARVR_EXCESSIVE_MOTION, - ARVR_INSUFFICIENT_FEATURES, - ARVR_UNKNOWN_TRACKING, - ARVR_NOT_TRACKING - }; - -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; - - bool is_primary(); - void set_is_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 */ - - /** specific to VR **/ - // nothing yet - - /** specific to AR **/ - virtual bool get_anchor_detection_is_enabled() const; - virtual void set_anchor_detection_is_enabled(bool p_enable); - virtual int get_camera_feed_id(); - - /** 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(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */ - virtual CameraMatrix get_projection_for_eye(ARVRInterface::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(ARVRInterface::Eyes p_eye); /* if applicable return external texture to render to */ - virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */ - - virtual void process() = 0; - virtual void notification(int p_what) = 0; - - ARVRInterface(); - ~ARVRInterface(); -}; - -VARIANT_ENUM_CAST(ARVRInterface::Capabilities); -VARIANT_ENUM_CAST(ARVRInterface::Eyes); -VARIANT_ENUM_CAST(ARVRInterface::Tracking_status); - -#endif diff --git a/servers/arvr/arvr_positional_tracker.cpp b/servers/arvr/arvr_positional_tracker.cpp deleted file mode 100644 index dabeb7b86f..0000000000 --- a/servers/arvr/arvr_positional_tracker.cpp +++ /dev/null @@ -1,237 +0,0 @@ -/*************************************************************************/ -/* arvr_positional_tracker.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 "arvr_positional_tracker.h" -#include "core/input/input_filter.h" - -void ARVRPositionalTracker::_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"), &ARVRPositionalTracker::get_type); - ClassDB::bind_method(D_METHOD("get_tracker_id"), &ARVRPositionalTracker::get_tracker_id); - ClassDB::bind_method(D_METHOD("get_name"), &ARVRPositionalTracker::get_name); - ClassDB::bind_method(D_METHOD("get_joy_id"), &ARVRPositionalTracker::get_joy_id); - ClassDB::bind_method(D_METHOD("get_tracks_orientation"), &ARVRPositionalTracker::get_tracks_orientation); - ClassDB::bind_method(D_METHOD("get_orientation"), &ARVRPositionalTracker::get_orientation); - ClassDB::bind_method(D_METHOD("get_tracks_position"), &ARVRPositionalTracker::get_tracks_position); - ClassDB::bind_method(D_METHOD("get_position"), &ARVRPositionalTracker::get_position); - ClassDB::bind_method(D_METHOD("get_hand"), &ARVRPositionalTracker::get_hand); - ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &ARVRPositionalTracker::get_transform); - ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRPositionalTracker::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"), &ARVRPositionalTracker::set_type); - ClassDB::bind_method(D_METHOD("_set_name", "name"), &ARVRPositionalTracker::set_name); - ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &ARVRPositionalTracker::set_joy_id); - ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &ARVRPositionalTracker::set_orientation); - ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &ARVRPositionalTracker::set_rw_position); - ClassDB::bind_method(D_METHOD("_set_mesh", "mesh"), &ARVRPositionalTracker::set_mesh); - ClassDB::bind_method(D_METHOD("get_rumble"), &ARVRPositionalTracker::get_rumble); - ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &ARVRPositionalTracker::set_rumble); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble"), "set_rumble", "get_rumble"); -}; - -void ARVRPositionalTracker::set_type(ARVRServer::TrackerType p_type) { - if (type != p_type) { - type = p_type; - hand = ARVRPositionalTracker::TRACKER_HAND_UNKNOWN; - - ARVRServer *arvr_server = ARVRServer::get_singleton(); - ERR_FAIL_NULL(arvr_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 = arvr_server->get_free_tracker_id_for_type(p_type); - }; -}; - -ARVRServer::TrackerType ARVRPositionalTracker::get_type() const { - return type; -}; - -void ARVRPositionalTracker::set_name(const String &p_name) { - name = p_name; -}; - -StringName ARVRPositionalTracker::get_name() const { - return name; -}; - -int ARVRPositionalTracker::get_tracker_id() const { - return tracker_id; -}; - -void ARVRPositionalTracker::set_joy_id(int p_joy_id) { - joy_id = p_joy_id; -}; - -int ARVRPositionalTracker::get_joy_id() const { - return joy_id; -}; - -bool ARVRPositionalTracker::get_tracks_orientation() const { - return tracks_orientation; -}; - -void ARVRPositionalTracker::set_orientation(const Basis &p_orientation) { - _THREAD_SAFE_METHOD_ - - tracks_orientation = true; // obviously we have this - orientation = p_orientation; -}; - -Basis ARVRPositionalTracker::get_orientation() const { - _THREAD_SAFE_METHOD_ - - return orientation; -}; - -bool ARVRPositionalTracker::get_tracks_position() const { - return tracks_position; -}; - -void ARVRPositionalTracker::set_position(const Vector3 &p_position) { - _THREAD_SAFE_METHOD_ - - ARVRServer *arvr_server = ARVRServer::get_singleton(); - ERR_FAIL_NULL(arvr_server); - real_t world_scale = arvr_server->get_world_scale(); - ERR_FAIL_COND(world_scale == 0); - - tracks_position = true; // obviously we have this - rw_position = p_position / world_scale; -}; - -Vector3 ARVRPositionalTracker::get_position() const { - _THREAD_SAFE_METHOD_ - - ARVRServer *arvr_server = ARVRServer::get_singleton(); - ERR_FAIL_NULL_V(arvr_server, rw_position); - real_t world_scale = arvr_server->get_world_scale(); - - return rw_position * world_scale; -}; - -void ARVRPositionalTracker::set_rw_position(const Vector3 &p_rw_position) { - _THREAD_SAFE_METHOD_ - - tracks_position = true; // obviously we have this - rw_position = p_rw_position; -}; - -Vector3 ARVRPositionalTracker::get_rw_position() const { - _THREAD_SAFE_METHOD_ - - return rw_position; -}; - -void ARVRPositionalTracker::set_mesh(const Ref &p_mesh) { - _THREAD_SAFE_METHOD_ - - mesh = p_mesh; -}; - -Ref ARVRPositionalTracker::get_mesh() const { - _THREAD_SAFE_METHOD_ - - return mesh; -}; - -ARVRPositionalTracker::TrackerHand ARVRPositionalTracker::get_hand() const { - return hand; -}; - -void ARVRPositionalTracker::set_hand(const ARVRPositionalTracker::TrackerHand p_hand) { - ARVRServer *arvr_server = ARVRServer::get_singleton(); - ERR_FAIL_NULL(arvr_server); - - if (hand != p_hand) { - // we can only set this if we've previously set this to be a controller!! - ERR_FAIL_COND((type != ARVRServer::TRACKER_CONTROLLER) && (p_hand != ARVRPositionalTracker::TRACKER_HAND_UNKNOWN)); - - hand = p_hand; - if (hand == ARVRPositionalTracker::TRACKER_LEFT_HAND) { - if (!arvr_server->is_tracker_id_in_use_for_type(type, 1)) { - tracker_id = 1; - }; - } else if (hand == ARVRPositionalTracker::TRACKER_RIGHT_HAND) { - if (!arvr_server->is_tracker_id_in_use_for_type(type, 2)) { - tracker_id = 2; - }; - }; - }; -}; - -Transform ARVRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const { - Transform new_transform; - - new_transform.basis = get_orientation(); - new_transform.origin = get_position(); - - if (p_adjust_by_reference_frame) { - ARVRServer *arvr_server = ARVRServer::get_singleton(); - ERR_FAIL_NULL_V(arvr_server, new_transform); - - new_transform = arvr_server->get_reference_frame() * new_transform; - }; - - return new_transform; -}; - -real_t ARVRPositionalTracker::get_rumble() const { - return rumble; -}; - -void ARVRPositionalTracker::set_rumble(real_t p_rumble) { - if (p_rumble > 0.0) { - rumble = p_rumble; - } else { - rumble = 0.0; - }; -}; - -ARVRPositionalTracker::ARVRPositionalTracker() { - type = ARVRServer::TRACKER_UNKNOWN; - name = "Unknown"; - joy_id = -1; - tracker_id = 0; - tracks_orientation = false; - tracks_position = false; - hand = TRACKER_HAND_UNKNOWN; - rumble = 0.0; -}; - -ARVRPositionalTracker::~ARVRPositionalTracker(){ - -}; diff --git a/servers/arvr/arvr_positional_tracker.h b/servers/arvr/arvr_positional_tracker.h deleted file mode 100644 index 03c6b33ffe..0000000000 --- a/servers/arvr/arvr_positional_tracker.h +++ /dev/null @@ -1,104 +0,0 @@ -/*************************************************************************/ -/* arvr_positional_tracker.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 ARVR_POSITIONAL_TRACKER_H -#define ARVR_POSITIONAL_TRACKER_H - -#include "core/os/thread_safe.h" -#include "scene/resources/mesh.h" -#include "servers/arvr_server.h" - -/** - @author Bastiaan Olij - - The positional tracker object as an object that represents the position and orientation of a tracked object like a controller or headset. - An AR/VR Interface will registered the trackers it manages with our AR/VR server and update its position and orientation. - This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking. -*/ - -class ARVRPositionalTracker : public Object { - GDCLASS(ARVRPositionalTracker, Object); - _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 */ - }; - -private: - ARVRServer::TrackerType type; // type of tracker - StringName name; // (unique) name of the tracker - int tracker_id; // tracker index id that is unique per type - 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; // 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, arvr_interface is responsible for execution - -protected: - static void _bind_methods(); - -public: - void set_type(ARVRServer::TrackerType p_type); - ARVRServer::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; - ARVRPositionalTracker::TrackerHand get_hand() const; - void set_hand(const ARVRPositionalTracker::TrackerHand p_hand); - real_t get_rumble() const; - void set_rumble(real_t p_rumble); - void set_mesh(const Ref &p_mesh); - Ref get_mesh() const; - - Transform get_transform(bool p_adjust_by_reference_frame) const; - - ARVRPositionalTracker(); - ~ARVRPositionalTracker(); -}; - -VARIANT_ENUM_CAST(ARVRPositionalTracker::TrackerHand); - -#endif diff --git a/servers/arvr_server.cpp b/servers/arvr_server.cpp deleted file mode 100644 index f5597d8974..0000000000 --- a/servers/arvr_server.cpp +++ /dev/null @@ -1,386 +0,0 @@ -/*************************************************************************/ -/* arvr_server.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 "arvr_server.h" -#include "arvr/arvr_interface.h" -#include "arvr/arvr_positional_tracker.h" -#include "core/project_settings.h" - -ARVRServer *ARVRServer::singleton = nullptr; - -ARVRServer *ARVRServer::get_singleton() { - return singleton; -}; - -void ARVRServer::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_world_scale"), &ARVRServer::get_world_scale); - ClassDB::bind_method(D_METHOD("set_world_scale"), &ARVRServer::set_world_scale); - ClassDB::bind_method(D_METHOD("get_reference_frame"), &ARVRServer::get_reference_frame); - ClassDB::bind_method(D_METHOD("center_on_hmd", "rotation_mode", "keep_height"), &ARVRServer::center_on_hmd); - ClassDB::bind_method(D_METHOD("get_hmd_transform"), &ARVRServer::get_hmd_transform); - - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale"); - - ClassDB::bind_method(D_METHOD("get_interface_count"), &ARVRServer::get_interface_count); - ClassDB::bind_method(D_METHOD("get_interface", "idx"), &ARVRServer::get_interface); - ClassDB::bind_method(D_METHOD("get_interfaces"), &ARVRServer::get_interfaces); - ClassDB::bind_method(D_METHOD("find_interface", "name"), &ARVRServer::find_interface); - ClassDB::bind_method(D_METHOD("get_tracker_count"), &ARVRServer::get_tracker_count); - ClassDB::bind_method(D_METHOD("get_tracker", "idx"), &ARVRServer::get_tracker); - - ClassDB::bind_method(D_METHOD("get_primary_interface"), &ARVRServer::get_primary_interface); - ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &ARVRServer::set_primary_interface); - - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "primary_interface"), "set_primary_interface", "get_primary_interface"); - - ClassDB::bind_method(D_METHOD("get_last_process_usec"), &ARVRServer::get_last_process_usec); - ClassDB::bind_method(D_METHOD("get_last_commit_usec"), &ARVRServer::get_last_commit_usec); - ClassDB::bind_method(D_METHOD("get_last_frame_usec"), &ARVRServer::get_last_frame_usec); - - BIND_ENUM_CONSTANT(TRACKER_CONTROLLER); - BIND_ENUM_CONSTANT(TRACKER_BASESTATION); - BIND_ENUM_CONSTANT(TRACKER_ANCHOR); - BIND_ENUM_CONSTANT(TRACKER_ANY_KNOWN); - BIND_ENUM_CONSTANT(TRACKER_UNKNOWN); - BIND_ENUM_CONSTANT(TRACKER_ANY); - - BIND_ENUM_CONSTANT(RESET_FULL_ROTATION); - BIND_ENUM_CONSTANT(RESET_BUT_KEEP_TILT); - BIND_ENUM_CONSTANT(DONT_RESET_ROTATION); - - ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING_NAME, "interface_name"))); - ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING_NAME, "interface_name"))); - - ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id"))); - ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id"))); -}; - -real_t ARVRServer::get_world_scale() const { - return world_scale; -}; - -void ARVRServer::set_world_scale(real_t p_world_scale) { - if (p_world_scale < 0.01) { - p_world_scale = 0.01; - } else if (p_world_scale > 1000.0) { - p_world_scale = 1000.0; - } - - world_scale = p_world_scale; -}; - -Transform ARVRServer::get_world_origin() const { - return world_origin; -}; - -void ARVRServer::set_world_origin(const Transform &p_world_origin) { - world_origin = p_world_origin; -}; - -Transform ARVRServer::get_reference_frame() const { - return reference_frame; -}; - -void ARVRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) { - if (primary_interface != nullptr) { - // clear our current reference frame or we'll end up double adjusting it - reference_frame = Transform(); - - // requesting our EYE_MONO transform should return our current HMD position - Transform new_reference_frame = primary_interface->get_transform_for_eye(ARVRInterface::EYE_MONO, Transform()); - - // remove our tilt - if (p_rotation_mode == 1) { - // take the Y out of our Z - new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized()); - - // Y is straight up - new_reference_frame.basis.set_axis(1, Vector3(0.0, 1.0, 0.0)); - - // and X is our cross reference - new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized()); - } else if (p_rotation_mode == 2) { - // remove our rotation, we're only interesting in centering on position - new_reference_frame.basis = Basis(); - }; - - // don't negate our height - if (p_keep_height) { - new_reference_frame.origin.y = 0.0; - }; - - reference_frame = new_reference_frame.inverse(); - }; -}; - -Transform ARVRServer::get_hmd_transform() { - Transform hmd_transform; - if (primary_interface != nullptr) { - hmd_transform = primary_interface->get_transform_for_eye(ARVRInterface::EYE_MONO, hmd_transform); - }; - return hmd_transform; -}; - -void ARVRServer::add_interface(const Ref &p_interface) { - ERR_FAIL_COND(p_interface.is_null()); - - for (int i = 0; i < interfaces.size(); i++) { - - if (interfaces[i] == p_interface) { - ERR_PRINT("Interface was already added"); - return; - }; - }; - - interfaces.push_back(p_interface); - emit_signal("interface_added", p_interface->get_name()); -}; - -void ARVRServer::remove_interface(const Ref &p_interface) { - ERR_FAIL_COND(p_interface.is_null()); - - int idx = -1; - for (int i = 0; i < interfaces.size(); i++) { - - if (interfaces[i] == p_interface) { - - idx = i; - break; - }; - }; - - ERR_FAIL_COND(idx == -1); - - print_verbose("ARVR: Removed interface" + p_interface->get_name()); - - emit_signal("interface_removed", p_interface->get_name()); - interfaces.remove(idx); -}; - -int ARVRServer::get_interface_count() const { - return interfaces.size(); -}; - -Ref ARVRServer::get_interface(int p_index) const { - ERR_FAIL_INDEX_V(p_index, interfaces.size(), nullptr); - - return interfaces[p_index]; -}; - -Ref ARVRServer::find_interface(const String &p_name) const { - int idx = -1; - for (int i = 0; i < interfaces.size(); i++) { - - if (interfaces[i]->get_name() == p_name) { - - idx = i; - break; - }; - }; - - ERR_FAIL_COND_V(idx == -1, nullptr); - - return interfaces[idx]; -}; - -Array ARVRServer::get_interfaces() const { - Array ret; - - for (int i = 0; i < interfaces.size(); i++) { - Dictionary iface_info; - - iface_info["id"] = i; - iface_info["name"] = interfaces[i]->get_name(); - - ret.push_back(iface_info); - }; - - return ret; -}; - -/* - A little extra info on the tracker ids, these are unique per tracker type so we get some consistency in recognising our trackers, specifically controllers. - - The first controller that is turned of will get ID 1, the second will get ID 2, etc. - The magic happens when one of the controllers is turned off, say controller 1 turns off, controller 2 will remain controller 2, controller 3 will remain controller 3. - If controller number 1 is turned on again it again gets ID 1 unless another new controller was turned on since. - - The most likely scenario however is a controller that runs out of battery and another controller being used to replace it. - Because the controllers are often linked to physical objects, say you're holding a shield in controller 1, your left hand, and a gun in controller 2, your right hand, and controller 1 dies: - - using our tracker index would suddenly make the gun disappear and the shield jump into your right hand because controller 2 becomes controller 1. - - using this approach the shield disappears or is no longer tracked, but the gun stays firmly in your right hand because that is still controller 2, further more, if controller 1 is replaced the shield will return. -*/ - -bool ARVRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const { - for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { - return true; - }; - }; - - // all good - return false; -}; - -int ARVRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) { - // We start checking at 1, 0 means that it's not a controller.. - // Note that for controller we reserve: - // - 1 for the left hand controller and - // - 2 for the right hand controller - // so we start at 3 :) - int tracker_id = p_tracker_type == ARVRServer::TRACKER_CONTROLLER ? 3 : 1; - - while (is_tracker_id_in_use_for_type(p_tracker_type, tracker_id)) { - // try the next one - tracker_id++; - }; - - return tracker_id; -}; - -void ARVRServer::add_tracker(ARVRPositionalTracker *p_tracker) { - ERR_FAIL_NULL(p_tracker); - - trackers.push_back(p_tracker); - emit_signal("tracker_added", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); -}; - -void ARVRServer::remove_tracker(ARVRPositionalTracker *p_tracker) { - ERR_FAIL_NULL(p_tracker); - - int idx = -1; - for (int i = 0; i < trackers.size(); i++) { - - if (trackers[i] == p_tracker) { - - idx = i; - break; - }; - }; - - ERR_FAIL_COND(idx == -1); - - emit_signal("tracker_removed", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); - trackers.remove(idx); -}; - -int ARVRServer::get_tracker_count() const { - return trackers.size(); -}; - -ARVRPositionalTracker *ARVRServer::get_tracker(int p_index) const { - ERR_FAIL_INDEX_V(p_index, trackers.size(), nullptr); - - return trackers[p_index]; -}; - -ARVRPositionalTracker *ARVRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const { - ERR_FAIL_COND_V(p_tracker_id == 0, nullptr); - - for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { - return trackers[i]; - }; - }; - - return nullptr; -}; - -Ref ARVRServer::get_primary_interface() const { - return primary_interface; -}; - -void ARVRServer::set_primary_interface(const Ref &p_primary_interface) { - primary_interface = p_primary_interface; - - print_verbose("ARVR: Primary interface set to: " + primary_interface->get_name()); -}; - -void ARVRServer::clear_primary_interface_if(const Ref &p_primary_interface) { - if (primary_interface == p_primary_interface) { - print_verbose("ARVR: Clearing primary interface"); - primary_interface.unref(); - }; -}; - -uint64_t ARVRServer::get_last_process_usec() { - return last_process_usec; -}; - -uint64_t ARVRServer::get_last_commit_usec() { - return last_commit_usec; -}; - -uint64_t ARVRServer::get_last_frame_usec() { - return last_frame_usec; -}; - -void ARVRServer::_process() { - /* called from rendering_server_viewport.draw_viewports right before we start drawing our viewports */ - - /* mark for our frame timing */ - last_process_usec = OS::get_singleton()->get_ticks_usec(); - - /* process all active interfaces */ - for (int i = 0; i < interfaces.size(); i++) { - if (!interfaces[i].is_valid()) { - // ignore, not a valid reference - } else if (interfaces[i]->is_initialized()) { - interfaces.write[i]->process(); - }; - }; -}; - -void ARVRServer::_mark_commit() { - /* time this */ - last_commit_usec = OS::get_singleton()->get_ticks_usec(); - - /* now store our difference as we may overwrite last_process_usec before this is accessed */ - last_frame_usec = last_commit_usec - last_process_usec; -}; - -ARVRServer::ARVRServer() { - singleton = this; - world_scale = 1.0; -}; - -ARVRServer::~ARVRServer() { - primary_interface.unref(); - - while (interfaces.size() > 0) { - interfaces.remove(0); - } - - while (trackers.size() > 0) { - trackers.remove(0); - } - - singleton = nullptr; -}; diff --git a/servers/arvr_server.h b/servers/arvr_server.h deleted file mode 100644 index ab2f0d721b..0000000000 --- a/servers/arvr_server.h +++ /dev/null @@ -1,192 +0,0 @@ -/*************************************************************************/ -/* arvr_server.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 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 ARVR_SERVER_H -#define ARVR_SERVER_H - -#include "core/os/os.h" -#include "core/os/thread_safe.h" -#include "core/reference.h" -#include "core/rid.h" -#include "core/variant.h" - -class ARVRInterface; -class ARVRPositionalTracker; - -/** - @author Bastiaan Olij - - The ARVR server is a singleton object that gives access to the various - objects and SDKs that are available on the system. - Because there can be multiple SDKs active this is exposed as an array - and our ARVR server object acts as a pass through - Also each positioning tracker is accessible from here. - - I've added some additional info into this header file that should move - into the documentation, I will do so when we're close to accepting this PR - or as a separate PR once this has been merged into the master branch. -**/ - -class ARVRServer : public Object { - GDCLASS(ARVRServer, Object); - _THREAD_SAFE_CLASS_ - -public: - enum TrackerType { - TRACKER_CONTROLLER = 0x01, /* tracks a controller */ - TRACKER_BASESTATION = 0x02, /* tracks location of a base station */ - TRACKER_ANCHOR = 0x04, /* tracks an anchor point, used in AR to track a real live location */ - TRACKER_UNKNOWN = 0x80, /* unknown tracker */ - - TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */ - TRACKER_ANY = 0xff /* used by get_connected_trackers to return all types */ - }; - - enum RotationMode { - RESET_FULL_ROTATION = 0, /* we reset the full rotation, regardless of how the HMD is oriented, we're looking dead ahead */ - RESET_BUT_KEEP_TILT = 1, /* reset rotation but keep tilt. */ - DONT_RESET_ROTATION = 2, /* don't reset the rotation, we will only center on position */ - }; - -private: - Vector> interfaces; - Vector trackers; - - Ref primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ - - real_t world_scale; /* scale by which we multiply our tracker positions */ - Transform world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */ - Transform reference_frame; /* our reference frame */ - - uint64_t last_process_usec; /* for frame timing, usec when we did our processing */ - uint64_t last_commit_usec; /* for frame timing, usec when we finished committing both eyes */ - uint64_t last_frame_usec; /* time it took between process and committing, we should probably average this over the last x frames */ - -protected: - static ARVRServer *singleton; - - static void _bind_methods(); - -public: - static ARVRServer *get_singleton(); - - /* - World scale allows you to specify a scale factor that is applied to all positioning vectors in our VR world in essence scaling up, or scaling down the world. - For stereoscopic rendering specifically this is very important to give an accurate sense of scale. - Add controllers into the mix and an accurate mapping of real world movement to perceived virtual movement becomes very important. - - Most VR platforms, and our assumption, is that 1 unit in our virtual world equates to 1 meter in the real mode. - This scale basically effects the unit size relationship to real world size. - - I may remove access to this property in GDScript in favour of exposing it on the ARVROrigin node - */ - real_t get_world_scale() const; - void set_world_scale(real_t p_world_scale); - - /* - The world maps the 0,0,0 coordinate of our real world coordinate system for our tracking volume to a location in our - virtual world. It is this origin point that should be moved when the player is moved through the world by controller - actions be it straffing, teleporting, etc. Movement of the player by moving through the physical space is always tracked - in relation to this point. - - Note that the ARVROrigin spatial node in your scene automatically updates this property and it should be used instead of - direct access to this property and it therefore is not available in GDScript - - Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world - and in the virtual world out of sync - */ - Transform get_world_origin() const; - void set_world_origin(const Transform &p_world_origin); - - /* - center_on_hmd calculates a new reference frame. This ensures the HMD is positioned to 0,0,0 facing 0,0,-1 (need to verify this direction) - in the virtual world. - - You can ignore the tilt of the device ensuring you're looking straight forward even if the player is looking down or sideways. - You can chose to keep the height the tracking provides which is important for room scale capable tracking. - - Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world - and in the virtual world out of sync - */ - Transform get_reference_frame() const; - void center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height); - - /* - get_hmd_transform gets our hmd transform (centered between eyes) with most up to date tracking, relative to the origin - */ - Transform get_hmd_transform(); - - /* - Interfaces are objects that 'glue' Godot to an AR or VR SDK such as the Oculus SDK, OpenVR, OpenHMD, etc. - */ - void add_interface(const Ref &p_interface); - void remove_interface(const Ref &p_interface); - int get_interface_count() const; - Ref get_interface(int p_index) const; - Ref find_interface(const String &p_name) const; - Array get_interfaces() const; - - /* - note, more then one interface can technically be active, especially on mobile, but only one interface is used for - rendering. This interface identifies itself by calling set_primary_interface when it is initialized - */ - Ref get_primary_interface() const; - void set_primary_interface(const Ref &p_primary_interface); - void clear_primary_interface_if(const Ref &p_primary_interface); /* this is automatically called if an interface destructs */ - - /* - Our trackers are objects that expose the orientation and position of physical devices such as controller, anchor points, etc. - They are created and managed by our active AR/VR interfaces. - */ - bool is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const; - int get_free_tracker_id_for_type(TrackerType p_tracker_type); - void add_tracker(ARVRPositionalTracker *p_tracker); - void remove_tracker(ARVRPositionalTracker *p_tracker); - int get_tracker_count() const; - ARVRPositionalTracker *get_tracker(int p_index) const; - ARVRPositionalTracker *find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const; - - uint64_t get_last_process_usec(); - uint64_t get_last_commit_usec(); - uint64_t get_last_frame_usec(); - - void _process(); - void _mark_commit(); - - ARVRServer(); - ~ARVRServer(); -}; - -#define ARVR ARVRServer - -VARIANT_ENUM_CAST(ARVRServer::TrackerType); -VARIANT_ENUM_CAST(ARVRServer::RotationMode); - -#endif diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 64b48bea50..dadd26dade 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -33,9 +33,6 @@ #include "core/engine.h" #include "core/project_settings.h" -#include "arvr/arvr_interface.h" -#include "arvr/arvr_positional_tracker.h" -#include "arvr_server.h" #include "audio/audio_effect.h" #include "audio/audio_stream.h" #include "audio/effects/audio_effect_amplify.h" @@ -67,6 +64,9 @@ #include "physics_server_3d.h" #include "rendering_server.h" #include "servers/rendering/shader_types.h" +#include "xr/xr_interface.h" +#include "xr/xr_positional_tracker.h" +#include "xr_server.h" ShaderTypes *shader_types = nullptr; @@ -102,11 +102,15 @@ void register_server_types() { ClassDB::register_class(); ClassDB::register_virtual_class(); ClassDB::register_virtual_class(); - ClassDB::register_class(); + ClassDB::register_class(); ClassDB::register_class(); - ClassDB::register_virtual_class(); - ClassDB::register_class(); + ClassDB::register_virtual_class(); + ClassDB::register_class(); + + ClassDB::add_compatibility_class("ARVRServer", "XRServer"); + ClassDB::add_compatibility_class("ARVRInterface", "XRInterface"); + ClassDB::add_compatibility_class("ARVRPositionalTracker", "XRPositionalTracker"); ClassDB::register_virtual_class(); ClassDB::register_virtual_class(); @@ -198,6 +202,6 @@ void register_server_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut())); Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut())); - Engine::get_singleton()->add_singleton(Engine::Singleton("ARVRServer", ARVRServer::get_singleton())); + Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton())); Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton())); } diff --git a/servers/rendering/rendering_server_raster.h b/servers/rendering/rendering_server_raster.h index 1162946796..1b9755397a 100644 --- a/servers/rendering/rendering_server_raster.h +++ b/servers/rendering/rendering_server_raster.h @@ -456,7 +456,7 @@ public: BIND0R(RID, viewport_create) - BIND2(viewport_set_use_arvr, RID, bool) + BIND2(viewport_set_use_xr, RID, bool) BIND3(viewport_set_size, RID, int, int) BIND2(viewport_set_active, RID, bool) diff --git a/servers/rendering/rendering_server_scene.cpp b/servers/rendering/rendering_server_scene.cpp index a367d4522c..4f40012c98 100644 --- a/servers/rendering/rendering_server_scene.cpp +++ b/servers/rendering/rendering_server_scene.cpp @@ -1883,7 +1883,7 @@ void RenderingServerScene::render_camera(RID p_render_buffers, RID p_camera, RID #endif } -void RenderingServerScene::render_camera(RID p_render_buffers, Ref &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { +void RenderingServerScene::render_camera(RID p_render_buffers, Ref &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas) { // render for AR/VR interface Camera *camera = camera_owner.getornull(p_camera); @@ -1895,16 +1895,14 @@ void RenderingServerScene::render_camera(RID p_render_buffers, Refget_world_origin(); + Transform world_origin = XRServer::get_singleton()->get_world_origin(); Transform cam_transform = p_interface->get_transform_for_eye(p_eye, world_origin); // For stereo render we only prepare for our left eye and then reuse the outcome for our right eye - if (p_eye == ARVRInterface::EYE_LEFT) { - ///@TODO possibly move responsibility for this into our ARVRServer or ARVRInterface? - + if (p_eye == XRInterface::EYE_LEFT) { // Center our transform, we assume basis is equal. Transform mono_transform = cam_transform; - Transform right_transform = p_interface->get_transform_for_eye(ARVRInterface::EYE_RIGHT, world_origin); + Transform right_transform = p_interface->get_transform_for_eye(XRInterface::EYE_RIGHT, world_origin); mono_transform.origin += right_transform.origin; mono_transform.origin *= 0.5; @@ -1958,7 +1956,7 @@ void RenderingServerScene::render_camera(RID p_render_buffers, Refenv, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); - } else if (p_eye == ARVRInterface::EYE_MONO) { + } else if (p_eye == XRInterface::EYE_MONO) { // For mono render, prepare as per usual _prepare_scene(cam_transform, camera_matrix, false, false, camera->env, camera->effects, camera->visible_layers, p_scenario, p_shadow_atlas, RID()); } diff --git a/servers/rendering/rendering_server_scene.h b/servers/rendering/rendering_server_scene.h index 80f226e1cb..0970fed6c4 100644 --- a/servers/rendering/rendering_server_scene.h +++ b/servers/rendering/rendering_server_scene.h @@ -39,7 +39,7 @@ #include "core/os/thread.h" #include "core/rid_owner.h" #include "core/self_list.h" -#include "servers/arvr/arvr_interface.h" +#include "servers/xr/xr_interface.h" class RenderingServerScene { public: @@ -426,7 +426,7 @@ public: void render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas); void render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); - void render_camera(RID p_render_buffers, Ref &p_interface, ARVRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); + void render_camera(RID p_render_buffers, Ref &p_interface, XRInterface::Eyes p_eye, RID p_camera, RID p_scenario, Size2 p_viewport_size, RID p_shadow_atlas); void update_dirty_instances(); void render_probes(); diff --git a/servers/rendering/rendering_server_viewport.cpp b/servers/rendering/rendering_server_viewport.cpp index aa65101ddf..87dcb772bc 100644 --- a/servers/rendering/rendering_server_viewport.cpp +++ b/servers/rendering/rendering_server_viewport.cpp @@ -62,24 +62,24 @@ static Transform2D _canvas_get_transform(RenderingServerViewport::Viewport *p_vi return xf; } -void RenderingServerViewport::_draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye) { +void RenderingServerViewport::_draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye) { RENDER_TIMESTAMP(">Begin Rendering 3D Scene"); - Ref arvr_interface; - if (ARVRServer::get_singleton() != nullptr) { - arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); + Ref xr_interface; + if (XRServer::get_singleton() != nullptr) { + xr_interface = XRServer::get_singleton()->get_primary_interface(); } - if (p_viewport->use_arvr && arvr_interface.is_valid()) { - RSG::scene->render_camera(p_viewport->render_buffers, arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); + if (p_viewport->use_xr && xr_interface.is_valid()) { + RSG::scene->render_camera(p_viewport->render_buffers, xr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); } else { RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas); } RENDER_TIMESTAMP(" arvr_interface; + // get our xr interface in case we need it + Ref xr_interface; - if (ARVRServer::get_singleton() != nullptr) { - arvr_interface = ARVRServer::get_singleton()->get_primary_interface(); + if (XRServer::get_singleton() != nullptr) { + xr_interface = XRServer::get_singleton()->get_primary_interface(); // process all our active interfaces - ARVRServer::get_singleton()->_process(); + XRServer::get_singleton()->_process(); } -#endif if (Engine::get_singleton()->is_editor_hint()) { set_default_clear_color(GLOBAL_GET("rendering/environment/default_clear_color")); @@ -367,38 +365,41 @@ void RenderingServerViewport::draw_viewports() { RSG::storage->render_target_set_as_unused(vp->render_target); #if 0 - if (vp->use_arvr && arvr_interface.is_valid()) { + // TODO fix up this code after we change our commit_for_eye to accept our new render targets + + if (vp->use_xr && xr_interface.is_valid()) { // override our size, make sure it matches our required size - vp->size = arvr_interface->get_render_targetsize(); + vp->size = xr_interface->get_render_targetsize(); RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y); // render mono or left eye first - ARVRInterface::Eyes leftOrMono = arvr_interface->is_stereo() ? ARVRInterface::EYE_LEFT : ARVRInterface::EYE_MONO; + XRInterface::Eyes leftOrMono = xr_interface->is_stereo() ? XRInterface::EYE_LEFT : XRInterface::EYE_MONO; // check for an external texture destination for our left eye/mono - RSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(leftOrMono)); + // TODO investigate how we're going to make external textures work + RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono)); // set our render target as current RSG::rasterizer->set_current_render_target(vp->render_target); // and draw left eye/mono _draw_viewport(vp, leftOrMono); - arvr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect); + xr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect); // render right eye - if (leftOrMono == ARVRInterface::EYE_LEFT) { + if (leftOrMono == XRInterface::EYE_LEFT) { // check for an external texture destination for our right eye - RSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(ARVRInterface::EYE_RIGHT)); + RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(XRInterface::EYE_RIGHT)); // commit for eye may have changed the render target RSG::rasterizer->set_current_render_target(vp->render_target); - _draw_viewport(vp, ARVRInterface::EYE_RIGHT); - arvr_interface->commit_for_eye(ARVRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect); + _draw_viewport(vp, XRInterface::EYE_RIGHT); + xr_interface->commit_for_eye(XRInterface::EYE_RIGHT, vp->render_target, vp->viewport_to_screen_rect); } // and for our frame timing, mark when we've finished committing our eyes - ARVRServer::get_singleton()->_mark_commit(); + XRServer::get_singleton()->_mark_commit(); } else { #endif { @@ -470,11 +471,11 @@ RID RenderingServerViewport::viewport_create() { return rid; } -void RenderingServerViewport::viewport_set_use_arvr(RID p_viewport, bool p_use_arvr) { +void RenderingServerViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { Viewport *viewport = viewport_owner.getornull(p_viewport); ERR_FAIL_COND(!viewport); - viewport->use_arvr = p_use_arvr; + viewport->use_xr = p_use_xr; } void RenderingServerViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { diff --git a/servers/rendering/rendering_server_viewport.h b/servers/rendering/rendering_server_viewport.h index f574c58d96..71d8408ed1 100644 --- a/servers/rendering/rendering_server_viewport.h +++ b/servers/rendering/rendering_server_viewport.h @@ -34,8 +34,8 @@ #include "core/rid_owner.h" #include "core/self_list.h" #include "rasterizer.h" -#include "servers/arvr/arvr_interface.h" #include "servers/rendering_server.h" +#include "servers/xr/xr_interface.h" class RenderingServerViewport { public: @@ -47,7 +47,7 @@ public: RID self; RID parent; - bool use_arvr; /* use arvr interface to override camera positioning and projection matrices and control output */ + bool use_xr; /* use xr interface to override camera positioning and projection matrices and control output */ Size2i size; RID camera; @@ -127,7 +127,7 @@ public: for (int i = 0; i < RS::VIEWPORT_RENDER_INFO_MAX; i++) { render_info[i] = 0; } - use_arvr = false; + use_xr = false; } }; @@ -152,13 +152,13 @@ public: Vector active_viewports; private: - void _draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye); - void _draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye = ARVRInterface::EYE_MONO); + void _draw_3d(Viewport *p_viewport, XRInterface::Eyes p_eye); + void _draw_viewport(Viewport *p_viewport, XRInterface::Eyes p_eye = XRInterface::EYE_MONO); public: RID viewport_create(); - void viewport_set_use_arvr(RID p_viewport, bool p_use_arvr); + void viewport_set_use_xr(RID p_viewport, bool p_use_xr); void viewport_set_size(RID p_viewport, int p_width, int p_height); diff --git a/servers/rendering/rendering_server_wrap_mt.h b/servers/rendering/rendering_server_wrap_mt.h index a3077980ce..9a98841b2c 100644 --- a/servers/rendering/rendering_server_wrap_mt.h +++ b/servers/rendering/rendering_server_wrap_mt.h @@ -370,7 +370,7 @@ public: FUNCRID(viewport) - FUNC2(viewport_set_use_arvr, RID, bool) + FUNC2(viewport_set_use_xr, RID, bool) FUNC3(viewport_set_size, RID, int, int) diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index d492586ce4..0a1b7b98e4 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -1766,7 +1766,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("camera_set_use_vertical_aspect", "camera", "enable"), &RenderingServer::camera_set_use_vertical_aspect); ClassDB::bind_method(D_METHOD("viewport_create"), &RenderingServer::viewport_create); - ClassDB::bind_method(D_METHOD("viewport_set_use_arvr", "viewport", "use_arvr"), &RenderingServer::viewport_set_use_arvr); + ClassDB::bind_method(D_METHOD("viewport_set_use_xr", "viewport", "use_xr"), &RenderingServer::viewport_set_use_xr); ClassDB::bind_method(D_METHOD("viewport_set_size", "viewport", "width", "height"), &RenderingServer::viewport_set_size); ClassDB::bind_method(D_METHOD("viewport_set_active", "viewport", "active"), &RenderingServer::viewport_set_active); ClassDB::bind_method(D_METHOD("viewport_set_parent_viewport", "viewport", "parent_viewport"), &RenderingServer::viewport_set_parent_viewport); diff --git a/servers/rendering_server.h b/servers/rendering_server.h index ddae78cb1f..cb7c2cecf6 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -580,7 +580,7 @@ public: virtual RID viewport_create() = 0; - virtual void viewport_set_use_arvr(RID p_viewport, bool p_use_arvr) = 0; + virtual void viewport_set_use_xr(RID p_viewport, bool p_use_xr) = 0; virtual void viewport_set_size(RID p_viewport, int p_width, int p_height) = 0; virtual void viewport_set_active(RID p_viewport, bool p_active) = 0; virtual void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) = 0; diff --git a/servers/xr/SCsub b/servers/xr/SCsub new file mode 100644 index 0000000000..86681f9c74 --- /dev/null +++ b/servers/xr/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp new file mode 100644 index 0000000000..c1233ae810 --- /dev/null +++ b/servers/xr/xr_interface.cpp @@ -0,0 +1,145 @@ +/*************************************************************************/ +/* xr_interface.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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.h" + +void XRInterface::_bind_methods() { + 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("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); + + 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"); + + // we don't have any properties specific to VR yet.... + + // but we do have 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); + + ADD_GROUP("AR", "ar_"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ar_is_anchor_detection_enabled"), "set_anchor_detection_is_enabled", "get_anchor_detection_is_enabled"); + + BIND_ENUM_CONSTANT(XR_NONE); + BIND_ENUM_CONSTANT(XR_MONO); + BIND_ENUM_CONSTANT(XR_STEREO); + 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"; +}; + +bool XRInterface::is_primary() { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, false); + + return xr_server->get_primary_interface() == this; +}; + +void XRInterface::set_is_primary(bool p_is_primary) { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL(xr_server); + + if (p_is_primary) { + ERR_FAIL_COND(!is_initialized()); + + xr_server->set_primary_interface(this); + } else { + xr_server->clear_primary_interface_if(this); + }; +}; + +void XRInterface::set_is_initialized(bool p_initialized) { + if (p_initialized) { + if (!is_initialized()) { + initialize(); + }; + } else { + if (is_initialized()) { + uninitialize(); + }; + }; +}; + +XRInterface::Tracking_status XRInterface::get_tracking_status() const { + return tracking_state; +}; + +XRInterface::XRInterface() { + tracking_state = XR_UNKNOWN_TRACKING; +}; + +XRInterface::~XRInterface(){}; + +// 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; +}; + +/** 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; +}; diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h new file mode 100644 index 0000000000..99fcef7925 --- /dev/null +++ b/servers/xr/xr_interface.h @@ -0,0 +1,126 @@ +/*************************************************************************/ +/* xr_interface.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_H +#define XR_INTERFACE_H + +#include "core/math/camera_matrix.h" +#include "core/os/thread_safe.h" +#include "scene/main/window.h" +#include "servers/xr_server.h" + +/** + @author Bastiaan Olij + + The XR interface is a template class ontop 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. + + If the user wants to enable AR/VR the choose the interface they want to use and initialize it. + + Note that we may make this into a fully instantiable class for GDNative support. +*/ + +class XRInterface : public Reference { + GDCLASS(XRInterface, Reference); + +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 + }; + + enum Tracking_status { /* 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, + XR_UNKNOWN_TRACKING, + XR_NOT_TRACKING + }; + +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; + + bool is_primary(); + void set_is_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 */ + + /** specific to VR **/ + // nothing yet + + /** specific to AR **/ + virtual bool get_anchor_detection_is_enabled() const; + virtual void set_anchor_detection_is_enabled(bool p_enable); + virtual int get_camera_feed_id(); + + /** 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 void process() = 0; + virtual void notification(int p_what) = 0; + + XRInterface(); + ~XRInterface(); +}; + +VARIANT_ENUM_CAST(XRInterface::Capabilities); +VARIANT_ENUM_CAST(XRInterface::Eyes); +VARIANT_ENUM_CAST(XRInterface::Tracking_status); + +#endif diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp new file mode 100644 index 0000000000..808b0a608f --- /dev/null +++ b/servers/xr/xr_positional_tracker.cpp @@ -0,0 +1,237 @@ +/*************************************************************************/ +/* xr_positional_tracker.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_positional_tracker.h" +#include "core/input/input_filter.h" + +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); + 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) { + 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 { + return type; +}; + +void XRPositionalTracker::set_name(const String &p_name) { + name = p_name; +}; + +StringName XRPositionalTracker::get_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; +}; + +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; +}; + +Basis XRPositionalTracker::get_orientation() const { + _THREAD_SAFE_METHOD_ + + return orientation; +}; + +bool XRPositionalTracker::get_tracks_position() const { + return tracks_position; +}; + +void XRPositionalTracker::set_position(const Vector3 &p_position) { + _THREAD_SAFE_METHOD_ + + 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_ + + return rw_position; +}; + +void XRPositionalTracker::set_mesh(const Ref &p_mesh) { + _THREAD_SAFE_METHOD_ + + mesh = p_mesh; +}; + +Ref XRPositionalTracker::get_mesh() const { + _THREAD_SAFE_METHOD_ + + return mesh; +}; + +XRPositionalTracker::TrackerHand XRPositionalTracker::get_hand() const { + return hand; +}; + +void XRPositionalTracker::set_hand(const XRPositionalTracker::TrackerHand p_hand) { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL(xr_server); + + 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)); + + 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; + }; + }; + }; +}; + +Transform XRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const { + Transform new_transform; + + new_transform.basis = get_orientation(); + new_transform.origin = get_position(); + + if (p_adjust_by_reference_frame) { + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, new_transform); + + new_transform = xr_server->get_reference_frame() * new_transform; + }; + + return new_transform; +}; + +real_t XRPositionalTracker::get_rumble() const { + return rumble; +}; + +void XRPositionalTracker::set_rumble(real_t p_rumble) { + if (p_rumble > 0.0) { + rumble = p_rumble; + } else { + rumble = 0.0; + }; +}; + +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; +}; + +XRPositionalTracker::~XRPositionalTracker(){ + +}; diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h new file mode 100644 index 0000000000..d9d1f909e9 --- /dev/null +++ b/servers/xr/xr_positional_tracker.h @@ -0,0 +1,104 @@ +/*************************************************************************/ +/* xr_positional_tracker.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_POSITIONAL_TRACKER_H +#define XR_POSITIONAL_TRACKER_H + +#include "core/os/thread_safe.h" +#include "scene/resources/mesh.h" +#include "servers/xr_server.h" + +/** + @author Bastiaan Olij + + The positional tracker object as an object that represents the position and orientation of a tracked object like a controller or headset. + An AR/VR Interface will registered the trackers it manages with our AR/VR server and update its position and orientation. + 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); + _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 */ + }; + +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 + 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; // 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); + real_t get_rumble() const; + void set_rumble(real_t p_rumble); + void set_mesh(const Ref &p_mesh); + Ref get_mesh() const; + + Transform get_transform(bool p_adjust_by_reference_frame) const; + + XRPositionalTracker(); + ~XRPositionalTracker(); +}; + +VARIANT_ENUM_CAST(XRPositionalTracker::TrackerHand); + +#endif diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp new file mode 100644 index 0000000000..a93b99025f --- /dev/null +++ b/servers/xr_server.cpp @@ -0,0 +1,386 @@ +/*************************************************************************/ +/* xr_server.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_server.h" +#include "core/project_settings.h" +#include "xr/xr_interface.h" +#include "xr/xr_positional_tracker.h" + +XRServer *XRServer::singleton = nullptr; + +XRServer *XRServer::get_singleton() { + return singleton; +}; + +void XRServer::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_world_scale"), &XRServer::get_world_scale); + ClassDB::bind_method(D_METHOD("set_world_scale"), &XRServer::set_world_scale); + ClassDB::bind_method(D_METHOD("get_reference_frame"), &XRServer::get_reference_frame); + ClassDB::bind_method(D_METHOD("center_on_hmd", "rotation_mode", "keep_height"), &XRServer::center_on_hmd); + ClassDB::bind_method(D_METHOD("get_hmd_transform"), &XRServer::get_hmd_transform); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale"); + + ClassDB::bind_method(D_METHOD("get_interface_count"), &XRServer::get_interface_count); + ClassDB::bind_method(D_METHOD("get_interface", "idx"), &XRServer::get_interface); + ClassDB::bind_method(D_METHOD("get_interfaces"), &XRServer::get_interfaces); + ClassDB::bind_method(D_METHOD("find_interface", "name"), &XRServer::find_interface); + ClassDB::bind_method(D_METHOD("get_tracker_count"), &XRServer::get_tracker_count); + ClassDB::bind_method(D_METHOD("get_tracker", "idx"), &XRServer::get_tracker); + + ClassDB::bind_method(D_METHOD("get_primary_interface"), &XRServer::get_primary_interface); + ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_primary_interface); + + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "primary_interface"), "set_primary_interface", "get_primary_interface"); + + ClassDB::bind_method(D_METHOD("get_last_process_usec"), &XRServer::get_last_process_usec); + ClassDB::bind_method(D_METHOD("get_last_commit_usec"), &XRServer::get_last_commit_usec); + ClassDB::bind_method(D_METHOD("get_last_frame_usec"), &XRServer::get_last_frame_usec); + + BIND_ENUM_CONSTANT(TRACKER_CONTROLLER); + BIND_ENUM_CONSTANT(TRACKER_BASESTATION); + BIND_ENUM_CONSTANT(TRACKER_ANCHOR); + BIND_ENUM_CONSTANT(TRACKER_ANY_KNOWN); + BIND_ENUM_CONSTANT(TRACKER_UNKNOWN); + BIND_ENUM_CONSTANT(TRACKER_ANY); + + BIND_ENUM_CONSTANT(RESET_FULL_ROTATION); + BIND_ENUM_CONSTANT(RESET_BUT_KEEP_TILT); + BIND_ENUM_CONSTANT(DONT_RESET_ROTATION); + + ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING_NAME, "interface_name"))); + ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING_NAME, "interface_name"))); + + ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id"))); +}; + +real_t XRServer::get_world_scale() const { + return world_scale; +}; + +void XRServer::set_world_scale(real_t p_world_scale) { + if (p_world_scale < 0.01) { + p_world_scale = 0.01; + } else if (p_world_scale > 1000.0) { + p_world_scale = 1000.0; + } + + world_scale = p_world_scale; +}; + +Transform XRServer::get_world_origin() const { + return world_origin; +}; + +void XRServer::set_world_origin(const Transform &p_world_origin) { + world_origin = p_world_origin; +}; + +Transform XRServer::get_reference_frame() const { + return reference_frame; +}; + +void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) { + if (primary_interface != nullptr) { + // clear our current reference frame or we'll end up double adjusting it + reference_frame = Transform(); + + // requesting our EYE_MONO transform should return our current HMD position + Transform new_reference_frame = primary_interface->get_transform_for_eye(XRInterface::EYE_MONO, Transform()); + + // remove our tilt + if (p_rotation_mode == 1) { + // take the Y out of our Z + new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized()); + + // Y is straight up + new_reference_frame.basis.set_axis(1, Vector3(0.0, 1.0, 0.0)); + + // and X is our cross reference + new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized()); + } else if (p_rotation_mode == 2) { + // remove our rotation, we're only interesting in centering on position + new_reference_frame.basis = Basis(); + }; + + // don't negate our height + if (p_keep_height) { + new_reference_frame.origin.y = 0.0; + }; + + reference_frame = new_reference_frame.inverse(); + }; +}; + +Transform XRServer::get_hmd_transform() { + Transform hmd_transform; + if (primary_interface != nullptr) { + hmd_transform = primary_interface->get_transform_for_eye(XRInterface::EYE_MONO, hmd_transform); + }; + return hmd_transform; +}; + +void XRServer::add_interface(const Ref &p_interface) { + ERR_FAIL_COND(p_interface.is_null()); + + for (int i = 0; i < interfaces.size(); i++) { + + if (interfaces[i] == p_interface) { + ERR_PRINT("Interface was already added"); + return; + }; + }; + + interfaces.push_back(p_interface); + emit_signal("interface_added", p_interface->get_name()); +}; + +void XRServer::remove_interface(const Ref &p_interface) { + ERR_FAIL_COND(p_interface.is_null()); + + int idx = -1; + for (int i = 0; i < interfaces.size(); i++) { + + if (interfaces[i] == p_interface) { + + idx = i; + break; + }; + }; + + ERR_FAIL_COND(idx == -1); + + print_verbose("XR: Removed interface" + p_interface->get_name()); + + emit_signal("interface_removed", p_interface->get_name()); + interfaces.remove(idx); +}; + +int XRServer::get_interface_count() const { + return interfaces.size(); +}; + +Ref XRServer::get_interface(int p_index) const { + ERR_FAIL_INDEX_V(p_index, interfaces.size(), nullptr); + + return interfaces[p_index]; +}; + +Ref XRServer::find_interface(const String &p_name) const { + int idx = -1; + for (int i = 0; i < interfaces.size(); i++) { + + if (interfaces[i]->get_name() == p_name) { + + idx = i; + break; + }; + }; + + ERR_FAIL_COND_V(idx == -1, nullptr); + + return interfaces[idx]; +}; + +Array XRServer::get_interfaces() const { + Array ret; + + for (int i = 0; i < interfaces.size(); i++) { + Dictionary iface_info; + + iface_info["id"] = i; + iface_info["name"] = interfaces[i]->get_name(); + + ret.push_back(iface_info); + }; + + return ret; +}; + +/* + A little extra info on the tracker ids, these are unique per tracker type so we get some consistency in recognising our trackers, specifically controllers. + + The first controller that is turned of will get ID 1, the second will get ID 2, etc. + The magic happens when one of the controllers is turned off, say controller 1 turns off, controller 2 will remain controller 2, controller 3 will remain controller 3. + If controller number 1 is turned on again it again gets ID 1 unless another new controller was turned on since. + + The most likely scenario however is a controller that runs out of battery and another controller being used to replace it. + Because the controllers are often linked to physical objects, say you're holding a shield in controller 1, your left hand, and a gun in controller 2, your right hand, and controller 1 dies: + - using our tracker index would suddenly make the gun disappear and the shield jump into your right hand because controller 2 becomes controller 1. + - using this approach the shield disappears or is no longer tracked, but the gun stays firmly in your right hand because that is still controller 2, further more, if controller 1 is replaced the shield will return. +*/ + +bool XRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const { + for (int i = 0; i < trackers.size(); i++) { + if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + return true; + }; + }; + + // all good + return false; +}; + +int XRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) { + // We start checking at 1, 0 means that it's not a controller.. + // Note that for controller we reserve: + // - 1 for the left hand controller and + // - 2 for the right hand controller + // so we start at 3 :) + int tracker_id = p_tracker_type == XRServer::TRACKER_CONTROLLER ? 3 : 1; + + while (is_tracker_id_in_use_for_type(p_tracker_type, tracker_id)) { + // try the next one + tracker_id++; + }; + + return tracker_id; +}; + +void XRServer::add_tracker(XRPositionalTracker *p_tracker) { + ERR_FAIL_NULL(p_tracker); + + trackers.push_back(p_tracker); + emit_signal("tracker_added", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); +}; + +void XRServer::remove_tracker(XRPositionalTracker *p_tracker) { + ERR_FAIL_NULL(p_tracker); + + int idx = -1; + for (int i = 0; i < trackers.size(); i++) { + + if (trackers[i] == p_tracker) { + + idx = i; + break; + }; + }; + + ERR_FAIL_COND(idx == -1); + + emit_signal("tracker_removed", p_tracker->get_name(), p_tracker->get_type(), p_tracker->get_tracker_id()); + trackers.remove(idx); +}; + +int XRServer::get_tracker_count() const { + return trackers.size(); +}; + +XRPositionalTracker *XRServer::get_tracker(int p_index) const { + ERR_FAIL_INDEX_V(p_index, trackers.size(), nullptr); + + return trackers[p_index]; +}; + +XRPositionalTracker *XRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const { + ERR_FAIL_COND_V(p_tracker_id == 0, nullptr); + + for (int i = 0; i < trackers.size(); i++) { + if (trackers[i]->get_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { + return trackers[i]; + }; + }; + + return nullptr; +}; + +Ref XRServer::get_primary_interface() const { + return primary_interface; +}; + +void XRServer::set_primary_interface(const Ref &p_primary_interface) { + primary_interface = p_primary_interface; + + print_verbose("XR: Primary interface set to: " + primary_interface->get_name()); +}; + +void XRServer::clear_primary_interface_if(const Ref &p_primary_interface) { + if (primary_interface == p_primary_interface) { + print_verbose("XR: Clearing primary interface"); + primary_interface.unref(); + }; +}; + +uint64_t XRServer::get_last_process_usec() { + return last_process_usec; +}; + +uint64_t XRServer::get_last_commit_usec() { + return last_commit_usec; +}; + +uint64_t XRServer::get_last_frame_usec() { + return last_frame_usec; +}; + +void XRServer::_process() { + /* called from rendering_server_viewport.draw_viewports right before we start drawing our viewports */ + + /* mark for our frame timing */ + last_process_usec = OS::get_singleton()->get_ticks_usec(); + + /* process all active interfaces */ + for (int i = 0; i < interfaces.size(); i++) { + if (!interfaces[i].is_valid()) { + // ignore, not a valid reference + } else if (interfaces[i]->is_initialized()) { + interfaces.write[i]->process(); + }; + }; +}; + +void XRServer::_mark_commit() { + /* time this */ + last_commit_usec = OS::get_singleton()->get_ticks_usec(); + + /* now store our difference as we may overwrite last_process_usec before this is accessed */ + last_frame_usec = last_commit_usec - last_process_usec; +}; + +XRServer::XRServer() { + singleton = this; + world_scale = 1.0; +}; + +XRServer::~XRServer() { + primary_interface.unref(); + + while (interfaces.size() > 0) { + interfaces.remove(0); + } + + while (trackers.size() > 0) { + trackers.remove(0); + } + + singleton = nullptr; +}; diff --git a/servers/xr_server.h b/servers/xr_server.h new file mode 100644 index 0000000000..e04c7b3592 --- /dev/null +++ b/servers/xr_server.h @@ -0,0 +1,192 @@ +/*************************************************************************/ +/* xr_server.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 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_SERVER_H +#define XR_SERVER_H + +#include "core/os/os.h" +#include "core/os/thread_safe.h" +#include "core/reference.h" +#include "core/rid.h" +#include "core/variant.h" + +class XRInterface; +class XRPositionalTracker; + +/** + @author Bastiaan Olij + + The XR server is a singleton object that gives access to the various + objects and SDKs that are available on the system. + Because there can be multiple SDKs active this is exposed as an array + and our XR server object acts as a pass through + Also each positioning tracker is accessible from here. + + I've added some additional info into this header file that should move + into the documentation, I will do so when we're close to accepting this PR + or as a separate PR once this has been merged into the master branch. +**/ + +class XRServer : public Object { + GDCLASS(XRServer, Object); + _THREAD_SAFE_CLASS_ + +public: + enum TrackerType { + TRACKER_CONTROLLER = 0x01, /* tracks a controller */ + TRACKER_BASESTATION = 0x02, /* tracks location of a base station */ + TRACKER_ANCHOR = 0x04, /* tracks an anchor point, used in AR to track a real live location */ + TRACKER_UNKNOWN = 0x80, /* unknown tracker */ + + TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */ + TRACKER_ANY = 0xff /* used by get_connected_trackers to return all types */ + }; + + enum RotationMode { + RESET_FULL_ROTATION = 0, /* we reset the full rotation, regardless of how the HMD is oriented, we're looking dead ahead */ + RESET_BUT_KEEP_TILT = 1, /* reset rotation but keep tilt. */ + DONT_RESET_ROTATION = 2, /* don't reset the rotation, we will only center on position */ + }; + +private: + Vector> interfaces; + Vector trackers; + + Ref primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ + + real_t world_scale; /* scale by which we multiply our tracker positions */ + Transform world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */ + Transform reference_frame; /* our reference frame */ + + uint64_t last_process_usec; /* for frame timing, usec when we did our processing */ + uint64_t last_commit_usec; /* for frame timing, usec when we finished committing both eyes */ + uint64_t last_frame_usec; /* time it took between process and committing, we should probably average this over the last x frames */ + +protected: + static XRServer *singleton; + + static void _bind_methods(); + +public: + static XRServer *get_singleton(); + + /* + World scale allows you to specify a scale factor that is applied to all positioning vectors in our VR world in essence scaling up, or scaling down the world. + For stereoscopic rendering specifically this is very important to give an accurate sense of scale. + Add controllers into the mix and an accurate mapping of real world movement to perceived virtual movement becomes very important. + + Most VR platforms, and our assumption, is that 1 unit in our virtual world equates to 1 meter in the real mode. + This scale basically effects the unit size relationship to real world size. + + I may remove access to this property in GDScript in favour of exposing it on the XROrigin3D node + */ + real_t get_world_scale() const; + void set_world_scale(real_t p_world_scale); + + /* + The world maps the 0,0,0 coordinate of our real world coordinate system for our tracking volume to a location in our + virtual world. It is this origin point that should be moved when the player is moved through the world by controller + actions be it straffing, teleporting, etc. Movement of the player by moving through the physical space is always tracked + in relation to this point. + + Note that the XROrigin3D spatial node in your scene automatically updates this property and it should be used instead of + direct access to this property and it therefore is not available in GDScript + + Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world + and in the virtual world out of sync + */ + Transform get_world_origin() const; + void set_world_origin(const Transform &p_world_origin); + + /* + center_on_hmd calculates a new reference frame. This ensures the HMD is positioned to 0,0,0 facing 0,0,-1 (need to verify this direction) + in the virtual world. + + You can ignore the tilt of the device ensuring you're looking straight forward even if the player is looking down or sideways. + You can chose to keep the height the tracking provides which is important for room scale capable tracking. + + Note: this should not be used in AR and should be ignored by an AR based interface as it would throw what you're looking at in the real world + and in the virtual world out of sync + */ + Transform get_reference_frame() const; + void center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height); + + /* + get_hmd_transform gets our hmd transform (centered between eyes) with most up to date tracking, relative to the origin + */ + Transform get_hmd_transform(); + + /* + Interfaces are objects that 'glue' Godot to an AR or VR SDK such as the Oculus SDK, OpenVR, OpenHMD, etc. + */ + void add_interface(const Ref &p_interface); + void remove_interface(const Ref &p_interface); + int get_interface_count() const; + Ref get_interface(int p_index) const; + Ref find_interface(const String &p_name) const; + Array get_interfaces() const; + + /* + note, more then one interface can technically be active, especially on mobile, but only one interface is used for + rendering. This interface identifies itself by calling set_primary_interface when it is initialized + */ + Ref get_primary_interface() const; + void set_primary_interface(const Ref &p_primary_interface); + void clear_primary_interface_if(const Ref &p_primary_interface); /* this is automatically called if an interface destructs */ + + /* + Our trackers are objects that expose the orientation and position of physical devices such as controller, anchor points, etc. + They are created and managed by our active AR/VR interfaces. + */ + bool is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const; + int get_free_tracker_id_for_type(TrackerType p_tracker_type); + void add_tracker(XRPositionalTracker *p_tracker); + void remove_tracker(XRPositionalTracker *p_tracker); + int get_tracker_count() const; + XRPositionalTracker *get_tracker(int p_index) const; + XRPositionalTracker *find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const; + + uint64_t get_last_process_usec(); + uint64_t get_last_commit_usec(); + uint64_t get_last_frame_usec(); + + void _process(); + void _mark_commit(); + + XRServer(); + ~XRServer(); +}; + +#define XR XRServer + +VARIANT_ENUM_CAST(XRServer::TrackerType); +VARIANT_ENUM_CAST(XRServer::RotationMode); + +#endif -- cgit v1.2.3