Adding GDExtension support to XRInterface

This commit is contained in:
Bastiaan Olij 2021-08-23 15:23:16 +10:00
parent 6e87d62873
commit 86ff7f8550
28 changed files with 494 additions and 1008 deletions

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="XRInterface" inherits="RefCounted" version="4.0">
<brief_description>
Base class for an AR/VR interface implementation.
Base class for an XR interface implementation.
</brief_description>
<description>
This class needs to be implemented to make an AR or VR platform available to Godot and these should be implemented as C++ modules or GDNative modules (note that for GDNative the subclass XRScriptInterface should be used). Part of the interface is exposed to GDScript so you can detect, enable and configure an AR or VR platform.
@ -26,17 +26,17 @@
<method name="get_name" qualifiers="const">
<return type="StringName" />
<description>
Returns the name of this interface (OpenVR, OpenHMD, ARKit, etc).
Returns the name of this interface (OpenXR, OpenVR, OpenHMD, ARKit, etc).
</description>
</method>
<method name="get_render_targetsize">
<method name="get_render_target_size">
<return type="Vector2" />
<description>
Returns the resolution at which we should render our intermediate results before things like lens distortion are applied by the VR platform.
</description>
</method>
<method name="get_tracking_status" qualifiers="const">
<return type="int" enum="XRInterface.Tracking_status" />
<return type="int" enum="XRInterface.TrackingStatus" />
<description>
If supported, returns the status of our tracking. This will allow you to provide feedback to the user whether there are issues with positional tracking.
</description>
@ -52,11 +52,17 @@
<description>
Call this to initialize this interface. The first interface that is initialized is identified as the primary interface and it will be used for rendering output.
After initializing the interface you want to use you then need to enable the AR/VR mode of a viewport and rendering should commence.
[b]Note:[/b] You must enable the AR/VR mode on the main viewport for any device that uses the main output of Godot, such as for mobile VR.
[b]Note:[/b] You must enable the XR mode on the main viewport for any device that uses the main output of Godot, such as for mobile VR.
If you do this for a platform that handles its own output (such as OpenVR) Godot will show just one eye without distortion on screen. Alternatively, you can add a separate viewport node to your scene and enable AR/VR on that viewport. It will be used to output to the HMD, leaving you free to do anything you like in the main window, such as using a separate camera as a spectator camera or rendering something completely different.
While currently not used, you can activate additional interfaces. You may wish to do this if you want to track controllers from other platforms. However, at this point in time only one interface can render to an HMD.
</description>
</method>
<method name="is_initialized" qualifiers="const">
<return type="bool" />
<description>
Is [code]true[/code] if this interface has been initialised.
</description>
</method>
<method name="uninitialize">
<return type="void" />
<description>
@ -68,10 +74,7 @@
<member name="ar_is_anchor_detection_enabled" type="bool" setter="set_anchor_detection_is_enabled" getter="get_anchor_detection_is_enabled" default="false">
On an AR interface, [code]true[/code] if anchor detection is enabled.
</member>
<member name="interface_is_initialized" type="bool" setter="set_is_initialized" getter="is_initialized" default="false">
[code]true[/code] if this interface been initialized.
</member>
<member name="interface_is_primary" type="bool" setter="set_is_primary" getter="is_primary" default="false">
<member name="interface_is_primary" type="bool" setter="set_primary" getter="is_primary" default="false">
[code]true[/code] if this is the primary interface.
</member>
</members>
@ -89,7 +92,7 @@
This interface supports AR (video background and real world tracking).
</constant>
<constant name="XR_EXTERNAL" value="8" enum="Capabilities">
This interface outputs to an external device. If the main viewport is used, the on screen output is an unmodified buffer of either the left or right eye (stretched if the viewport size is not changed to the same aspect ratio of [method get_render_targetsize]). Using a separate viewport node frees up the main viewport for other purposes.
This interface outputs to an external device. If the main viewport is used, the on screen output is an unmodified buffer of either the left or right eye (stretched if the viewport size is not changed to the same aspect ratio of [method get_render_target_size]). Using a separate viewport node frees up the main viewport for other purposes.
</constant>
<constant name="EYE_MONO" value="0" enum="Eyes">
Mono output, this is mostly used internally when retrieving positioning information for our camera node or when stereo scopic rendering is not supported.
@ -100,19 +103,19 @@
<constant name="EYE_RIGHT" value="2" enum="Eyes">
Right eye output, this is mostly used internally when rendering the image for the right eye and obtaining positioning and projection information.
</constant>
<constant name="XR_NORMAL_TRACKING" value="0" enum="Tracking_status">
<constant name="XR_NORMAL_TRACKING" value="0" enum="TrackingStatus">
Tracking is behaving as expected.
</constant>
<constant name="XR_EXCESSIVE_MOTION" value="1" enum="Tracking_status">
<constant name="XR_EXCESSIVE_MOTION" value="1" enum="TrackingStatus">
Tracking is hindered by excessive motion (the player is moving faster than tracking can keep up).
</constant>
<constant name="XR_INSUFFICIENT_FEATURES" value="2" enum="Tracking_status">
<constant name="XR_INSUFFICIENT_FEATURES" value="2" enum="TrackingStatus">
Tracking is hindered by insufficient features, it's too dark (for camera-based tracking), player is blocked, etc.
</constant>
<constant name="XR_UNKNOWN_TRACKING" value="3" enum="Tracking_status">
<constant name="XR_UNKNOWN_TRACKING" value="3" enum="TrackingStatus">
We don't know the status of the tracking or this interface does not provide feedback.
</constant>
<constant name="XR_NOT_TRACKING" value="4" enum="Tracking_status">
<constant name="XR_NOT_TRACKING" value="4" enum="TrackingStatus">
Tracking is not functional (camera not plugged in or obscured, lighthouses turned off, etc.).
</constant>
</constants>

