Merge pull request #115190 from ashwinvbs/xr_ext_user_presence
Implement support for `XR_EXT_user_presence` extension
This commit is contained in:
commit
5ad8b27d8d
10 changed files with 245 additions and 0 deletions
|
|
@ -75,6 +75,7 @@ def get_doc_classes():
|
|||
"OpenXRSpatialPlaneTrackingCapability",
|
||||
"OpenXRSpatialMarkerTrackingCapability",
|
||||
"OpenXRAndroidThreadSettingsExtension",
|
||||
"OpenXRUserPresenceExtension",
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -126,6 +126,19 @@
|
|||
[b]Note:[/b] This only returns a valid value after OpenXR has been initialized.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_user_presence_supported" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if OpenXR's user presence extension is supported and enabled.
|
||||
[b]Note:[/b] This only returns a valid value after OpenXR has been initialized.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_user_present" qualifiers="const">
|
||||
<return type="bool" />
|
||||
<description>
|
||||
Returns [code]true[/code] if system has detected the presence of a user in the XR experience.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_action_set_active">
|
||||
<return type="void" />
|
||||
<param index="0" name="name" type="String" />
|
||||
|
|
@ -245,6 +258,13 @@
|
|||
Informs our OpenXR session is now visible, for example output is sent to the HMD but we don't receive XR input.
|
||||
</description>
|
||||
</signal>
|
||||
<signal name="user_presence_changed">
|
||||
<param index="0" name="is_user_present" type="bool" />
|
||||
<description>
|
||||
Signal emitted when the user presence value changes.
|
||||
[b]Note:[/b] This signal will not be emitted during application startup and application shutdown. Developers should assume user presence is gained on startup and lost on shutdown.
|
||||
</description>
|
||||
</signal>
|
||||
</signals>
|
||||
<constants>
|
||||
<constant name="SESSION_STATE_UNKNOWN" value="0" enum="SessionState">
|
||||
|
|
|
|||
11
modules/openxr/doc_classes/OpenXRUserPresenceExtension.xml
Normal file
11
modules/openxr/doc_classes/OpenXRUserPresenceExtension.xml
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<class name="OpenXRUserPresenceExtension" inherits="OpenXRExtensionWrapper" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../../../doc/class.xsd">
|
||||
<brief_description>
|
||||
This class implements the OpenXR User Presence Extension.
|
||||
</brief_description>
|
||||
<description>
|
||||
This class implements the OpenXR User Presence Extension.
|
||||
</description>
|
||||
<tutorials>
|
||||
</tutorials>
|
||||
</class>
|
||||
100
modules/openxr/extensions/openxr_user_presence_extension.cpp
Normal file
100
modules/openxr/extensions/openxr_user_presence_extension.cpp
Normal file
|
|
@ -0,0 +1,100 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_user_presence_extension.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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 "openxr_user_presence_extension.h"
|
||||
|
||||
#include "../openxr_interface.h"
|
||||
#include "core/config/project_settings.h"
|
||||
|
||||
OpenXRUserPresenceExtension *OpenXRUserPresenceExtension::singleton = nullptr;
|
||||
|
||||
OpenXRUserPresenceExtension *OpenXRUserPresenceExtension::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
OpenXRUserPresenceExtension::OpenXRUserPresenceExtension() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
OpenXRUserPresenceExtension::~OpenXRUserPresenceExtension() {
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
HashMap<String, bool *> OpenXRUserPresenceExtension::get_requested_extensions(XrVersion p_version) {
|
||||
HashMap<String, bool *> request_extensions;
|
||||
if (GLOBAL_GET("xr/openxr/extensions/user_presence")) {
|
||||
request_extensions[XR_EXT_USER_PRESENCE_EXTENSION_NAME] = &available;
|
||||
}
|
||||
return request_extensions;
|
||||
}
|
||||
|
||||
void *OpenXRUserPresenceExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) {
|
||||
if (!available) {
|
||||
return p_next_pointer;
|
||||
}
|
||||
|
||||
properties.type = XR_TYPE_SYSTEM_USER_PRESENCE_PROPERTIES_EXT;
|
||||
properties.next = p_next_pointer;
|
||||
properties.supportsUserPresence = false;
|
||||
|
||||
return &properties;
|
||||
}
|
||||
|
||||
bool OpenXRUserPresenceExtension::is_active() const {
|
||||
return available && properties.supportsUserPresence;
|
||||
}
|
||||
|
||||
void OpenXRUserPresenceExtension::on_state_ready() {
|
||||
user_present = true;
|
||||
}
|
||||
|
||||
void OpenXRUserPresenceExtension::on_state_stopping() {
|
||||
user_present = false;
|
||||
}
|
||||
|
||||
bool OpenXRUserPresenceExtension::on_event_polled(const XrEventDataBuffer &event) {
|
||||
if (!is_active() || event.type != XR_TYPE_EVENT_DATA_USER_PRESENCE_CHANGED_EXT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const XrEventDataUserPresenceChangedEXT *user_presence_changed_event = (XrEventDataUserPresenceChangedEXT *)&event;
|
||||
if (user_present != (bool)user_presence_changed_event->isUserPresent) {
|
||||
user_present = user_presence_changed_event->isUserPresent;
|
||||
OpenXRInterface *xr_interface = OpenXRAPI::get_singleton()->get_xr_interface();
|
||||
if (xr_interface) {
|
||||
xr_interface->emit_signal(SNAME("user_presence_changed"), user_present);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool OpenXRUserPresenceExtension::is_user_present() const {
|
||||
return user_present;
|
||||
}
|
||||
71
modules/openxr/extensions/openxr_user_presence_extension.h
Normal file
71
modules/openxr/extensions/openxr_user_presence_extension.h
Normal file
|
|
@ -0,0 +1,71 @@
|
|||
/**************************************************************************/
|
||||
/* openxr_user_presence_extension.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* 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. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "openxr_extension_wrapper.h"
|
||||
|
||||
// When supported, the user presence extension allows an application to detect and respond to change
|
||||
// of user presence, such as when the user has taken off or put on an XR headset.
|
||||
//
|
||||
// See: https://registry.khronos.org/OpenXR/specs/1.1/html/xrspec.html#XR_EXT_user_presence
|
||||
// for more information.
|
||||
|
||||
class OpenXRUserPresenceExtension : public OpenXRExtensionWrapper {
|
||||
GDCLASS(OpenXRUserPresenceExtension, OpenXRExtensionWrapper);
|
||||
|
||||
protected:
|
||||
static void _bind_methods() {}
|
||||
|
||||
public:
|
||||
static OpenXRUserPresenceExtension *get_singleton();
|
||||
|
||||
OpenXRUserPresenceExtension();
|
||||
virtual ~OpenXRUserPresenceExtension() override;
|
||||
|
||||
virtual HashMap<String, bool *> get_requested_extensions(XrVersion p_version) override;
|
||||
virtual void *set_system_properties_and_get_next_pointer(void *p_next_pointer) override;
|
||||
|
||||
virtual void on_state_ready() override;
|
||||
virtual void on_state_stopping() override;
|
||||
|
||||
virtual bool on_event_polled(const XrEventDataBuffer &event) override;
|
||||
|
||||
bool is_user_present() const;
|
||||
bool is_active() const;
|
||||
|
||||
private:
|
||||
static OpenXRUserPresenceExtension *singleton;
|
||||
|
||||
bool available = false;
|
||||
XrSystemUserPresencePropertiesEXT properties;
|
||||
|
||||
bool user_present = true;
|
||||
};
|
||||
|
|
@ -36,6 +36,7 @@
|
|||
#include "extensions/openxr_eye_gaze_interaction.h"
|
||||
#include "extensions/openxr_hand_interaction_extension.h"
|
||||
#include "extensions/openxr_performance_settings_extension.h"
|
||||
#include "extensions/openxr_user_presence_extension.h"
|
||||
#include "servers/rendering/renderer_compositor.h"
|
||||
|
||||
#include <openxr/openxr.h>
|
||||
|
|
@ -58,6 +59,12 @@ void OpenXRInterface::_bind_methods() {
|
|||
// State
|
||||
ClassDB::bind_method(D_METHOD("get_session_state"), &OpenXRInterface::get_session_state);
|
||||
|
||||
// User presence
|
||||
ADD_SIGNAL(MethodInfo("user_presence_changed", PropertyInfo(Variant::BOOL, "is_user_present")));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("is_user_presence_supported"), &OpenXRInterface::is_user_presence_supported);
|
||||
ClassDB::bind_method(D_METHOD("is_user_present"), &OpenXRInterface::is_user_present);
|
||||
|
||||
// Display refresh rate
|
||||
ClassDB::bind_method(D_METHOD("get_display_refresh_rate"), &OpenXRInterface::get_display_refresh_rate);
|
||||
ClassDB::bind_method(D_METHOD("set_display_refresh_rate", "refresh_rate"), &OpenXRInterface::set_display_refresh_rate);
|
||||
|
|
@ -1448,6 +1455,26 @@ OpenXRInterface::SessionState OpenXRInterface::get_session_state() {
|
|||
return SESSION_STATE_UNKNOWN;
|
||||
}
|
||||
|
||||
/** User Presence. */
|
||||
bool OpenXRInterface::is_user_presence_supported() const {
|
||||
if (!openxr_api || !openxr_api->is_initialized()) {
|
||||
return false;
|
||||
} else {
|
||||
OpenXRUserPresenceExtension *user_presence_ext = OpenXRUserPresenceExtension::get_singleton();
|
||||
return user_presence_ext && user_presence_ext->is_active();
|
||||
}
|
||||
}
|
||||
|
||||
bool OpenXRInterface::is_user_present() const {
|
||||
// If extension is unavailable or unsupported, we default to user is present.
|
||||
if (!is_user_presence_supported()) {
|
||||
return true;
|
||||
} else {
|
||||
OpenXRUserPresenceExtension *user_presence_ext = OpenXRUserPresenceExtension::get_singleton();
|
||||
return user_presence_ext->is_user_present();
|
||||
}
|
||||
}
|
||||
|
||||
/** Hand tracking. */
|
||||
void OpenXRInterface::set_motion_range(const Hand p_hand, const HandMotionRange p_motion_range) {
|
||||
ERR_FAIL_INDEX(p_hand, HAND_MAX);
|
||||
|
|
|
|||
|
|
@ -232,6 +232,10 @@ public:
|
|||
|
||||
SessionState get_session_state();
|
||||
|
||||
/** User presence. */
|
||||
bool is_user_presence_supported() const;
|
||||
bool is_user_present() const;
|
||||
|
||||
/** Hand tracking. */
|
||||
enum Hand {
|
||||
HAND_LEFT,
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@
|
|||
#ifdef MODULE_GLTF_ENABLED
|
||||
#include "extensions/openxr_render_model_extension.h"
|
||||
#endif
|
||||
#include "extensions/openxr_user_presence_extension.h"
|
||||
#include "extensions/openxr_valve_analog_threshold_extension.h"
|
||||
#include "extensions/openxr_valve_controller_extension.h"
|
||||
#include "extensions/openxr_visibility_mask_extension.h"
|
||||
|
|
@ -142,6 +143,7 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
|
|||
GDREGISTER_CLASS(OpenXRRenderModelExtension);
|
||||
#endif
|
||||
GDREGISTER_CLASS(OpenXRAndroidThreadSettingsExtension);
|
||||
GDREGISTER_CLASS(OpenXRUserPresenceExtension);
|
||||
|
||||
// Note, we're not registering all wrapper classes here, there is no point in exposing them
|
||||
// if there isn't specific logic to expose.
|
||||
|
|
@ -214,6 +216,11 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
|
|||
OpenXRAPI::register_extension_wrapper(android_thread_settings);
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("OpenXRAndroidThreadSettingsExtension", android_thread_settings));
|
||||
|
||||
// Register user presence extension as a singleton
|
||||
OpenXRUserPresenceExtension *user_presence_extension = memnew(OpenXRUserPresenceExtension);
|
||||
OpenXRAPI::register_extension_wrapper(user_presence_extension);
|
||||
Engine::get_singleton()->add_singleton(Engine::Singleton("OpenXRUserPresenceExtension", user_presence_extension));
|
||||
|
||||
// register gated extensions
|
||||
if (int(GLOBAL_GET("xr/openxr/extensions/debug_utils")) > 0) {
|
||||
OpenXRAPI::register_extension_wrapper(memnew(OpenXRDebugUtilsExtension));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue