Path: blob/master/modules/openxr/extensions/openxr_eye_gaze_interaction.cpp
10278 views
/**************************************************************************/1/* openxr_eye_gaze_interaction.cpp */2/**************************************************************************/3/* This file is part of: */4/* GODOT ENGINE */5/* https://godotengine.org */6/**************************************************************************/7/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */8/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */9/* */10/* Permission is hereby granted, free of charge, to any person obtaining */11/* a copy of this software and associated documentation files (the */12/* "Software"), to deal in the Software without restriction, including */13/* without limitation the rights to use, copy, modify, merge, publish, */14/* distribute, sublicense, and/or sell copies of the Software, and to */15/* permit persons to whom the Software is furnished to do so, subject to */16/* the following conditions: */17/* */18/* The above copyright notice and this permission notice shall be */19/* included in all copies or substantial portions of the Software. */20/* */21/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */22/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */23/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */24/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */25/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */26/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */27/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */28/**************************************************************************/2930#include "openxr_eye_gaze_interaction.h"3132#include "core/config/project_settings.h"33#include "core/os/os.h"3435#include "../action_map/openxr_interaction_profile_metadata.h"36#include "../openxr_api.h"3738OpenXREyeGazeInteractionExtension *OpenXREyeGazeInteractionExtension::singleton = nullptr;3940OpenXREyeGazeInteractionExtension *OpenXREyeGazeInteractionExtension::get_singleton() {41ERR_FAIL_NULL_V(singleton, nullptr);42return singleton;43}4445OpenXREyeGazeInteractionExtension::OpenXREyeGazeInteractionExtension() {46singleton = this;47}4849OpenXREyeGazeInteractionExtension::~OpenXREyeGazeInteractionExtension() {50singleton = nullptr;51}5253HashMap<String, bool *> OpenXREyeGazeInteractionExtension::get_requested_extensions() {54HashMap<String, bool *> request_extensions;5556// Only enable this extension when requested.57// We still register our meta data or the action map editor will fail.58if (GLOBAL_GET_CACHED(bool, "xr/openxr/extensions/eye_gaze_interaction") && (!OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature(XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME))) {59request_extensions[XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME] = &available;60}6162return request_extensions;63}6465void *OpenXREyeGazeInteractionExtension::set_system_properties_and_get_next_pointer(void *p_next_pointer) {66if (!available) {67return p_next_pointer;68}6970properties.type = XR_TYPE_SYSTEM_EYE_GAZE_INTERACTION_PROPERTIES_EXT;71properties.next = p_next_pointer;72properties.supportsEyeGazeInteraction = false;7374return &properties;75}7677PackedStringArray OpenXREyeGazeInteractionExtension::get_suggested_tracker_names() {78PackedStringArray arr = { "/user/eyes_ext" };79return arr;80}8182bool OpenXREyeGazeInteractionExtension::is_available() {83return available;84}8586bool OpenXREyeGazeInteractionExtension::supports_eye_gaze_interaction() {87// The extension being available only means that the OpenXR Runtime supports the extension.88// The `supportsEyeGazeInteraction` is set to true if the device also supports this.89// Thus both need to be true.90// In addition, on mobile runtimes, the proper permission needs to be granted.91if (available && properties.supportsEyeGazeInteraction) {92return !OS::get_singleton()->has_feature("mobile") || OS::get_singleton()->has_feature("PERMISSION_XR_EXT_eye_gaze_interaction");93}9495return false;96}9798void OpenXREyeGazeInteractionExtension::on_register_metadata() {99OpenXRInteractionProfileMetadata *openxr_metadata = OpenXRInteractionProfileMetadata::get_singleton();100ERR_FAIL_NULL(openxr_metadata);101102// Eyes top path103openxr_metadata->register_top_level_path("Eye gaze tracker", "/user/eyes_ext", XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME);104105// Eye gaze interaction106openxr_metadata->register_interaction_profile("Eye gaze", "/interaction_profiles/ext/eye_gaze_interaction", XR_EXT_EYE_GAZE_INTERACTION_EXTENSION_NAME);107openxr_metadata->register_io_path("/interaction_profiles/ext/eye_gaze_interaction", "Gaze pose", "/user/eyes_ext", "/user/eyes_ext/input/gaze_ext/pose", "", OpenXRAction::OPENXR_ACTION_POSE);108}109110bool OpenXREyeGazeInteractionExtension::get_eye_gaze_pose(double p_dist, Vector3 &r_eye_pose) {111OpenXRAPI *openxr_api = OpenXRAPI::get_singleton();112ERR_FAIL_NULL_V(openxr_api, false);113114if (!init_eye_gaze_pose) {115init_eye_gaze_pose = true;116117eye_tracker = openxr_api->find_tracker("/user/eyes_ext");118if (eye_tracker.is_null()) {119WARN_PRINT("Couldn't obtain eye tracker");120}121122eye_action = openxr_api->find_action("eye_gaze_pose");123if (eye_action.is_null()) {124WARN_PRINT("Couldn't obtain pose action for `eye_gaze_pose`, make sure to add this to your action map.");125}126}127128if (eye_tracker.is_null() || eye_action.is_null()) {129return false;130}131132Transform3D eye_transform;133Vector3 linear_velocity;134Vector3 angular_velocity;135XRPose::TrackingConfidence confidence = openxr_api->get_action_pose(eye_action, eye_tracker, eye_transform, linear_velocity, angular_velocity);136if (confidence == XRPose::XR_TRACKING_CONFIDENCE_NONE) {137return false;138}139140r_eye_pose = eye_transform.origin + eye_transform.basis[2] * p_dist;141142return true;143}144145146