View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="XRInterfaceExtension" inherits="XRInterface" version="4.0">
<brief_description>
Base class for XR interface extensions (plugins).
</brief_description>
<description>
External XR interface plugins should inherit from this class.
</description>
<tutorials>
</tutorials>
<methods>
<method name="_commit_views" qualifiers="virtual">
<return type="void" />
<argument index="0" name="" type="RID" />
<argument index="1" name="" type="Rect2" />
<description>
</description>
</method>
<method name="_get_anchor_detection_is_enabled" qualifiers="virtual const">
<return type="bool" />
<description>
</description>
</method>
<method name="_get_camera_feed_id" qualifiers="virtual const">
<return type="int" />
<description>
</description>
</method>
<method name="_get_camera_transform" qualifiers="virtual">
<return type="Transform3D" />
<description>
</description>
</method>
<method name="_get_capabilities" qualifiers="virtual const">
<return type="int" />
<description>
</description>
</method>
<method name="_get_name" qualifiers="virtual const">
<return type="StringName" />
<description>
</description>
</method>
<method name="_get_projection_for_view" qualifiers="virtual">
<return type="PackedFloat64Array" />
<argument index="0" name="view" type="int" />
<argument index="1" name="aspect" type="float" />
<argument index="2" name="z_near" type="float" />
<argument index="3" name="z_far" type="float" />
<description>
</description>
</method>
<method name="_get_render_target_size" qualifiers="virtual">
<return type="Vector2" />
<description>
</description>
</method>
<method name="_get_tracking_status" qualifiers="virtual const">
<return type="int" />
<description>
</description>
</method>
<method name="_get_transform_for_view" qualifiers="virtual">
<return type="Transform3D" />
<argument index="0" name="view" type="int" />
<argument index="1" name="cam_transform" type="Transform3D" />
<description>
</description>
</method>
<method name="_get_view_count" qualifiers="virtual">
<return type="int" />
<description>
</description>
</method>
<method name="_initialize" qualifiers="virtual">
<return type="bool" />
<description>
</description>
</method>
<method name="_is_initialized" qualifiers="virtual const">
<return type="bool" />
<description>
</description>
</method>
<method name="_notification" qualifiers="virtual">
<return type="void" />
<argument index="0" name="what" type="int" />
<description>
</description>
</method>
<method name="_process" qualifiers="virtual">
<return type="void" />
<description>
</description>
</method>
<method name="_set_anchor_detection_is_enabled" qualifiers="virtual">
<return type="void" />
<argument index="0" name="enabled" type="bool" />
<description>
</description>
</method>
<method name="_uninitialize" qualifiers="virtual">
<return type="void" />
<description>
</description>
</method>
<method name="add_blit">
<return type="void" />
<argument index="0" name="render_target" type="RID" />
<argument index="1" name="rect" type="Rect2i" />
<argument index="2" name="use_layer" type="bool" />
<argument index="3" name="layer" type="int" />
<argument index="4" name="apply_lens_distortion" type="bool" />
<argument index="5" name="eye_center" type="Vector2" />
<argument index="6" name="k1" type="float" />
<argument index="7" name="k2" type="float" />
<argument index="8" name="upscale" type="float" />
<argument index="9" name="aspect_ratio" type="float" />
<description>
Blits our render results to screen optionally applying lens distortion. This can only be called while processing [code]_commit_views[/code].
</description>
</method>
</methods>
<constants>
</constants>
</class>

View file

@ -37,13 +37,6 @@
You should call this method after a few seconds have passed. For instance, when the user requests a realignment of the display holding a designated button on a controller for a short period of time, or when implementing a teleport mechanism.
</description>
</method>
<method name="clear_primary_interface_if">
<return type="void" />
<argument index="0" name="interface" type="XRInterface" />
<description>
Clears our current primary interface if it is set to the provided interface.
</description>
</method>
<method name="find_interface" qualifiers="const">
<return type="XRInterface" />
<argument index="0" name="name" type="String" />

View file

@ -8,7 +8,6 @@ def configure(env):
def get_doc_classes():
return [
"XRInterfaceGDNative",
"GDNative",
"GDNativeLibrary",
"MultiplayerPeerGDNative",

View file

@ -4,7 +4,7 @@
An external library containing functions or script classes to use in Godot.
</brief_description>
<description>
A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as [XRInterfaceGDNative]. The library must be compiled for each platform and architecture that the project will run on.
A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as XRInterfaceGDNative. The library must be compiled for each platform and architecture that the project will run on.
</description>
<tutorials>
<link title="GDNative C example">https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-example.html</link>

View file

@ -1,15 +0,0 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="XRInterfaceGDNative" inherits="XRInterface" version="4.0">
<brief_description>
GDNative wrapper for an XR interface.
</brief_description>
<description>
This is a wrapper class for GDNative implementations of the XR interface. To use a GDNative XR interface, simply instantiate this object and set your GDNative library containing the XR interface implementation.
</description>
<tutorials>
</tutorials>
<methods>
</methods>
<constants>
</constants>
</class>

View file

@ -5047,169 +5047,6 @@
}
]
},
{
"name": "xr",
"type": "XR",
"version": {
"major": 1,
"minor": 1
},
"next": null,
"api": [
{
"name": "godot_xr_register_interface",
"return_type": "void",
"arguments": [
[
"const godot_xr_interface_gdnative *",
"p_interface"
]
]
},
{
"name": "godot_xr_get_worldscale",
"return_type": "godot_real_t",
"arguments": []
},
{
"name": "godot_xr_get_reference_frame",
"return_type": "godot_transform3d",
"arguments": []
},
{
"name": "godot_xr_blit",
"return_type": "void",
"arguments": [
[
"godot_int",
"p_eye"
],
[
"godot_rid *",
"p_render_target"
],
[
"godot_rect2 *",
"p_screen_rect"
]
]
},
{
"name": "godot_xr_get_texid",
"return_type": "godot_int",
"arguments": [
[
"godot_rid *",
"p_render_target"
]
]
},
{
"name": "godot_xr_add_controller",
"return_type": "godot_int",
"arguments": [
[
"char *",
"p_device_name"
],
[
"godot_int",
"p_hand"
],
[
"godot_bool",
"p_tracks_orientation"
],
[
"godot_bool",
"p_tracks_position"
]
]
},
{
"name": "godot_xr_remove_controller",
"return_type": "void",
"arguments": [
[
"godot_int",
"p_controller_id"
]
]
},
{
"name": "godot_xr_set_controller_transform",
"return_type": "void",
"arguments": [
[
"godot_int",
"p_controller_id"
],
[
"godot_transform3d *",
"p_transform"
],
[
"godot_bool",
"p_tracks_orientation"
],
[
"godot_bool",
"p_tracks_position"
]
]
},
{
"name": "godot_xr_set_controller_button",
"return_type": "void",
"arguments": [
[
"godot_int",
"p_controller_id"
],
[
"godot_int",
"p_button"
],
[
"godot_bool",
"p_is_pressed"
]
]
},
{
"name": "godot_xr_set_controller_axis",
"return_type": "void",
"arguments": [
[
"godot_int",
"p_controller_id"
],
[
"godot_int",
"p_exis"
],
[
"godot_real_t",
"p_value"
],
[
"godot_bool",
"p_can_be_negative"
]
]
},
{
"name": "godot_xr_get_controller_rumble",
"return_type": "godot_real_t",
"arguments": [
[
"godot_int",
"p_controller_id"
]
]
}
]
},
{
"name": "videodecoder",
"type": "VIDEODECODER",

View file

@ -19,7 +19,6 @@ def _build_gdnative_api_struct_header(api):
"",
"#include <gdnative/gdnative.h>",
"#include <android/godot_android.h>",
"#include <xr/godot_xr.h>",
"#include <nativescript/godot_nativescript.h>",
"#include <net/godot_net.h>",
"#include <pluginscript/godot_pluginscript.h>",

View file

@ -1,98 +0,0 @@
/*************************************************************************/
/* godot_xr.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef GODOT_NATIVEXR_H
#define GODOT_NATIVEXR_H
#include <gdnative/gdnative.h>
#ifdef __cplusplus
extern "C" {
#endif
// For future versions of the API we should only add new functions at the end of the structure and use the
// version info to detect whether a call is available
// Use these to populate version in your plugin
#define GODOTVR_API_MAJOR 4
#define GODOTVR_API_MINOR 0
typedef struct {
godot_gdnative_api_version version; /* version of our API */
void *(*constructor)(godot_object *);
void (*destructor)(void *);
godot_string (*get_name)(const void *);
godot_int (*get_capabilities)(const void *);
godot_bool (*get_anchor_detection_is_enabled)(const void *);
void (*set_anchor_detection_is_enabled)(void *, godot_bool);
godot_int (*get_view_count)(const void *);
godot_bool (*is_initialized)(const void *);
godot_bool (*initialize)(void *);
void (*uninitialize)(void *);
godot_vector2 (*get_render_targetsize)(const void *);
godot_transform3d (*get_camera_transform)(void *);
godot_transform3d (*get_transform_for_view)(void *, godot_int, godot_transform3d *);
void (*fill_projection_for_view)(void *, godot_real_t *, godot_int, godot_real_t, godot_real_t, godot_real_t);
void (*commit_views)(void *, godot_rid *, godot_rect2 *);
void (*process)(void *);
void (*notification)(void *, godot_int);
godot_int (*get_camera_feed_id)(void *);
// possibly deprecate but adding/keeping as a reminder these are in Godot 3
void (*commit_for_eye)(void *, godot_int, godot_rid *, godot_rect2 *);
godot_int (*get_external_texture_for_eye)(void *, godot_int);
godot_int (*get_external_depth_for_eye)(void *, godot_int);
} godot_xr_interface_gdnative;
void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_interface);
// helper functions to access XRServer data
godot_real_t GDAPI godot_xr_get_worldscale();
godot_transform3d GDAPI godot_xr_get_reference_frame();
// helper functions for rendering
void GDAPI godot_xr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect);
godot_int GDAPI godot_xr_get_texid(godot_rid *p_render_target);
// helper functions for updating XR controllers
godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
void GDAPI godot_xr_remove_controller(godot_int p_controller_id);
void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform3d *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position);
void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed);
void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real_t p_value, godot_bool p_can_be_negative);
godot_real_t GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id);
#ifdef __cplusplus
}
#endif
#endif /* !GODOT_NATIVEXR_H */

