diff --git a/SConstruct b/SConstruct index 1d55b3e37eb..5dc0ed0fa28 100644 --- a/SConstruct +++ b/SConstruct @@ -240,6 +240,7 @@ opts.Add(BoolVariable("builtin_libwebp", "Use the built-in libwebp library", Tru opts.Add(BoolVariable("builtin_wslay", "Use the built-in wslay library", True)) opts.Add(BoolVariable("builtin_mbedtls", "Use the built-in mbedTLS library", True)) opts.Add(BoolVariable("builtin_miniupnpc", "Use the built-in miniupnpc library", True)) +opts.Add(BoolVariable("builtin_openxr", "Use the built-in OpenXR library", True)) opts.Add(BoolVariable("builtin_pcre2", "Use the built-in PCRE2 library", True)) opts.Add(BoolVariable("builtin_pcre2_with_jit", "Use JIT compiler for the built-in PCRE2 library", True)) opts.Add(BoolVariable("builtin_recastnavigation", "Use the built-in Recast navigation library", True)) diff --git a/modules/openxr/SCsub b/modules/openxr/SCsub index 0dd41675b6b..d5abbe4c725 100644 --- a/modules/openxr/SCsub +++ b/modules/openxr/SCsub @@ -5,22 +5,13 @@ Import("env_modules") env_openxr = env_modules.Clone() -################################################# -# Add in our Khronos OpenXR loader +# Thirdparty source files thirdparty_obj = [] -thirdparty_dir = "#thirdparty/openxr" -env_openxr.Prepend( - CPPPATH=[ - thirdparty_dir, - thirdparty_dir + "/include", - thirdparty_dir + "/src", - thirdparty_dir + "/src/common", - thirdparty_dir + "/src/external/jsoncpp/include", - ] -) +# Khronos OpenXR loader +# Needs even for build against shared library, at least the defines used in public headers. if env["platform"] == "android": # may need to set OPENXR_ANDROID_VERSION_SUFFIX env_openxr.AppendUnique(CPPDEFINES=["XR_OS_ANDROID", "XR_USE_PLATFORM_ANDROID"]) @@ -41,43 +32,57 @@ elif env["platform"] == "windows": # may need to check and set: # - XR_USE_TIMESPEC -env_thirdparty = env_openxr.Clone() -env_thirdparty.disable_warnings() -env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"]) +if env["builtin_openxr"]: + thirdparty_dir = "#thirdparty/openxr" -if "-fno-exceptions" in env_thirdparty["CXXFLAGS"]: - env_thirdparty["CXXFLAGS"].remove("-fno-exceptions") -env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"]) + env_openxr.Prepend( + CPPPATH=[ + thirdparty_dir, + thirdparty_dir + "/include", + thirdparty_dir + "/src", + thirdparty_dir + "/src/common", + thirdparty_dir + "/src/external/jsoncpp/include", + ] + ) -# add in external jsoncpp dependency -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_reader.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_value.cpp") -env_thirdparty.add_source_files(thirdparty_obj, thirdparty_dir + "/src/external/jsoncpp/src/lib_json/json_writer.cpp") + env_thirdparty = env_openxr.Clone() + env_thirdparty.disable_warnings() + env_thirdparty.AppendUnique(CPPDEFINES=["DISABLE_STD_FILESYSTEM"]) -# add in load -if env["platform"] != "android": - # On Android the openxr_loader is provided by separate plugins for each device - # Build the engine using object files - khrloader_obj = [] - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c") + if "-fno-exceptions" in env_thirdparty["CXXFLAGS"]: + env_thirdparty["CXXFLAGS"].remove("-fno-exceptions") + env_thirdparty.Append(CPPPATH=[thirdparty_dir + "/src/loader"]) - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp") - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/object_info.cpp") + # add in external jsoncpp dependency + thirdparty_jsoncpp_dir = thirdparty_dir + "/src/external/jsoncpp/src/lib_json/" + env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_reader.cpp") + env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_value.cpp") + env_thirdparty.add_source_files(thirdparty_obj, thirdparty_jsoncpp_dir + "json_writer.cpp") - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp") - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_core.cpp") - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_instance.cpp") - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp") - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger.cpp") - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/manifest_file.cpp") - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp") - env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp") - env.modules_sources += khrloader_obj + # add in load + if env["platform"] != "android": + # On Android the openxr_loader is provided by separate plugins for each device + # Build the engine using object files + khrloader_obj = [] + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/xr_generated_dispatch_table.c") -env.modules_sources += thirdparty_obj + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/filesystem_utils.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/common/object_info.cpp") -################################################# -# And include our module source + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/api_layer_interface.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_core.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_instance.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger_recorders.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/loader_logger.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/manifest_file.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/runtime_interface.cpp") + env_thirdparty.add_source_files(khrloader_obj, thirdparty_dir + "/src/loader/xr_generated_loader.cpp") + env.modules_sources += khrloader_obj + + env.modules_sources += thirdparty_obj + + +# Godot source files module_obj = [] diff --git a/modules/openxr/extensions/openxr_extension_wrapper.h b/modules/openxr/extensions/openxr_extension_wrapper.h index 920bfe74b73..31f8d23268d 100644 --- a/modules/openxr/extensions/openxr_extension_wrapper.h +++ b/modules/openxr/extensions/openxr_extension_wrapper.h @@ -36,8 +36,6 @@ #include "core/templates/hash_map.h" #include "core/templates/rid.h" -#include "thirdparty/openxr/src/common/xr_linear.h" - #include class OpenXRAPI; diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp index 39b5c61e8e7..9038e9f4587 100644 --- a/modules/openxr/extensions/openxr_opengl_extension.cpp +++ b/modules/openxr/extensions/openxr_opengl_extension.cpp @@ -278,8 +278,8 @@ bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in } bool OpenXROpenGLExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) { - XrMatrix4x4f matrix; - XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far); + OpenXRUtil::XrMatrix4x4f matrix; + OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(&matrix, OpenXRUtil::GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far); for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { diff --git a/modules/openxr/extensions/openxr_vulkan_extension.cpp b/modules/openxr/extensions/openxr_vulkan_extension.cpp index 2902c16baf4..9429d9e0824 100644 --- a/modules/openxr/extensions/openxr_vulkan_extension.cpp +++ b/modules/openxr/extensions/openxr_vulkan_extension.cpp @@ -381,8 +381,8 @@ bool OpenXRVulkanExtension::get_swapchain_image_data(XrSwapchain p_swapchain, in bool OpenXRVulkanExtension::create_projection_fov(const XrFovf p_fov, double p_z_near, double p_z_far, Projection &r_camera_matrix) { // Even though this is a Vulkan renderer we're using OpenGL coordinate systems - XrMatrix4x4f matrix; - XrMatrix4x4f_CreateProjectionFov(&matrix, GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far); + OpenXRUtil::XrMatrix4x4f matrix; + OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(&matrix, OpenXRUtil::GRAPHICS_OPENGL, p_fov, (float)p_z_near, (float)p_z_far); for (int j = 0; j < 4; j++) { for (int i = 0; i < 4; i++) { diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h index 96af2bfc492..9374cb7afad 100644 --- a/modules/openxr/openxr_api.h +++ b/modules/openxr/openxr_api.h @@ -48,8 +48,6 @@ #include "core/templates/vector.h" #include "servers/xr/xr_pose.h" -#include "thirdparty/openxr/src/common/xr_linear.h" - #include // Note, OpenXR code that we wrote for our plugin makes use of C++20 notation for initializing structs which ensures zeroing out unspecified members. diff --git a/modules/openxr/openxr_util.cpp b/modules/openxr/openxr_util.cpp index 0c5cdd71131..1d442333378 100644 --- a/modules/openxr/openxr_util.cpp +++ b/modules/openxr/openxr_util.cpp @@ -32,6 +32,8 @@ #include +#include + #define XR_ENUM_CASE_STR(name, val) \ case name: \ return #name; @@ -75,3 +77,89 @@ String OpenXRUtil::make_xr_version_string(XrVersion p_version) { return version; } + +// Copied from OpenXR xr_linear.h private header, so we can still link against +// system-provided packages without relying on our `thirdparty` code. + +// Copyright (c) 2017 The Khronos Group Inc. +// Copyright (c) 2016 Oculus VR, LLC. +// +// SPDX-License-Identifier: Apache-2.0 + +// Creates a projection matrix based on the specified dimensions. +// The projection matrix transforms -Z=forward, +Y=up, +X=right to the appropriate clip space for the graphics API. +// The far plane is placed at infinity if farZ <= nearZ. +// An infinite projection matrix is preferred for rasterization because, except for +// things *right* up against the near plane, it always provides better precision: +// "Tightening the Precision of Perspective Rendering" +// Paul Upchurch, Mathieu Desbrun +// Journal of Graphics Tools, Volume 16, Issue 1, 2012 +void OpenXRUtil::XrMatrix4x4f_CreateProjection(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const float tanAngleLeft, + const float tanAngleRight, const float tanAngleUp, float const tanAngleDown, + const float nearZ, const float farZ) { + const float tanAngleWidth = tanAngleRight - tanAngleLeft; + + // Set to tanAngleDown - tanAngleUp for a clip space with positive Y down (Vulkan). + // Set to tanAngleUp - tanAngleDown for a clip space with positive Y up (OpenGL / D3D / Metal). + const float tanAngleHeight = graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown); + + // Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES). + // Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal). + const float offsetZ = (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0; + + if (farZ <= nearZ) { + // place the far plane at infinity + result->m[0] = 2.0f / tanAngleWidth; + result->m[4] = 0.0f; + result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; + result->m[12] = 0.0f; + + result->m[1] = 0.0f; + result->m[5] = 2.0f / tanAngleHeight; + result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight; + result->m[13] = 0.0f; + + result->m[2] = 0.0f; + result->m[6] = 0.0f; + result->m[10] = -1.0f; + result->m[14] = -(nearZ + offsetZ); + + result->m[3] = 0.0f; + result->m[7] = 0.0f; + result->m[11] = -1.0f; + result->m[15] = 0.0f; + } else { + // normal projection + result->m[0] = 2.0f / tanAngleWidth; + result->m[4] = 0.0f; + result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; + result->m[12] = 0.0f; + + result->m[1] = 0.0f; + result->m[5] = 2.0f / tanAngleHeight; + result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight; + result->m[13] = 0.0f; + + result->m[2] = 0.0f; + result->m[6] = 0.0f; + result->m[10] = -(farZ + offsetZ) / (farZ - nearZ); + result->m[14] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ); + + result->m[3] = 0.0f; + result->m[7] = 0.0f; + result->m[11] = -1.0f; + result->m[15] = 0.0f; + } +} + +// Creates a projection matrix based on the specified FOV. +void OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const XrFovf fov, + const float nearZ, const float farZ) { + const float tanLeft = tanf(fov.angleLeft); + const float tanRight = tanf(fov.angleRight); + + const float tanDown = tanf(fov.angleDown); + const float tanUp = tanf(fov.angleUp); + + XrMatrix4x4f_CreateProjection(result, graphicsApi, tanLeft, tanRight, tanUp, tanDown, nearZ, farZ); +} diff --git a/modules/openxr/openxr_util.h b/modules/openxr/openxr_util.h index 8ad68c0b022..3f36ab9fca2 100644 --- a/modules/openxr/openxr_util.h +++ b/modules/openxr/openxr_util.h @@ -44,6 +44,27 @@ public: static String get_action_type_name(XrActionType p_action_type); static String get_environment_blend_mode_name(XrEnvironmentBlendMode p_blend_mode); static String make_xr_version_string(XrVersion p_version); + + // Copied from OpenXR xr_linear.h private header, so we can still link against + // system-provided packages without relying on our `thirdparty` code. + + // Column-major, pre-multiplied. This type does not exist in the OpenXR API and is provided for convenience. + typedef struct XrMatrix4x4f { + float m[16]; + } XrMatrix4x4f; + + typedef enum GraphicsAPI { + GRAPHICS_VULKAN, + GRAPHICS_OPENGL, + GRAPHICS_OPENGL_ES, + GRAPHICS_D3D + } GraphicsAPI; + + static void XrMatrix4x4f_CreateProjection(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const float tanAngleLeft, + const float tanAngleRight, const float tanAngleUp, float const tanAngleDown, + const float nearZ, const float farZ); + static void XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const XrFovf fov, + const float nearZ, const float farZ); }; #endif // OPENXR_UTIL_H diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py index ce743fbf8a8..a723bb5d584 100644 --- a/platform/linuxbsd/detect.py +++ b/platform/linuxbsd/detect.py @@ -291,6 +291,9 @@ def configure(env: "Environment"): # No pkgconfig file so far, hardcode expected lib name. env.Append(LIBS=["embree3"]) + if not env["builtin_openxr"]: + env.ParseConfig("pkg-config openxr --cflags --libs") + if env["fontconfig"]: if not env["use_sowrap"]: if os.system("pkg-config --exists fontconfig") == 0: # 0 means found