2021-12-14 02:44:12 +01:00
|
|
|
/**************************************************************************/
|
|
|
|
/* openxr_api.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. */
|
|
|
|
/**************************************************************************/
|
|
|
|
|
2022-07-23 23:41:51 +02:00
|
|
|
#ifndef OPENXR_API_H
|
|
|
|
#define OPENXR_API_H
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2023-06-13 16:56:21 +02:00
|
|
|
#include "action_map/openxr_action.h"
|
|
|
|
#include "extensions/openxr_composition_layer_provider.h"
|
|
|
|
#include "extensions/openxr_extension_wrapper.h"
|
|
|
|
#include "util.h"
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
#include "core/error/error_macros.h"
|
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
2022-07-20 01:11:13 +02:00
|
|
|
#include "core/math/projection.h"
|
2021-12-14 02:44:12 +01:00
|
|
|
#include "core/math/transform_3d.h"
|
|
|
|
#include "core/math/vector2.h"
|
|
|
|
#include "core/os/memory.h"
|
2022-09-26 09:04:12 +02:00
|
|
|
#include "core/string/print_string.h"
|
2021-12-14 02:44:12 +01:00
|
|
|
#include "core/string/ustring.h"
|
2022-05-13 15:04:37 +02:00
|
|
|
#include "core/templates/rb_map.h"
|
2021-12-14 02:44:12 +01:00
|
|
|
#include "core/templates/rid_owner.h"
|
|
|
|
#include "core/templates/vector.h"
|
2024-03-21 08:58:24 +01:00
|
|
|
#include "servers/rendering_server.h"
|
2021-12-14 02:44:12 +01:00
|
|
|
#include "servers/xr/xr_pose.h"
|
|
|
|
|
2023-06-13 16:56:21 +02:00
|
|
|
#include <openxr/openxr.h>
|
2022-09-24 13:56:00 +02:00
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
// forward declarations, we don't want to include these fully
|
2022-03-05 11:09:21 +01:00
|
|
|
class OpenXRInterface;
|
2021-12-14 02:44:12 +01:00
|
|
|
|
|
|
|
class OpenXRAPI {
|
2024-03-25 14:07:28 +01:00
|
|
|
public:
|
2024-01-22 10:32:41 +01:00
|
|
|
class OpenXRSwapChainInfo {
|
|
|
|
private:
|
2024-03-25 14:07:28 +01:00
|
|
|
XrSwapchain swapchain = XR_NULL_HANDLE;
|
|
|
|
void *swapchain_graphics_data = nullptr;
|
|
|
|
uint32_t image_index = 0;
|
|
|
|
bool image_acquired = false;
|
|
|
|
bool skip_acquire_swapchain = false;
|
2024-01-22 10:32:41 +01:00
|
|
|
|
|
|
|
static Vector<OpenXRSwapChainInfo> free_queue;
|
|
|
|
|
|
|
|
public:
|
|
|
|
_FORCE_INLINE_ XrSwapchain get_swapchain() const { return swapchain; }
|
|
|
|
_FORCE_INLINE_ bool is_image_acquired() const { return image_acquired; }
|
|
|
|
|
|
|
|
bool create(XrSwapchainCreateFlags p_create_flags, XrSwapchainUsageFlags p_usage_flags, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size);
|
|
|
|
void queue_free();
|
|
|
|
static void free_queued();
|
|
|
|
void free();
|
|
|
|
|
2024-03-21 08:58:24 +01:00
|
|
|
bool acquire(bool &p_should_render);
|
2024-01-22 10:32:41 +01:00
|
|
|
bool release();
|
|
|
|
RID get_image();
|
2024-03-25 14:07:28 +01:00
|
|
|
};
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
private:
|
|
|
|
// our singleton
|
|
|
|
static OpenXRAPI *singleton;
|
|
|
|
|
2022-12-29 06:34:25 +01:00
|
|
|
// Registered extension wrappers
|
|
|
|
static Vector<OpenXRExtensionWrapper *> registered_extension_wrappers;
|
|
|
|
|
2022-03-05 11:09:21 +01:00
|
|
|
// linked XR interface
|
|
|
|
OpenXRInterface *xr_interface = nullptr;
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
// layers
|
|
|
|
uint32_t num_layer_properties = 0;
|
|
|
|
XrApiLayerProperties *layer_properties = nullptr;
|
|
|
|
|
|
|
|
// extensions
|
|
|
|
uint32_t num_supported_extensions = 0;
|
|
|
|
XrExtensionProperties *supported_extensions = nullptr;
|
2022-05-13 15:04:37 +02:00
|
|
|
Vector<CharString> enabled_extensions;
|
2021-12-14 02:44:12 +01:00
|
|
|
|
|
|
|
// composition layer providers
|
|
|
|
Vector<OpenXRCompositionLayerProvider *> composition_layer_providers;
|
|
|
|
|
|
|
|
// view configuration
|
|
|
|
uint32_t num_view_configuration_types = 0;
|
|
|
|
XrViewConfigurationType *supported_view_configuration_types = nullptr;
|
|
|
|
|
|
|
|
// reference spaces
|
|
|
|
uint32_t num_reference_spaces = 0;
|
|
|
|
XrReferenceSpaceType *supported_reference_spaces = nullptr;
|
|
|
|
|
|
|
|
// swapchains (note these are platform dependent)
|
|
|
|
uint32_t num_swapchain_formats = 0;
|
|
|
|
int64_t *supported_swapchain_formats = nullptr;
|
|
|
|
|
2023-03-13 02:26:10 +01:00
|
|
|
// system info
|
|
|
|
String runtime_name;
|
|
|
|
String runtime_version;
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
// configuration
|
|
|
|
XrFormFactor form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
|
|
|
|
XrViewConfigurationType view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_STEREO;
|
2024-01-15 23:26:55 +01:00
|
|
|
XrReferenceSpaceType requested_reference_space = XR_REFERENCE_SPACE_TYPE_STAGE;
|
|
|
|
XrReferenceSpaceType reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
|
2022-12-06 12:20:51 +01:00
|
|
|
bool submit_depth_buffer = false; // if set to true we submit depth buffers to OpenXR if a suitable extension is enabled.
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2023-02-02 15:14:16 +01:00
|
|
|
// blend mode
|
|
|
|
XrEnvironmentBlendMode environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
2024-01-25 21:07:50 +01:00
|
|
|
XrEnvironmentBlendMode requested_environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
|
2023-02-02 15:14:16 +01:00
|
|
|
uint32_t num_supported_environment_blend_modes = 0;
|
|
|
|
XrEnvironmentBlendMode *supported_environment_blend_modes = nullptr;
|
2024-01-25 21:07:50 +01:00
|
|
|
bool emulate_environment_blend_mode_alpha_blend = false;
|
2023-02-02 15:14:16 +01:00
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
// state
|
|
|
|
XrInstance instance = XR_NULL_HANDLE;
|
2022-05-02 16:28:25 +02:00
|
|
|
XrSystemId system_id = 0;
|
2021-12-14 02:44:12 +01:00
|
|
|
String system_name;
|
2022-05-02 16:28:25 +02:00
|
|
|
uint32_t vendor_id = 0;
|
2021-12-14 02:44:12 +01:00
|
|
|
XrSystemTrackingProperties tracking_properties;
|
|
|
|
XrSession session = XR_NULL_HANDLE;
|
|
|
|
XrSessionState session_state = XR_SESSION_STATE_UNKNOWN;
|
|
|
|
bool running = false;
|
2024-03-12 15:40:40 +01:00
|
|
|
XrFrameState frame_state = { XR_TYPE_FRAME_STATE, nullptr, 0, 0, false };
|
2023-02-18 16:50:55 +01:00
|
|
|
double render_target_size_multiplier = 1.0;
|
2021-12-14 02:44:12 +01:00
|
|
|
|
|
|
|
OpenXRGraphicsExtensionWrapper *graphics_extension = nullptr;
|
|
|
|
XrSystemGraphicsProperties graphics_properties;
|
|
|
|
|
|
|
|
uint32_t view_count = 0;
|
|
|
|
XrViewConfigurationView *view_configuration_views = nullptr;
|
2022-09-01 10:10:53 +02:00
|
|
|
|
|
|
|
enum OpenXRSwapChainTypes {
|
|
|
|
OPENXR_SWAPCHAIN_COLOR,
|
|
|
|
OPENXR_SWAPCHAIN_DEPTH,
|
|
|
|
// OPENXR_SWAPCHAIN_VELOCITY,
|
|
|
|
OPENXR_SWAPCHAIN_MAX
|
|
|
|
};
|
|
|
|
|
2024-03-25 14:07:28 +01:00
|
|
|
int64_t color_swapchain_format = 0;
|
|
|
|
int64_t depth_swapchain_format = 0;
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2024-03-21 08:58:24 +01:00
|
|
|
bool play_space_is_dirty = true;
|
2021-12-14 02:44:12 +01:00
|
|
|
XrSpace play_space = XR_NULL_HANDLE;
|
|
|
|
XrSpace view_space = XR_NULL_HANDLE;
|
|
|
|
XRPose::TrackingConfidence head_pose_confidence = XRPose::XR_TRACKING_CONFIDENCE_NONE;
|
|
|
|
|
2024-06-27 21:12:11 +02:00
|
|
|
// When LOCAL_FLOOR isn't supported, we use an approach based on the example code in the
|
|
|
|
// OpenXR spec in order to emulate it.
|
|
|
|
// See: https://registry.khronos.org/OpenXR/specs/1.0/html/xrspec.html#XR_EXT_local_floor
|
|
|
|
struct LocalFloorEmulation {
|
|
|
|
bool enabled = false;
|
|
|
|
XrSpace local_space = XR_NULL_HANDLE;
|
|
|
|
XrSpace stage_space = XR_NULL_HANDLE;
|
|
|
|
bool should_reset_floor_height = false;
|
|
|
|
} local_floor_emulation;
|
|
|
|
|
2024-01-15 23:26:55 +01:00
|
|
|
bool reset_emulated_floor_height();
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
bool load_layer_properties();
|
|
|
|
bool load_supported_extensions();
|
2022-05-13 15:04:37 +02:00
|
|
|
bool is_extension_supported(const String &p_extension) const;
|
2022-11-11 15:59:22 +01:00
|
|
|
bool is_extension_enabled(const String &p_extension) const;
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2022-09-24 13:56:00 +02:00
|
|
|
bool openxr_loader_init();
|
|
|
|
bool resolve_instance_openxr_symbols();
|
|
|
|
|
2022-04-17 04:58:09 +02:00
|
|
|
#ifdef ANDROID_ENABLED
|
|
|
|
// On Android we keep tracker of our external OpenXR loader
|
2022-09-24 13:56:00 +02:00
|
|
|
void *openxr_loader_library_handle = nullptr;
|
2022-04-17 04:58:09 +02:00
|
|
|
#endif
|
2022-09-24 13:56:00 +02:00
|
|
|
|
|
|
|
// function pointers
|
|
|
|
#ifdef ANDROID_ENABLED
|
|
|
|
// On non-Android platforms we use the OpenXR symbol linked into the engine binary.
|
|
|
|
PFN_xrGetInstanceProcAddr xrGetInstanceProcAddr = nullptr;
|
|
|
|
#endif
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrAcquireSwapchainImage, (XrSwapchain), swapchain, (const XrSwapchainImageAcquireInfo *), acquireInfo, (uint32_t *), index)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrApplyHapticFeedback, (XrSession), session, (const XrHapticActionInfo *), hapticActionInfo, (const XrHapticBaseHeader *), hapticFeedback)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrAttachSessionActionSets, (XrSession), session, (const XrSessionActionSetsAttachInfo *), attachInfo)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrBeginFrame, (XrSession), session, (const XrFrameBeginInfo *), frameBeginInfo)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrBeginSession, (XrSession), session, (const XrSessionBeginInfo *), beginInfo)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrCreateAction, (XrActionSet), actionSet, (const XrActionCreateInfo *), createInfo, (XrAction *), action)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrCreateActionSet, (XrInstance), instance, (const XrActionSetCreateInfo *), createInfo, (XrActionSet *), actionSet)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrCreateActionSpace, (XrSession), session, (const XrActionSpaceCreateInfo *), createInfo, (XrSpace *), space)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrCreateInstance, (const XrInstanceCreateInfo *), createInfo, (XrInstance *), instance)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrCreateReferenceSpace, (XrSession), session, (const XrReferenceSpaceCreateInfo *), createInfo, (XrSpace *), space)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrCreateSession, (XrInstance), instance, (const XrSessionCreateInfo *), createInfo, (XrSession *), session)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrCreateSwapchain, (XrSession), session, (const XrSwapchainCreateInfo *), createInfo, (XrSwapchain *), swapchain)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC1(xrDestroyAction, (XrAction), action)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC1(xrDestroyActionSet, (XrActionSet), actionSet)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC1(xrDestroyInstance, (XrInstance), instance)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC1(xrDestroySession, (XrSession), session)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC1(xrDestroySpace, (XrSpace), space)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC1(xrDestroySwapchain, (XrSwapchain), swapchain)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrEndFrame, (XrSession), session, (const XrFrameEndInfo *), frameEndInfo)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC1(xrEndSession, (XrSession), session)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrEnumerateApiLayerProperties, (uint32_t), propertyCapacityInput, (uint32_t *), propertyCountOutput, (XrApiLayerProperties *), properties)
|
2023-02-02 15:14:16 +01:00
|
|
|
EXT_PROTO_XRRESULT_FUNC6(xrEnumerateEnvironmentBlendModes, (XrInstance), instance, (XrSystemId), systemId, (XrViewConfigurationType), viewConfigurationType, (uint32_t), environmentBlendModeCapacityInput, (uint32_t *), environmentBlendModeCountOutput, (XrEnvironmentBlendMode *), environmentBlendModes)
|
2022-09-24 13:56:00 +02:00
|
|
|
EXT_PROTO_XRRESULT_FUNC4(xrEnumerateInstanceExtensionProperties, (const char *), layerName, (uint32_t), propertyCapacityInput, (uint32_t *), propertyCountOutput, (XrExtensionProperties *), properties)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC4(xrEnumerateReferenceSpaces, (XrSession), session, (uint32_t), spaceCapacityInput, (uint32_t *), spaceCountOutput, (XrReferenceSpaceType *), spaces)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC4(xrEnumerateSwapchainFormats, (XrSession), session, (uint32_t), formatCapacityInput, (uint32_t *), formatCountOutput, (int64_t *), formats)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC5(xrEnumerateViewConfigurations, (XrInstance), instance, (XrSystemId), systemId, (uint32_t), viewConfigurationTypeCapacityInput, (uint32_t *), viewConfigurationTypeCountOutput, (XrViewConfigurationType *), viewConfigurationTypes)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC6(xrEnumerateViewConfigurationViews, (XrInstance), instance, (XrSystemId), systemId, (XrViewConfigurationType), viewConfigurationType, (uint32_t), viewCapacityInput, (uint32_t *), viewCountOutput, (XrViewConfigurationView *), views)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateBoolean, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateBoolean *), state)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateFloat, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateFloat *), state)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrGetActionStateVector2f, (XrSession), session, (const XrActionStateGetInfo *), getInfo, (XrActionStateVector2f *), state)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrGetCurrentInteractionProfile, (XrSession), session, (XrPath), topLevelUserPath, (XrInteractionProfileState *), interactionProfile)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrGetInstanceProperties, (XrInstance), instance, (XrInstanceProperties *), instanceProperties)
|
2023-11-21 06:34:29 +01:00
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrGetReferenceSpaceBoundsRect, (XrSession), session, (XrReferenceSpaceType), referenceSpaceType, (XrExtent2Df *), bounds)
|
2022-09-24 13:56:00 +02:00
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrGetSystem, (XrInstance), instance, (const XrSystemGetInfo *), getInfo, (XrSystemId *), systemId)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrGetSystemProperties, (XrInstance), instance, (XrSystemId), systemId, (XrSystemProperties *), properties)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC4(xrLocateSpace, (XrSpace), space, (XrSpace), baseSpace, (XrTime), time, (XrSpaceLocation *), location)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC6(xrLocateViews, (XrSession), session, (const XrViewLocateInfo *), viewLocateInfo, (XrViewState *), viewState, (uint32_t), viewCapacityInput, (uint32_t *), viewCountOutput, (XrView *), views)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC5(xrPathToString, (XrInstance), instance, (XrPath), path, (uint32_t), bufferCapacityInput, (uint32_t *), bufferCountOutput, (char *), buffer)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrPollEvent, (XrInstance), instance, (XrEventDataBuffer *), eventData)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrReleaseSwapchainImage, (XrSwapchain), swapchain, (const XrSwapchainImageReleaseInfo *), releaseInfo)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrResultToString, (XrInstance), instance, (XrResult), value, (char *), buffer)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrStringToPath, (XrInstance), instance, (const char *), pathString, (XrPath *), path)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrSuggestInteractionProfileBindings, (XrInstance), instance, (const XrInteractionProfileSuggestedBinding *), suggestedBindings)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrSyncActions, (XrSession), session, (const XrActionsSyncInfo *), syncInfo)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC3(xrWaitFrame, (XrSession), session, (const XrFrameWaitInfo *), frameWaitInfo, (XrFrameState *), frameState)
|
|
|
|
EXT_PROTO_XRRESULT_FUNC2(xrWaitSwapchainImage, (XrSwapchain), swapchain, (const XrSwapchainImageWaitInfo *), waitInfo)
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
// instance
|
|
|
|
bool create_instance();
|
|
|
|
bool get_system_info();
|
|
|
|
bool load_supported_view_configuration_types();
|
2023-02-02 15:14:16 +01:00
|
|
|
bool load_supported_environmental_blend_modes();
|
2021-12-14 02:44:12 +01:00
|
|
|
bool is_view_configuration_supported(XrViewConfigurationType p_configuration_type) const;
|
|
|
|
bool load_supported_view_configuration_views(XrViewConfigurationType p_configuration_type);
|
|
|
|
void destroy_instance();
|
|
|
|
|
|
|
|
// session
|
|
|
|
bool create_session();
|
|
|
|
bool load_supported_reference_spaces();
|
|
|
|
bool is_reference_space_supported(XrReferenceSpaceType p_reference_space);
|
2024-01-30 17:30:54 +01:00
|
|
|
bool setup_play_space();
|
|
|
|
bool setup_view_space();
|
2021-12-14 02:44:12 +01:00
|
|
|
bool load_supported_swapchain_formats();
|
|
|
|
bool is_swapchain_format_supported(int64_t p_swapchain_format);
|
2024-01-22 10:32:41 +01:00
|
|
|
bool obtain_swapchain_formats();
|
|
|
|
bool create_main_swapchains(Size2i p_size);
|
|
|
|
void free_main_swapchains();
|
2021-12-14 02:44:12 +01:00
|
|
|
void destroy_session();
|
|
|
|
|
|
|
|
// action map
|
2022-03-05 11:09:21 +01:00
|
|
|
struct Tracker { // Trackers represent tracked physical objects such as controllers, pucks, etc.
|
|
|
|
String name; // Name for this tracker (i.e. "/user/hand/left")
|
|
|
|
XrPath toplevel_path; // OpenXR XrPath for this tracker
|
|
|
|
RID active_profile_rid; // RID of the active profile for this tracker
|
2021-12-14 02:44:12 +01:00
|
|
|
};
|
2022-03-05 11:09:21 +01:00
|
|
|
RID_Owner<Tracker, true> tracker_owner;
|
|
|
|
RID get_tracker_rid(XrPath p_path);
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2022-03-05 11:09:21 +01:00
|
|
|
struct ActionSet { // Action sets define a set of actions that can be enabled together
|
|
|
|
String name; // Name for this action set (i.e. "godot_action_set")
|
|
|
|
bool is_attached; // If true our action set has been attached to the session and can no longer be modified
|
|
|
|
XrActionSet handle; // OpenXR handle for this action set
|
2021-12-14 02:44:12 +01:00
|
|
|
};
|
|
|
|
RID_Owner<ActionSet, true> action_set_owner;
|
|
|
|
|
2022-03-05 11:09:21 +01:00
|
|
|
struct ActionTracker { // Links and action to a tracker
|
|
|
|
RID tracker_rid; // RID of the tracker
|
|
|
|
XrSpace space; // Optional space for pose actions
|
|
|
|
bool was_location_valid; // If true the last position we obtained was valid
|
2021-12-14 02:44:12 +01:00
|
|
|
};
|
|
|
|
|
2022-03-05 11:09:21 +01:00
|
|
|
struct Action { // Actions define the inputs and outputs in OpenXR
|
|
|
|
RID action_set_rid; // RID of the action set this action belongs to
|
|
|
|
String name; // Name for this action (i.e. "aim_pose")
|
|
|
|
XrActionType action_type; // Type of action (bool, float, etc.)
|
|
|
|
Vector<ActionTracker> trackers; // The trackers this action can be used with
|
|
|
|
XrAction handle; // OpenXR handle for this action
|
2021-12-14 02:44:12 +01:00
|
|
|
};
|
|
|
|
RID_Owner<Action, true> action_owner;
|
2022-03-05 11:09:21 +01:00
|
|
|
RID get_action_rid(XrAction p_action);
|
|
|
|
|
|
|
|
struct InteractionProfile { // Interaction profiles define suggested bindings between the physical inputs on controller types and our actions
|
|
|
|
String name; // Name of the interaction profile (i.e. "/interaction_profiles/valve/index_controller")
|
|
|
|
XrPath path; // OpenXR path for this profile
|
|
|
|
Vector<XrActionSuggestedBinding> bindings; // OpenXR action bindings
|
|
|
|
};
|
|
|
|
RID_Owner<InteractionProfile, true> interaction_profile_owner;
|
|
|
|
RID get_interaction_profile_rid(XrPath p_path);
|
|
|
|
XrPath get_interaction_profile_path(RID p_interaction_profile);
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2023-05-09 15:29:13 +02:00
|
|
|
struct OrderedCompositionLayer {
|
|
|
|
const XrCompositionLayerBaseHeader *composition_layer;
|
|
|
|
int sort_order;
|
|
|
|
|
|
|
|
_FORCE_INLINE_ bool operator()(const OrderedCompositionLayer &a, const OrderedCompositionLayer &b) const {
|
|
|
|
return a.sort_order < b.sort_order || (a.sort_order == b.sort_order && uint64_t(a.composition_layer) < uint64_t(b.composition_layer));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
// state changes
|
|
|
|
bool poll_events();
|
|
|
|
bool on_state_idle();
|
|
|
|
bool on_state_ready();
|
|
|
|
bool on_state_synchronized();
|
|
|
|
bool on_state_visible();
|
|
|
|
bool on_state_focused();
|
|
|
|
bool on_state_stopping();
|
|
|
|
bool on_state_loss_pending();
|
|
|
|
bool on_state_exiting();
|
|
|
|
|
2023-09-12 08:54:18 +02:00
|
|
|
// convenience
|
2021-12-14 02:44:12 +01:00
|
|
|
void copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len);
|
|
|
|
|
2024-03-21 08:58:24 +01:00
|
|
|
// Render state, Only accessible in rendering thread
|
|
|
|
struct RenderState {
|
|
|
|
bool running = false;
|
|
|
|
bool should_render = false;
|
|
|
|
bool has_xr_viewport = false;
|
|
|
|
XrTime predicted_display_time = 0;
|
|
|
|
XrSpace play_space = XR_NULL_HANDLE;
|
|
|
|
double render_target_size_multiplier = 1.0;
|
|
|
|
|
|
|
|
uint32_t view_count = 0;
|
|
|
|
XrView *views = nullptr;
|
|
|
|
XrCompositionLayerProjectionView *projection_views = nullptr;
|
|
|
|
XrCompositionLayerDepthInfoKHR *depth_views = nullptr; // Only used by Composition Layer Depth Extension if available
|
|
|
|
bool submit_depth_buffer = false; // if set to true we submit depth buffers to OpenXR if a suitable extension is enabled.
|
|
|
|
bool view_pose_valid = false;
|
|
|
|
|
|
|
|
Size2i main_swapchain_size;
|
|
|
|
OpenXRSwapChainInfo main_swapchains[OPENXR_SWAPCHAIN_MAX];
|
|
|
|
} render_state;
|
|
|
|
|
|
|
|
static void _allocate_view_buffers(uint32_t p_view_count, bool p_submit_depth_buffer);
|
|
|
|
static void _set_render_session_running(bool p_is_running);
|
|
|
|
static void _set_render_display_info(XrTime p_predicted_display_time, bool p_should_render);
|
|
|
|
static void _set_render_play_space(uint64_t p_play_space);
|
|
|
|
static void _set_render_state_multiplier(double p_render_target_size_multiplier);
|
|
|
|
|
|
|
|
_FORCE_INLINE_ void allocate_view_buffers(uint32_t p_view_count, bool p_submit_depth_buffer) {
|
|
|
|
// If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
|
|
|
|
RenderingServer *rendering_server = RenderingServer::get_singleton();
|
|
|
|
ERR_FAIL_NULL(rendering_server);
|
|
|
|
|
|
|
|
rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_allocate_view_buffers).bind(p_view_count, p_submit_depth_buffer));
|
|
|
|
}
|
|
|
|
|
|
|
|
_FORCE_INLINE_ void set_render_session_running(bool p_is_running) {
|
|
|
|
// If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
|
|
|
|
RenderingServer *rendering_server = RenderingServer::get_singleton();
|
|
|
|
ERR_FAIL_NULL(rendering_server);
|
|
|
|
|
|
|
|
rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_session_running).bind(p_is_running));
|
|
|
|
}
|
|
|
|
|
|
|
|
_FORCE_INLINE_ void set_render_display_info(XrTime p_predicted_display_time, bool p_should_render) {
|
|
|
|
// If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
|
|
|
|
RenderingServer *rendering_server = RenderingServer::get_singleton();
|
|
|
|
ERR_FAIL_NULL(rendering_server);
|
|
|
|
|
|
|
|
rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_display_info).bind(p_predicted_display_time, p_should_render));
|
|
|
|
}
|
|
|
|
|
|
|
|
_FORCE_INLINE_ void set_render_play_space(XrSpace p_play_space) {
|
|
|
|
// If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
|
|
|
|
RenderingServer *rendering_server = RenderingServer::get_singleton();
|
|
|
|
ERR_FAIL_NULL(rendering_server);
|
|
|
|
|
|
|
|
rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_play_space).bind(uint64_t(p_play_space)));
|
|
|
|
}
|
|
|
|
|
|
|
|
_FORCE_INLINE_ void set_render_state_multiplier(double p_render_target_size_multiplier) {
|
|
|
|
// If we're rendering on a separate thread, we may still be processing the last frame, don't communicate this till we're ready...
|
|
|
|
RenderingServer *rendering_server = RenderingServer::get_singleton();
|
|
|
|
ERR_FAIL_NULL(rendering_server);
|
|
|
|
|
|
|
|
rendering_server->call_on_render_thread(callable_mp_static(&OpenXRAPI::_set_render_state_multiplier).bind(p_render_target_size_multiplier));
|
|
|
|
}
|
|
|
|
|
2022-04-17 04:58:09 +02:00
|
|
|
public:
|
2021-12-14 02:44:12 +01:00
|
|
|
XrInstance get_instance() const { return instance; };
|
|
|
|
XrSystemId get_system_id() const { return system_id; };
|
|
|
|
XrSession get_session() const { return session; };
|
2024-01-22 10:32:41 +01:00
|
|
|
OpenXRGraphicsExtensionWrapper *get_graphics_extension() const { return graphics_extension; };
|
2023-03-13 02:26:10 +01:00
|
|
|
String get_runtime_name() const { return runtime_name; };
|
|
|
|
String get_runtime_version() const { return runtime_version; };
|
2021-12-14 02:44:12 +01:00
|
|
|
|
|
|
|
// helper method to convert an XrPosef to a Transform3D
|
|
|
|
Transform3D transform_from_pose(const XrPosef &p_pose);
|
|
|
|
|
|
|
|
// helper method to get a valid Transform3D from an openxr space location
|
|
|
|
XRPose::TrackingConfidence transform_from_location(const XrSpaceLocation &p_location, Transform3D &r_transform);
|
|
|
|
XRPose::TrackingConfidence transform_from_location(const XrHandJointLocationEXT &p_location, Transform3D &r_transform);
|
2022-06-14 16:33:03 +02:00
|
|
|
void parse_velocities(const XrSpaceVelocity &p_velocity, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2022-09-26 09:04:12 +02:00
|
|
|
bool xr_result(XrResult result, const char *format, Array args = Array()) const;
|
2022-11-11 15:59:22 +01:00
|
|
|
bool is_top_level_path_supported(const String &p_toplevel_path);
|
|
|
|
bool is_interaction_profile_supported(const String &p_ip_path);
|
|
|
|
bool interaction_profile_supports_io_path(const String &p_ip_path, const String &p_io_path);
|
2022-09-26 09:04:12 +02:00
|
|
|
|
2022-03-17 00:24:47 +01:00
|
|
|
static bool openxr_is_enabled(bool p_check_run_in_editor = true);
|
2022-12-29 06:34:25 +01:00
|
|
|
_FORCE_INLINE_ static OpenXRAPI *get_singleton() { return singleton; }
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2023-01-07 18:41:58 +01:00
|
|
|
XrResult try_get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr);
|
2022-09-24 13:56:00 +02:00
|
|
|
XrResult get_instance_proc_addr(const char *p_name, PFN_xrVoidFunction *p_addr);
|
2023-11-21 06:34:29 +01:00
|
|
|
String get_error_string(XrResult result) const;
|
2021-12-14 02:44:12 +01:00
|
|
|
String get_swapchain_format_name(int64_t p_swapchain_format) const;
|
|
|
|
|
2024-04-08 03:41:38 +02:00
|
|
|
OpenXRInterface *get_xr_interface() const { return xr_interface; }
|
2022-03-05 11:09:21 +01:00
|
|
|
void set_xr_interface(OpenXRInterface *p_xr_interface);
|
2022-12-29 06:34:25 +01:00
|
|
|
static void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper);
|
2023-01-15 06:57:42 +01:00
|
|
|
static void unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper);
|
2024-01-23 18:14:47 +01:00
|
|
|
static const Vector<OpenXRExtensionWrapper *> &get_registered_extension_wrappers();
|
2022-12-29 06:34:25 +01:00
|
|
|
static void register_extension_metadata();
|
|
|
|
static void cleanup_extension_wrappers();
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2022-12-06 12:20:51 +01:00
|
|
|
void set_form_factor(XrFormFactor p_form_factor);
|
|
|
|
XrFormFactor get_form_factor() const { return form_factor; }
|
|
|
|
|
|
|
|
void set_view_configuration(XrViewConfigurationType p_view_configuration);
|
|
|
|
XrViewConfigurationType get_view_configuration() const { return view_configuration; }
|
|
|
|
|
2024-01-30 17:30:54 +01:00
|
|
|
bool set_requested_reference_space(XrReferenceSpaceType p_requested_reference_space);
|
2024-01-15 23:26:55 +01:00
|
|
|
XrReferenceSpaceType get_requested_reference_space() const { return requested_reference_space; }
|
2022-12-06 12:20:51 +01:00
|
|
|
XrReferenceSpaceType get_reference_space() const { return reference_space; }
|
|
|
|
|
|
|
|
void set_submit_depth_buffer(bool p_submit_depth_buffer);
|
|
|
|
bool get_submit_depth_buffer() const { return submit_depth_buffer; }
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
bool is_initialized();
|
|
|
|
bool is_running();
|
2022-03-24 12:10:43 +01:00
|
|
|
bool initialize(const String &p_rendering_driver);
|
|
|
|
bool initialize_session();
|
2021-12-14 02:44:12 +01:00
|
|
|
void finish();
|
|
|
|
|
2024-03-21 08:58:24 +01:00
|
|
|
_FORCE_INLINE_ XrSpace get_play_space() const { return play_space; }
|
|
|
|
_FORCE_INLINE_ XrTime get_predicted_display_time() { return frame_state.predictedDisplayTime; }
|
|
|
|
_FORCE_INLINE_ XrTime get_next_frame_time() { return frame_state.predictedDisplayTime + frame_state.predictedDisplayPeriod; }
|
|
|
|
_FORCE_INLINE_ bool can_render() {
|
|
|
|
return instance != XR_NULL_HANDLE && session != XR_NULL_HANDLE && running && frame_state.shouldRender;
|
|
|
|
}
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2024-02-19 03:06:36 +01:00
|
|
|
XrHandTrackerEXT get_hand_tracker(int p_hand_index);
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
Size2 get_recommended_target_size();
|
2022-06-14 16:33:03 +02:00
|
|
|
XRPose::TrackingConfidence get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
|
2021-12-14 02:44:12 +01:00
|
|
|
bool get_view_transform(uint32_t p_view, Transform3D &r_transform);
|
Implement Vector4, Vector4i, Projection
Implement built-in classes Vector4, Vector4i and Projection.
* Two versions of Vector4 (float and integer).
* A Projection class, which is a 4x4 matrix specialized in projection types.
These types have been requested for a long time, but given they were very corner case they were not added before.
Because in Godot 4, reimplementing parts of the rendering engine is now possible, access to these types (heavily used by the rendering code) becomes a necessity.
**Q**: Why Projection and not Matrix4?
**A**: Godot does not use Matrix2, Matrix3, Matrix4x3, etc. naming convention because, within the engine, these types always have a *purpose*. As such, Godot names them: Transform2D, Transform3D or Basis. In this case, this 4x4 matrix is _always_ used as a _Projection_, hence the naming.
2022-07-20 01:11:13 +02:00
|
|
|
bool get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, Projection &p_camera_matrix);
|
2024-03-26 02:57:26 +01:00
|
|
|
Vector2 get_eye_focus(uint32_t p_view, float p_aspect);
|
2021-12-14 02:44:12 +01:00
|
|
|
bool process();
|
|
|
|
|
|
|
|
void pre_render();
|
|
|
|
bool pre_draw_viewport(RID p_render_target);
|
2023-08-21 09:45:28 +02:00
|
|
|
XrSwapchain get_color_swapchain();
|
2022-09-01 10:10:53 +02:00
|
|
|
RID get_color_texture();
|
|
|
|
RID get_depth_texture();
|
2021-12-14 02:44:12 +01:00
|
|
|
void post_draw_viewport(RID p_render_target);
|
|
|
|
void end_frame();
|
|
|
|
|
2022-10-10 09:51:53 +02:00
|
|
|
// Display refresh rate
|
|
|
|
float get_display_refresh_rate() const;
|
|
|
|
void set_display_refresh_rate(float p_refresh_rate);
|
|
|
|
Array get_available_display_refresh_rates() const;
|
|
|
|
|
2023-02-18 16:50:55 +01:00
|
|
|
// Render Target size multiplier
|
|
|
|
double get_render_target_size_multiplier() const;
|
|
|
|
void set_render_target_size_multiplier(double multiplier);
|
|
|
|
|
2023-08-21 09:45:28 +02:00
|
|
|
// Foveation settings
|
|
|
|
bool is_foveation_supported() const;
|
|
|
|
|
|
|
|
int get_foveation_level() const;
|
|
|
|
void set_foveation_level(int p_foveation_level);
|
|
|
|
|
|
|
|
bool get_foveation_dynamic() const;
|
|
|
|
void set_foveation_dynamic(bool p_foveation_dynamic);
|
|
|
|
|
2023-11-21 06:34:29 +01:00
|
|
|
// Play space.
|
|
|
|
Size2 get_play_space_bounds() const;
|
|
|
|
|
2024-03-25 14:07:28 +01:00
|
|
|
// swapchains
|
|
|
|
int64_t get_color_swapchain_format() const { return color_swapchain_format; }
|
2024-01-22 10:32:41 +01:00
|
|
|
int64_t get_depth_swapchain_format() const { return depth_swapchain_format; }
|
2024-03-25 14:07:28 +01:00
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
// action map
|
|
|
|
String get_default_action_map_resource_name();
|
2022-03-05 11:09:21 +01:00
|
|
|
|
|
|
|
RID tracker_create(const String p_name);
|
|
|
|
String tracker_get_name(RID p_tracker);
|
|
|
|
void tracker_check_profile(RID p_tracker, XrSession p_session = XR_NULL_HANDLE);
|
|
|
|
void tracker_free(RID p_tracker);
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
RID action_set_create(const String p_name, const String p_localized_name, const int p_priority);
|
2022-03-05 11:09:21 +01:00
|
|
|
String action_set_get_name(RID p_action_set);
|
2023-08-10 03:40:16 +02:00
|
|
|
bool attach_action_sets(const Vector<RID> &p_action_sets);
|
2021-12-14 02:44:12 +01:00
|
|
|
void action_set_free(RID p_action_set);
|
2022-03-05 11:09:21 +01:00
|
|
|
|
|
|
|
RID action_create(RID p_action_set, const String p_name, const String p_localized_name, OpenXRAction::ActionType p_action_type, const Vector<RID> &p_trackers);
|
|
|
|
String action_get_name(RID p_action);
|
2021-12-14 02:44:12 +01:00
|
|
|
void action_free(RID p_action);
|
|
|
|
|
2022-03-05 11:09:21 +01:00
|
|
|
RID interaction_profile_create(const String p_name);
|
|
|
|
String interaction_profile_get_name(RID p_interaction_profile);
|
|
|
|
void interaction_profile_clear_bindings(RID p_interaction_profile);
|
|
|
|
bool interaction_profile_add_binding(RID p_interaction_profile, RID p_action, const String p_path);
|
|
|
|
bool interaction_profile_suggest_bindings(RID p_interaction_profile);
|
|
|
|
void interaction_profile_free(RID p_interaction_profile);
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2024-03-26 02:57:26 +01:00
|
|
|
RID find_tracker(const String &p_name);
|
|
|
|
RID find_action(const String &p_name);
|
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
bool sync_action_sets(const Vector<RID> p_active_sets);
|
2022-03-05 11:09:21 +01:00
|
|
|
bool get_action_bool(RID p_action, RID p_tracker);
|
|
|
|
float get_action_float(RID p_action, RID p_tracker);
|
|
|
|
Vector2 get_action_vector2(RID p_action, RID p_tracker);
|
2022-06-14 16:33:03 +02:00
|
|
|
XRPose::TrackingConfidence get_action_pose(RID p_action, RID p_tracker, Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity);
|
2022-03-05 11:09:21 +01:00
|
|
|
bool trigger_haptic_pulse(RID p_action, RID p_tracker, float p_frequency, float p_amplitude, XrDuration p_duration_ns);
|
2021-12-14 02:44:12 +01:00
|
|
|
|
2022-09-26 09:04:12 +02:00
|
|
|
void register_composition_layer_provider(OpenXRCompositionLayerProvider *provider);
|
|
|
|
void unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider);
|
|
|
|
|
2023-02-02 15:14:16 +01:00
|
|
|
const XrEnvironmentBlendMode *get_supported_environment_blend_modes(uint32_t &count);
|
2023-09-12 04:39:48 +02:00
|
|
|
bool is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const;
|
|
|
|
bool set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode);
|
2024-01-25 21:07:50 +01:00
|
|
|
XrEnvironmentBlendMode get_environment_blend_mode() const { return requested_environment_blend_mode; }
|
|
|
|
|
|
|
|
enum OpenXRAlphaBlendModeSupport {
|
|
|
|
OPENXR_ALPHA_BLEND_MODE_SUPPORT_NONE = 0,
|
|
|
|
OPENXR_ALPHA_BLEND_MODE_SUPPORT_REAL = 1,
|
|
|
|
OPENXR_ALPHA_BLEND_MODE_SUPPORT_EMULATING = 2,
|
|
|
|
};
|
|
|
|
|
|
|
|
void set_emulate_environment_blend_mode_alpha_blend(bool p_enabled);
|
|
|
|
OpenXRAlphaBlendModeSupport is_environment_blend_mode_alpha_blend_supported();
|
2023-02-02 15:14:16 +01:00
|
|
|
|
2021-12-14 02:44:12 +01:00
|
|
|
OpenXRAPI();
|
|
|
|
~OpenXRAPI();
|
|
|
|
};
|
|
|
|
|
2022-07-23 23:41:51 +02:00
|
|
|
#endif // OPENXR_API_H
|