View file

@ -38,7 +38,6 @@
#include "net/register_types.h"
#include "pluginscript/register_types.h"
#include "videodecoder/register_types.h"
#include "xr/register_types.h"
#include "core/config/engine.h"
#include "core/config/project_settings.h"
@ -267,7 +266,6 @@ void register_gdnative_types() {
GDNativeCallRegistry::singleton->register_native_call_type("standard_varcall", cb_standard_varcall);
register_net_types();
register_xr_types();
register_nativescript_types();
register_pluginscript_types();
register_videodecoder_types();
@ -331,7 +329,6 @@ void unregister_gdnative_types() {
unregister_videodecoder_types();
unregister_pluginscript_types();
unregister_nativescript_types();
unregister_xr_types();
unregister_net_types();
memdelete(GDNativeCallRegistry::singleton);

View file

@ -1,6 +0,0 @@
#!/usr/bin/env python
Import("env")
Import("env_gdnative")
env_gdnative.add_source_files(env.modules_sources, "*.cpp")

View file

@ -1,40 +0,0 @@
/*************************************************************************/
/* register_types.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "register_types.h"
#include "xr_interface_gdnative.h"
void register_xr_types() {
GDREGISTER_CLASS(XRInterfaceGDNative);
ClassDB::add_compatibility_class("ARVRInterfaceGDNative", "XRInterfaceGDNative");
}
void unregister_xr_types() {
}

View file

@ -1,37 +0,0 @@
/*************************************************************************/
/* register_types.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef XR_REGISTER_TYPES_H
#define XR_REGISTER_TYPES_H
void register_xr_types();
void unregister_xr_types();
#endif // XR_REGISTER_TYPES_H

View file

@ -1,450 +0,0 @@
/*************************************************************************/
/* xr_interface_gdnative.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "xr_interface_gdnative.h"
#include "core/input/input.h"
#include "servers/rendering/rendering_server_globals.h"
#include "servers/xr/xr_positional_tracker.h"
void XRInterfaceGDNative::_bind_methods() {
ADD_PROPERTY_DEFAULT("interface_is_initialized", false);
ADD_PROPERTY_DEFAULT("ar_is_anchor_detection_enabled", false);
}
XRInterfaceGDNative::XRInterfaceGDNative() {
print_verbose("Construct gdnative interface\n");
// we won't have our data pointer until our library gets set
data = nullptr;
interface = nullptr;
}
XRInterfaceGDNative::~XRInterfaceGDNative() {
print_verbose("Destruct gdnative interface\n");
if (interface != nullptr && is_initialized()) {
uninitialize();
};
// cleanup after ourselves
cleanup();
}
void XRInterfaceGDNative::cleanup() {
if (interface != nullptr) {
interface->destructor(data);
data = nullptr;
interface = nullptr;
}
}
void XRInterfaceGDNative::set_interface(const godot_xr_interface_gdnative *p_interface) {
// this should only be called once, just being paranoid..
if (interface) {
cleanup();
interface = NULL;
}
// validate
ERR_FAIL_NULL(p_interface);
ERR_FAIL_COND_MSG(p_interface->version.major < 4, "This is an incompatible GDNative XR plugin.");
// bind to our interface
interface = p_interface;
// Now we do our constructing...
data = interface->constructor((godot_object *)this);
}
StringName XRInterfaceGDNative::get_name() const {
ERR_FAIL_COND_V(interface == nullptr, StringName());
godot_string result = interface->get_name(data);
StringName name = *(String *)&result;
godot_string_destroy(&result);
return name;
}
int XRInterfaceGDNative::get_capabilities() const {
int capabilities;
ERR_FAIL_COND_V(interface == nullptr, 0); // 0 = None
capabilities = interface->get_capabilities(data);
return capabilities;
}
bool XRInterfaceGDNative::get_anchor_detection_is_enabled() const {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->get_anchor_detection_is_enabled(data);
}
void XRInterfaceGDNative::set_anchor_detection_is_enabled(bool p_enable) {
ERR_FAIL_COND(interface == nullptr);
interface->set_anchor_detection_is_enabled(data, p_enable);
}
int XRInterfaceGDNative::get_camera_feed_id() {
ERR_FAIL_COND_V(interface == nullptr, 0);
return (unsigned int)interface->get_camera_feed_id(data);
}
uint32_t XRInterfaceGDNative::get_view_count() {
uint32_t view_count;
ERR_FAIL_COND_V(interface == nullptr, 1);
view_count = interface->get_view_count(data);
return view_count;
}
bool XRInterfaceGDNative::is_initialized() const {
ERR_FAIL_COND_V(interface == nullptr, false);
return interface->is_initialized(data);
}
bool XRInterfaceGDNative::initialize() {
ERR_FAIL_COND_V(interface == nullptr, false);
bool initialized = interface->initialize(data);
if (initialized) {
// if we successfully initialize our interface and we don't have a primary interface yet, this becomes our primary interface
XRServer *xr_server = XRServer::get_singleton();
if ((xr_server != nullptr) && (xr_server->get_primary_interface() == nullptr)) {
xr_server->set_primary_interface(this);
};
};
return initialized;
}
void XRInterfaceGDNative::uninitialize() {
ERR_FAIL_COND(interface == nullptr);
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
// Whatever happens, make sure this is no longer our primary interface
xr_server->clear_primary_interface_if(this);
}
interface->uninitialize(data);
}
Size2 XRInterfaceGDNative::get_render_targetsize() {
ERR_FAIL_COND_V(interface == nullptr, Size2());
godot_vector2 result = interface->get_render_targetsize(data);
Vector2 *vec = (Vector2 *)&result;
return *vec;
}
Transform3D XRInterfaceGDNative::get_camera_transform() {
Transform3D *ret;
ERR_FAIL_COND_V(interface == nullptr, Transform3D());
godot_transform3d t = interface->get_camera_transform(data);
ret = (Transform3D *)&t;
return *ret;
}
Transform3D XRInterfaceGDNative::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
Transform3D *ret;
ERR_FAIL_COND_V(interface == nullptr, Transform3D());
godot_transform3d t = interface->get_transform_for_view(data, (int)p_view, (godot_transform3d *)&p_cam_transform);
ret = (Transform3D *)&t;
return *ret;
}
CameraMatrix XRInterfaceGDNative::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
CameraMatrix cm;
ERR_FAIL_COND_V(interface == nullptr, CameraMatrix());
interface->fill_projection_for_view(data, (godot_real_t *)cm.matrix, (godot_int)p_view, p_aspect, p_z_near, p_z_far);
return cm;
}
Vector<BlitToScreen> XRInterfaceGDNative::commit_views(RID p_render_target, const Rect2 &p_screen_rect) {
// possibly move this as a member variable and add a callback to populate?
Vector<BlitToScreen> blit_to_screen;
ERR_FAIL_COND_V(interface == nullptr, blit_to_screen);
// must implement
interface->commit_views(data, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect);
return blit_to_screen;
}
unsigned int XRInterfaceGDNative::get_external_texture_for_eye(XRInterface::Eyes p_eye) {
ERR_FAIL_COND_V(interface == nullptr, 0);
return (unsigned int)interface->get_external_texture_for_eye(data, (godot_int)p_eye);
}
void XRInterfaceGDNative::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
ERR_FAIL_COND(interface == nullptr);
interface->commit_for_eye(data, (godot_int)p_eye, (godot_rid *)&p_render_target, (godot_rect2 *)&p_screen_rect);
}
void XRInterfaceGDNative::process() {
ERR_FAIL_COND(interface == nullptr);
interface->process(data);
}
void XRInterfaceGDNative::notification(int p_what) {
ERR_FAIL_COND(interface == nullptr);
interface->notification(data, p_what);
}
/////////////////////////////////////////////////////////////////////////////////////
// some helper callbacks
extern "C" {
void GDAPI godot_xr_register_interface(const godot_xr_interface_gdnative *p_interface) {
// Must be on a version 4 plugin
ERR_FAIL_COND_MSG(p_interface->version.major < 4, "GDNative XR interfaces build for Godot 3.x are not supported.");
Ref<XRInterfaceGDNative> new_interface;
new_interface.instantiate();
new_interface->set_interface((const godot_xr_interface_gdnative *)p_interface);
XRServer::get_singleton()->add_interface(new_interface);
}
godot_real_t GDAPI godot_xr_get_worldscale() {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 1.0);
return xr_server->get_world_scale();
}
godot_transform3d GDAPI godot_xr_get_reference_frame() {
godot_transform3d reference_frame;
Transform3D *reference_frame_ptr = (Transform3D *)&reference_frame;
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
*reference_frame_ptr = xr_server->get_reference_frame();
} else {
memnew_placement(&reference_frame, Transform3D);
}
return reference_frame;
}
void GDAPI godot_xr_blit(godot_int p_eye, godot_rid *p_render_target, godot_rect2 *p_rect) {
// blits out our texture as is, handy for preview display of one of the eyes that is already rendered with lens distortion on an external HMD
XRInterface::Eyes eye = (XRInterface::Eyes)p_eye;
#if 0
RID *render_target = (RID *)p_render_target;
#endif
Rect2 screen_rect = *(Rect2 *)p_rect;
if (eye == XRInterface::EYE_LEFT) {
screen_rect.size.x /= 2.0;
} else if (p_eye == XRInterface::EYE_RIGHT) {
screen_rect.size.x /= 2.0;
screen_rect.position.x += screen_rect.size.x;
}
#ifndef _MSC_VER
#warning this needs to be redone
#endif
#if 0
RSG::rasterizer->blit_render_target_to_screen(*render_target, screen_rect, 0);
#endif
}
godot_int GDAPI godot_xr_get_texid(godot_rid *p_render_target) {
// In order to send off our textures to display on our hardware we need the opengl texture ID instead of the render target RID
// This is a handy function to expose that.
#if 0
RID *render_target = (RID *)p_render_target;
RID eye_texture = RSG::storage->render_target_get_texture(*render_target);
#endif
#ifndef _MSC_VER
#warning need to obtain this ID again
#endif
uint32_t texid = 0; //RS::get_singleton()->texture_get_texid(eye_texture);
return texid;
}
godot_int GDAPI godot_xr_add_controller(char *p_device_name, godot_int p_hand, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0);
Input *input = Input::get_singleton();
ERR_FAIL_NULL_V(input, 0);
Ref<XRPositionalTracker> new_tracker;
new_tracker.instantiate();
new_tracker->set_tracker_name(p_device_name);
new_tracker->set_tracker_type(XRServer::TRACKER_CONTROLLER);
if (p_hand == 1) {
new_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_LEFT);
} else if (p_hand == 2) {
new_tracker->set_tracker_hand(XRPositionalTracker::TRACKER_HAND_RIGHT);
}
// also register as joystick...
int joyid = input->get_unused_joy_id();
if (joyid != -1) {
new_tracker->set_joy_id(joyid);
input->joy_connection_changed(joyid, true, p_device_name, "");
}
if (p_tracks_orientation) {
Basis orientation;
new_tracker->set_orientation(orientation);
}
if (p_tracks_position) {
Vector3 position;
new_tracker->set_position(position);
}
// add our tracker to our server and remember its pointer
xr_server->add_tracker(new_tracker);
// note, this ID is only unique within controllers!
return new_tracker->get_tracker_id();
}
void GDAPI godot_xr_remove_controller(godot_int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
Ref<XRPositionalTracker> remove_tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (remove_tracker.is_valid()) {
// unset our joystick if applicable
int joyid = remove_tracker->get_joy_id();
if (joyid != -1) {
input->joy_connection_changed(joyid, false, "", "");
remove_tracker->set_joy_id(-1);
}
// remove our tracker from our server
xr_server->remove_tracker(remove_tracker);
remove_tracker.unref();
}
}
void GDAPI godot_xr_set_controller_transform(godot_int p_controller_id, godot_transform3d *p_transform, godot_bool p_tracks_orientation, godot_bool p_tracks_position) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (tracker.is_valid()) {
Transform3D *transform = (Transform3D *)p_transform;
if (p_tracks_orientation) {
tracker->set_orientation(transform->basis);
}
if (p_tracks_position) {
tracker->set_rw_position(transform->origin);
}
}
}
void GDAPI godot_xr_set_controller_button(godot_int p_controller_id, godot_int p_button, godot_bool p_is_pressed) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (tracker.is_valid()) {
int joyid = tracker->get_joy_id();
if (joyid != -1) {
input->joy_button(joyid, (JoyButton)p_button, p_is_pressed);
}
}
}
void GDAPI godot_xr_set_controller_axis(godot_int p_controller_id, godot_int p_axis, godot_real_t p_value, godot_bool p_can_be_negative) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
Input *input = Input::get_singleton();
ERR_FAIL_NULL(input);
Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (tracker.is_valid()) {
int joyid = tracker->get_joy_id();
if (joyid != -1) {
Input::JoyAxisValue jx;
jx.min = p_can_be_negative ? -1 : 0;
jx.value = p_value;
input->joy_axis(joyid, (JoyAxis)p_axis, jx);
}
}
}
godot_real_t GDAPI godot_xr_get_controller_rumble(godot_int p_controller_id) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL_V(xr_server, 0.0);
Ref<XRPositionalTracker> tracker = xr_server->find_by_type_and_id(XRServer::TRACKER_CONTROLLER, p_controller_id);
if (tracker.is_valid()) {
return tracker->get_rumble();
}
return 0.0;
}
}

View file

@ -39,7 +39,7 @@ StringName MobileVRInterface::get_name() const {
return "Native mobile";
};
int MobileVRInterface::get_capabilities() const {
uint32_t MobileVRInterface::get_capabilities() const {
return XRInterface::XR_STEREO;
};
@ -305,6 +305,10 @@ uint32_t MobileVRInterface::get_view_count() {
return 2;
};
XRInterface::TrackingStatus MobileVRInterface::get_tracking_status() const {
return tracking_state;
}
bool MobileVRInterface::is_initialized() const {
return (initialized);
};
@ -340,16 +344,16 @@ bool MobileVRInterface::initialize() {
void MobileVRInterface::uninitialize() {
if (initialized) {
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
if (xr_server != nullptr && xr_server->get_primary_interface() == this) {
// no longer our primary interface
xr_server->clear_primary_interface_if(this);
xr_server->set_primary_interface(nullptr);
}
initialized = false;
};
};
Size2 MobileVRInterface::get_render_targetsize() {
Size2 MobileVRInterface::get_render_target_size() {
_THREAD_SAFE_METHOD_
// we use half our window size
@ -429,31 +433,6 @@ CameraMatrix MobileVRInterface::get_projection_for_view(uint32_t p_view, real_t
return eye;
};
void MobileVRInterface::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
_THREAD_SAFE_METHOD_
// We must have a valid render target
ERR_FAIL_COND(!p_render_target.is_valid());
// Because we are rendering to our device we must use our main viewport!
ERR_FAIL_COND(p_screen_rect == Rect2());
Rect2 dest = p_screen_rect;
Vector2 eye_center;
// we output half a screen
dest.size.x *= 0.5;
if (p_eye == XRInterface::EYE_LEFT) {
eye_center.x = ((-intraocular_dist / 2.0) + (display_width / 4.0)) / (display_width / 2.0);
} else if (p_eye == XRInterface::EYE_RIGHT) {
dest.position.x = dest.size.x;
eye_center.x = ((intraocular_dist / 2.0) - (display_width / 4.0)) / (display_width / 2.0);
}
// we don't offset the eye center vertically (yet)
eye_center.y = 0.0;
}
Vector<BlitToScreen> MobileVRInterface::commit_views(RID p_render_target, const Rect2 &p_screen_rect) {
_THREAD_SAFE_METHOD_

View file

@ -52,6 +52,7 @@ class MobileVRInterface : public XRInterface {
private:
bool initialized = false;
XRInterface::TrackingStatus tracking_state;
Basis orientation;
// Just set some defaults for these. At some point we need to look at adding a lookup table for common device + headset combos and/or support reading cardboard QR codes
@ -131,13 +132,15 @@ public:
real_t get_k2() const;
virtual StringName get_name() const override;
virtual int get_capabilities() const override;
virtual uint32_t get_capabilities() const override;
virtual TrackingStatus get_tracking_status() const override;
virtual bool is_initialized() const override;
virtual bool initialize() override;
virtual void uninitialize() override;
virtual Size2 get_render_targetsize() override;
virtual Size2 get_render_target_size() override;
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
@ -145,13 +148,9 @@ public:
virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
virtual void process() override;
virtual void notification(int p_what) override {}
MobileVRInterface();
~MobileVRInterface();
// deprecated
virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override;
};
#endif // !MOBILE_VR_INTERFACE_H

View file

@ -62,7 +62,7 @@ extern void godot_webxr_initialize(
extern void godot_webxr_uninitialize();
extern int godot_webxr_get_view_count();
extern int *godot_webxr_get_render_targetsize();
extern int *godot_webxr_get_render_target_size();
extern float *godot_webxr_get_transform_for_eye(int p_eye);
extern float *godot_webxr_get_projection_for_eye(int p_eye);
extern int godot_webxr_get_external_texture_for_eye(int p_eye);

View file

@ -406,9 +406,9 @@ const GodotWebXR = {
return GodotWebXR.pose.views.length;
},
godot_webxr_get_render_targetsize__proxy: 'sync',
godot_webxr_get_render_targetsize__sig: 'i',
godot_webxr_get_render_targetsize: function () {
godot_webxr_get_render_target_size__proxy: 'sync',
godot_webxr_get_render_target_size__sig: 'i',
godot_webxr_get_render_target_size: function () {
if (!GodotWebXR.session || !GodotWebXR.pose) {
return 0;
}

View file

@ -199,7 +199,7 @@ StringName WebXRInterfaceJS::get_name() const {
return "WebXR";
};
int WebXRInterfaceJS::get_capabilities() const {
uint32_t WebXRInterfaceJS::get_capabilities() const {
return XRInterface::XR_STEREO | XRInterface::XR_MONO;
};
@ -254,9 +254,9 @@ bool WebXRInterfaceJS::initialize() {
void WebXRInterfaceJS::uninitialize() {
if (initialized) {
XRServer *xr_server = XRServer::get_singleton();
if (xr_server != nullptr) {
if (xr_server != nullptr && xr_server->get_primary_interface() == this) {
// no longer our primary interface
xr_server->clear_primary_interface_if(this);
xr_server->set_primary_interface(nullptr);
}
godot_webxr_uninitialize();
@ -285,12 +285,12 @@ Transform3D WebXRInterfaceJS::_js_matrix_to_transform(float *p_js_matrix) {
return transform;
}
Size2 WebXRInterfaceJS::get_render_targetsize() {
Size2 WebXRInterfaceJS::get_render_target_size() {
if (render_targetsize.width != 0 && render_targetsize.height != 0) {
return render_targetsize;
}
int *js_size = godot_webxr_get_render_targetsize();
int *js_size = godot_webxr_get_render_target_size();
if (!initialized || js_size == nullptr) {
// As a temporary default (until WebXR is fully initialized), use half the window size.
Size2 temp = DisplayServer::get_singleton()->window_get_size();
@ -365,20 +365,6 @@ CameraMatrix WebXRInterfaceJS::get_projection_for_view(uint32_t p_view, real_t p
return eye;
}
unsigned int WebXRInterfaceJS::get_external_texture_for_eye(XRInterface::Eyes p_eye) {
if (!initialized) {
return 0;
}
return godot_webxr_get_external_texture_for_eye(p_eye);
}
void WebXRInterfaceJS::commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) {
if (!initialized) {
return;
}
godot_webxr_commit_for_eye(p_eye);
}
Vector<BlitToScreen> WebXRInterfaceJS::commit_views(RID p_render_target, const Rect2 &p_screen_rect) {
Vector<BlitToScreen> blit_to_screen;
@ -474,10 +460,6 @@ void WebXRInterfaceJS::_on_controller_changed() {
}
}
void WebXRInterfaceJS::notification(int p_what) {
// Nothing to do here.
}
WebXRInterfaceJS::WebXRInterfaceJS() {
initialized = false;
session_mode = "inline";

View file

@ -76,23 +76,20 @@ public:
virtual PackedVector3Array get_bounds_geometry() const override;
virtual StringName get_name() const override;
virtual int get_capabilities() const override;
virtual uint32_t get_capabilities() const override;
virtual bool is_initialized() const override;
virtual bool initialize() override;
virtual void uninitialize() override;
virtual Size2 get_render_targetsize() override;
virtual Size2 get_render_target_size() override;
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override;
virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override;
virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
virtual void process() override;
virtual void notification(int p_what) override;
void _on_controller_changed();

View file

@ -72,6 +72,7 @@
#include "servers/rendering/shader_types.h"
#include "text_server.h"
#include "xr/xr_interface.h"
#include "xr/xr_interface_extension.h"
#include "xr/xr_positional_tracker.h"
#include "xr_server.h"
@ -138,6 +139,7 @@ void register_server_types() {
GDREGISTER_VIRTUAL_CLASS(RenderingDevice);
GDREGISTER_VIRTUAL_CLASS(XRInterface);
GDREGISTER_CLASS(XRInterfaceExtension); // can't register this as virtual because we need a creation function for our extensions.
GDREGISTER_CLASS(XRPositionalTracker);
GDREGISTER_CLASS(AudioStream);

View file

@ -544,7 +544,7 @@ void RendererViewport::draw_viewports() {
RSG::storage->render_target_set_as_unused(vp->render_target);
if (vp->use_xr && xr_interface.is_valid()) {
// override our size, make sure it matches our required size and is created as a stereo target
vp->size = xr_interface->get_render_targetsize();
vp->size = xr_interface->get_render_target_size();
uint32_t view_count = xr_interface->get_view_count();
RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count);

View file

@ -36,21 +36,19 @@ void XRInterface::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_capabilities"), &XRInterface::get_capabilities);
ClassDB::bind_method(D_METHOD("is_primary"), &XRInterface::is_primary);
ClassDB::bind_method(D_METHOD("set_is_primary", "enable"), &XRInterface::set_is_primary);
ClassDB::bind_method(D_METHOD("set_primary", "primary"), &XRInterface::set_primary);
ClassDB::bind_method(D_METHOD("is_initialized"), &XRInterface::is_initialized);
ClassDB::bind_method(D_METHOD("set_is_initialized", "initialized"), &XRInterface::set_is_initialized);
ClassDB::bind_method(D_METHOD("initialize"), &XRInterface::initialize);
ClassDB::bind_method(D_METHOD("uninitialize"), &XRInterface::uninitialize);
ClassDB::bind_method(D_METHOD("get_tracking_status"), &XRInterface::get_tracking_status);
ClassDB::bind_method(D_METHOD("get_render_targetsize"), &XRInterface::get_render_targetsize);
ClassDB::bind_method(D_METHOD("get_render_target_size"), &XRInterface::get_render_target_size);
ClassDB::bind_method(D_METHOD("get_view_count"), &XRInterface::get_view_count);
ADD_GROUP("Interface", "interface_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_is_primary", "is_primary");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_initialized"), "set_is_initialized", "is_initialized");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_primary", "is_primary");
// we don't have any properties specific to VR yet....
@ -77,70 +75,48 @@ void XRInterface::_bind_methods() {
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) {
void XRInterface::set_primary(bool p_primary) {
XRServer *xr_server = XRServer::get_singleton();
ERR_FAIL_NULL(xr_server);
if (p_is_primary) {
if (p_primary) {
ERR_FAIL_COND(!is_initialized());
xr_server->set_primary_interface(this);
} else {
xr_server->clear_primary_interface_if(this);
};
};
} else if (xr_server->get_primary_interface() == this) {
xr_server->set_primary_interface(nullptr);
}
}
void XRInterface::set_is_initialized(bool p_initialized) {
if (p_initialized) {
if (!is_initialized()) {
initialize();
};
} else {
if (is_initialized()) {
uninitialize();
};
};
};
XRInterface::Tracking_status XRInterface::get_tracking_status() const {
return tracking_state;
};
XRInterface::XRInterface() {
tracking_state = XR_UNKNOWN_TRACKING;
};
XRInterface::XRInterface() {}
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;
};
}
/** these are optional, so we want dummies **/
XRInterface::TrackingStatus XRInterface::get_tracking_status() const {
return XR_UNKNOWN_TRACKING;
}
void XRInterface::notification(int p_what) {
}

View file

@ -68,7 +68,7 @@ public:
EYE_RIGHT
};
enum Tracking_status { /* tracking status currently based on AR but we can start doing more with this for VR as well */
enum TrackingStatus { /* tracking status currently based on AR but we can start doing more with this for VR as well */
XR_NORMAL_TRACKING,
XR_EXCESSIVE_MOTION,
XR_INSUFFICIENT_FEATURES,
@ -76,26 +76,25 @@ public:
XR_NOT_TRACKING
};
private:
protected:
_THREAD_SAFE_CLASS_
Tracking_status tracking_state;
static void _bind_methods();
public:
/** general interface information **/
virtual StringName get_name() const;
virtual int get_capabilities() const = 0;
virtual StringName get_name() const = 0;
virtual uint32_t get_capabilities() const = 0;
bool is_primary();
void set_is_primary(bool p_is_primary);
void set_primary(bool p_is_primary);
virtual bool is_initialized() const = 0; /* returns true if we've initialized this interface */
void set_is_initialized(bool p_initialized); /* helper function, will call initialize or uninitialize */
virtual bool initialize() = 0; /* initialize this interface, if this has an HMD it becomes the primary interface */
virtual void uninitialize() = 0; /* deinitialize this interface */
Tracking_status get_tracking_status() const; /* get the status of our current tracking */
virtual TrackingStatus get_tracking_status() const; /* get the status of our current tracking */
/** specific to VR **/
// nothing yet
@ -107,27 +106,25 @@ public:
/** rendering and internal **/
virtual Size2 get_render_targetsize() = 0; /* returns the recommended render target size per eye for this device */
virtual Size2 get_render_target_size() = 0; /* returns the recommended render target size per eye for this device */
virtual uint32_t get_view_count() = 0; /* returns the view count we need (1 is monoscopic, 2 is stereoscopic but can be more) */
virtual Transform3D get_camera_transform() = 0; /* returns the position of our camera for updating our camera node. For monoscopic this is equal to the views transform, for stereoscopic this should be an average */
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */
virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each view projection matrix */
// note, external color/depth/vrs texture support will be added here soon.
virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) = 0; /* commit rendered views to the XR interface */
virtual void process() = 0;
virtual void notification(int p_what) = 0;
virtual void notification(int p_what);
XRInterface();
~XRInterface();
// deprecated
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 */
};
VARIANT_ENUM_CAST(XRInterface::Capabilities);
VARIANT_ENUM_CAST(XRInterface::Eyes);
VARIANT_ENUM_CAST(XRInterface::Tracking_status);
VARIANT_ENUM_CAST(XRInterface::TrackingStatus);
#endif
#endif // !XR_INTERFACE_H

View file

@ -0,0 +1,241 @@
/*************************************************************************/
/* xr_interface_extension.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "xr_interface_extension.h"
#include "servers/rendering/renderer_compositor.h"
void XRInterfaceExtension::_bind_methods() {
GDVIRTUAL_BIND(_get_name);
GDVIRTUAL_BIND(_get_capabilities);
GDVIRTUAL_BIND(_is_initialized);
GDVIRTUAL_BIND(_initialize);
GDVIRTUAL_BIND(_uninitialize);
GDVIRTUAL_BIND(_get_tracking_status);
ClassDB::bind_method(D_METHOD("add_blit", "render_target", "rect", "use_layer", "layer", "apply_lens_distortion", "eye_center", "k1", "k2", "upscale", "aspect_ratio"), &XRInterfaceExtension::add_blit);
GDVIRTUAL_BIND(_get_render_target_size);
GDVIRTUAL_BIND(_get_view_count);
GDVIRTUAL_BIND(_get_camera_transform);
GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform");
GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far");
GDVIRTUAL_BIND(_commit_views);
GDVIRTUAL_BIND(_process);
GDVIRTUAL_BIND(_notification, "what");
// we don't have any properties specific to VR yet....
// but we do have properties specific to AR....
GDVIRTUAL_BIND(_get_anchor_detection_is_enabled);
GDVIRTUAL_BIND(_set_anchor_detection_is_enabled, "enabled");
GDVIRTUAL_BIND(_get_camera_feed_id);
}
StringName XRInterfaceExtension::get_name() const {
StringName name;
if (GDVIRTUAL_CALL(_get_name, name)) {
return name;
}
return "Unknown";
}
uint32_t XRInterfaceExtension::get_capabilities() const {
uint32_t capabilities;
if (GDVIRTUAL_CALL(_get_capabilities, capabilities)) {
return capabilities;
}
return 0;
}
bool XRInterfaceExtension::is_initialized() const {
bool initialised = false;
if (GDVIRTUAL_CALL(_is_initialized, initialised)) {
return initialised;
}
return false;
}
bool XRInterfaceExtension::initialize() {
bool initialised = false;
if (GDVIRTUAL_CALL(_initialize, initialised)) {
return initialised;
}
return false;
}
void XRInterfaceExtension::uninitialize() {
GDVIRTUAL_CALL(_uninitialize);
}
XRInterface::TrackingStatus XRInterfaceExtension::get_tracking_status() const {
uint32_t status;
if (GDVIRTUAL_CALL(_get_tracking_status, status)) {
return TrackingStatus(status);
}
return XR_UNKNOWN_TRACKING;
}
/** these will only be implemented on AR interfaces, so we want dummies for VR **/
bool XRInterfaceExtension::get_anchor_detection_is_enabled() const {
bool enabled;
if (GDVIRTUAL_CALL(_get_anchor_detection_is_enabled, enabled)) {
return enabled;
}
return false;
}
void XRInterfaceExtension::set_anchor_detection_is_enabled(bool p_enable) {
// don't do anything here, this needs to be implemented on AR interface to enable/disable things like plane detection etc.
GDVIRTUAL_CALL(_set_anchor_detection_is_enabled, p_enable);
}
int XRInterfaceExtension::get_camera_feed_id() {
int feed_id;
if (GDVIRTUAL_CALL(_get_camera_feed_id, feed_id)) {
return feed_id;
}
return 0;
}
Size2 XRInterfaceExtension::get_render_target_size() {
Size2 size;
if (GDVIRTUAL_CALL(_get_render_target_size, size)) {
return size;
}
return Size2(0, 0);
}
uint32_t XRInterfaceExtension::get_view_count() {
uint32_t view_count;
if (GDVIRTUAL_CALL(_get_view_count, view_count)) {
return view_count;
}
return 1;
}
Transform3D XRInterfaceExtension::get_camera_transform() {
Transform3D transform;
if (GDVIRTUAL_CALL(_get_camera_transform, transform)) {
return transform;
}
return Transform3D();
}
Transform3D XRInterfaceExtension::get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) {
Transform3D transform;
if (GDVIRTUAL_CALL(_get_transform_for_view, p_view, p_cam_transform, transform)) {
return transform;
}
return Transform3D();
}
CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) {
CameraMatrix cm;
PackedFloat64Array arr;
if (GDVIRTUAL_CALL(_get_projection_for_view, p_view, p_aspect, p_z_near, p_z_far, arr)) {
ERR_FAIL_COND_V_MSG(arr.size() != 16, CameraMatrix(), "Projection matrix must contain 16 floats");
real_t *m = (real_t *)cm.matrix;
for (int i = 0; i < 16; i++) {
m[i] = arr[i];
}
return cm;
}
return CameraMatrix();
}
void XRInterfaceExtension::add_blit(RID p_render_target, Rect2i p_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, float p_k1, float p_k2, float p_upscale, float p_aspect_ratio) {
BlitToScreen blit;
ERR_FAIL_COND_MSG(!can_add_blits, "add_blit can only be called from an XR plugin from within _commit_views!");
blit.render_target = p_render_target;
blit.rect = p_rect;
blit.multi_view.use_layer = p_use_layer;
blit.multi_view.layer = p_layer;
blit.lens_distortion.apply = p_apply_lens_distortion;
blit.lens_distortion.eye_center = p_eye_center;
blit.lens_distortion.k1 = p_k1;
blit.lens_distortion.k2 = p_k2;
blit.lens_distortion.upscale = p_upscale;
blit.lens_distortion.aspect_ratio = p_aspect_ratio;
blits.push_back(blit);
}
Vector<BlitToScreen> XRInterfaceExtension::commit_views(RID p_render_target, const Rect2 &p_screen_rect) {
// This is just so our XR plugin can add blits...
blits.clear();
can_add_blits = true;
if (GDVIRTUAL_CALL(_commit_views, p_render_target, p_screen_rect)) {
return blits;
}
can_add_blits = false;
return blits;
}
void XRInterfaceExtension::process() {
GDVIRTUAL_CALL(_process);
}
void XRInterfaceExtension::notification(int p_what) {
GDVIRTUAL_CALL(_notification, p_what);
}

View file

@ -1,5 +1,5 @@
/*************************************************************************/
/* xr_interface_gdnative.h */
/* xr_interface_extension.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@ -28,68 +28,78 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef XR_INTERFACE_GDNATIVE_H
#define XR_INTERFACE_GDNATIVE_H
#ifndef XR_INTERFACE_EXTENSION_H
#define XR_INTERFACE_EXTENSION_H
#include "modules/gdnative/gdnative.h"
#include "servers/xr/xr_interface.h"
/**
@authors Hinsbart & Karroffel & Mux213
class XRInterfaceExtension : public XRInterface {
GDCLASS(XRInterfaceExtension, XRInterface);
This subclass of our AR/VR interface forms a bridge to GDNative.
*/
class XRInterfaceGDNative : public XRInterface {
GDCLASS(XRInterfaceGDNative, XRInterface);
void cleanup();
public:
private:
bool can_add_blits = false;
Vector<BlitToScreen> blits;
protected:
const godot_xr_interface_gdnative *interface;
void *data;
_THREAD_SAFE_CLASS_
static void _bind_methods();
public:
/** general interface information **/
XRInterfaceGDNative();
~XRInterfaceGDNative();
void set_interface(const godot_xr_interface_gdnative *p_interface);
virtual StringName get_name() const override;
virtual int get_capabilities() const override;
virtual uint32_t get_capabilities() const override;
GDVIRTUAL0RC(StringName, _get_name);
GDVIRTUAL0RC(uint32_t, _get_capabilities);
virtual bool is_initialized() const override;
virtual bool initialize() override;
virtual void uninitialize() override;
GDVIRTUAL0RC(bool, _is_initialized);
GDVIRTUAL0R(bool, _initialize);
GDVIRTUAL0(_uninitialize);
virtual TrackingStatus get_tracking_status() const override;
GDVIRTUAL0RC(uint32_t, _get_tracking_status);
/** specific to VR **/
// nothing yet
/** specific to AR **/
virtual bool get_anchor_detection_is_enabled() const override;
virtual void set_anchor_detection_is_enabled(bool p_enable) override;
virtual int get_camera_feed_id() override;
GDVIRTUAL0RC(bool, _get_anchor_detection_is_enabled);
GDVIRTUAL1(_set_anchor_detection_is_enabled, bool);
GDVIRTUAL0RC(int, _get_camera_feed_id);
/** rendering and internal **/
virtual Size2 get_render_targetsize() override;
virtual Size2 get_render_target_size() override;
virtual uint32_t get_view_count() override;
virtual Transform3D get_camera_transform() override;
virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override;
// we expose a Vector<float> version of this function to GDNative
Vector<float> _get_projection_for_eye(XRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far);
// and a CameraMatrix version to XRServer
virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override;
GDVIRTUAL0R(Size2, _get_render_target_size);
GDVIRTUAL0R(uint32_t, _get_view_count);
GDVIRTUAL0R(Transform3D, _get_camera_transform);
GDVIRTUAL2R(Transform3D, _get_transform_for_view, uint32_t, const Transform3D &);
GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, real_t, real_t, real_t);
void add_blit(RID p_render_target, Rect2i p_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), float p_k1 = 0.0, float p_k2 = 0.0, float p_upscale = 1.0, float p_aspect_ratio = 1.0);
virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override;
GDVIRTUAL2(_commit_views, RID, const Rect2 &);
virtual void process() override;
virtual void notification(int p_what) override;
// deprecated
virtual void commit_for_eye(XRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) override;
virtual unsigned int get_external_texture_for_eye(XRInterface::Eyes p_eye) override;
GDVIRTUAL0(_process);
GDVIRTUAL1(_notification, int);
};
#endif // XR_INTERFACE_GDNATIVE_H
#endif // !XR_INTERFACE_EXTENSION_H

View file

@ -49,7 +49,6 @@ void XRServer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "world_scale"), "set_world_scale", "get_world_scale");
ClassDB::bind_method(D_METHOD("add_interface", "interface"), &XRServer::add_interface);
ClassDB::bind_method(D_METHOD("clear_primary_interface_if", "interface"), &XRServer::clear_primary_interface_if);
ClassDB::bind_method(D_METHOD("get_interface_count"), &XRServer::get_interface_count);
ClassDB::bind_method(D_METHOD("remove_interface", "interface"), &XRServer::remove_interface);
ClassDB::bind_method(D_METHOD("get_interface", "idx"), &XRServer::get_interface);
@ -316,17 +315,14 @@ Ref<XRInterface> XRServer::get_primary_interface() const {
};
void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface) {
ERR_FAIL_COND(p_primary_interface.is_null());
primary_interface = p_primary_interface;
print_verbose("XR: Primary interface set to: " + primary_interface->get_name());
};
void XRServer::clear_primary_interface_if(const Ref<XRInterface> &p_primary_interface) {
if (primary_interface == p_primary_interface) {
if (p_primary_interface.is_null()) {
print_verbose("XR: Clearing primary interface");
primary_interface.unref();
};
} else {
primary_interface = p_primary_interface;
print_verbose("XR: Primary interface set to: " + primary_interface->get_name());
}
};
uint64_t XRServer::get_last_process_usec() {

View file

@ -159,7 +159,6 @@ public:
*/
Ref<XRInterface> get_primary_interface() const;
void set_primary_interface(const Ref<XRInterface> &p_primary_interface);
void clear_primary_interface_if(const Ref<XRInterface> &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.