1 | /**************************************************************************/ |
2 | /* openxr_util.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "openxr_util.h" |
32 | |
33 | #include <openxr/openxr_reflection.h> |
34 | |
35 | #include <math.h> |
36 | |
37 | #define XR_ENUM_CASE_STR(name, val) \ |
38 | case name: \ |
39 | return #name; |
40 | #define XR_ENUM_SWITCH(enumType, var) \ |
41 | switch (var) { \ |
42 | XR_LIST_ENUM_##enumType(XR_ENUM_CASE_STR) default : return "Unknown " #enumType ": " + String::num_int64(int64_t(var)); \ |
43 | } |
44 | |
45 | String OpenXRUtil::get_view_configuration_name(XrViewConfigurationType p_view_configuration){ |
46 | XR_ENUM_SWITCH(XrViewConfigurationType, p_view_configuration) |
47 | } |
48 | |
49 | String OpenXRUtil::get_reference_space_name(XrReferenceSpaceType p_reference_space){ |
50 | XR_ENUM_SWITCH(XrReferenceSpaceType, p_reference_space) |
51 | } |
52 | |
53 | String OpenXRUtil::get_structure_type_name(XrStructureType p_structure_type){ |
54 | XR_ENUM_SWITCH(XrStructureType, p_structure_type) |
55 | } |
56 | |
57 | String OpenXRUtil::get_session_state_name(XrSessionState p_session_state){ |
58 | XR_ENUM_SWITCH(XrSessionState, p_session_state) |
59 | } |
60 | |
61 | String OpenXRUtil::get_action_type_name(XrActionType p_action_type){ |
62 | XR_ENUM_SWITCH(XrActionType, p_action_type) |
63 | } |
64 | |
65 | String OpenXRUtil::get_environment_blend_mode_name(XrEnvironmentBlendMode p_blend_mode) { |
66 | XR_ENUM_SWITCH(XrEnvironmentBlendMode, p_blend_mode); |
67 | } |
68 | |
69 | String OpenXRUtil::make_xr_version_string(XrVersion p_version) { |
70 | String version; |
71 | |
72 | version += String::num_int64(XR_VERSION_MAJOR(p_version)); |
73 | version += String("." ); |
74 | version += String::num_int64(XR_VERSION_MINOR(p_version)); |
75 | version += String("." ); |
76 | version += String::num_int64(XR_VERSION_PATCH(p_version)); |
77 | |
78 | return version; |
79 | } |
80 | |
81 | // Copied from OpenXR xr_linear.h private header, so we can still link against |
82 | // system-provided packages without relying on our `thirdparty` code. |
83 | |
84 | // Copyright (c) 2017 The Khronos Group Inc. |
85 | // Copyright (c) 2016 Oculus VR, LLC. |
86 | // |
87 | // SPDX-License-Identifier: Apache-2.0 |
88 | |
89 | // Creates a projection matrix based on the specified dimensions. |
90 | // The projection matrix transforms -Z=forward, +Y=up, +X=right to the appropriate clip space for the graphics API. |
91 | // The far plane is placed at infinity if farZ <= nearZ. |
92 | // An infinite projection matrix is preferred for rasterization because, except for |
93 | // things *right* up against the near plane, it always provides better precision: |
94 | // "Tightening the Precision of Perspective Rendering" |
95 | // Paul Upchurch, Mathieu Desbrun |
96 | // Journal of Graphics Tools, Volume 16, Issue 1, 2012 |
97 | void OpenXRUtil::XrMatrix4x4f_CreateProjection(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const float tanAngleLeft, |
98 | const float tanAngleRight, const float tanAngleUp, float const tanAngleDown, |
99 | const float nearZ, const float farZ) { |
100 | const float tanAngleWidth = tanAngleRight - tanAngleLeft; |
101 | |
102 | // Set to tanAngleDown - tanAngleUp for a clip space with positive Y down (Vulkan). |
103 | // Set to tanAngleUp - tanAngleDown for a clip space with positive Y up (OpenGL / D3D / Metal). |
104 | const float tanAngleHeight = graphicsApi == GRAPHICS_VULKAN ? (tanAngleDown - tanAngleUp) : (tanAngleUp - tanAngleDown); |
105 | |
106 | // Set to nearZ for a [-1,1] Z clip space (OpenGL / OpenGL ES). |
107 | // Set to zero for a [0,1] Z clip space (Vulkan / D3D / Metal). |
108 | const float offsetZ = (graphicsApi == GRAPHICS_OPENGL || graphicsApi == GRAPHICS_OPENGL_ES) ? nearZ : 0; |
109 | |
110 | if (farZ <= nearZ) { |
111 | // place the far plane at infinity |
112 | result->m[0] = 2.0f / tanAngleWidth; |
113 | result->m[4] = 0.0f; |
114 | result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; |
115 | result->m[12] = 0.0f; |
116 | |
117 | result->m[1] = 0.0f; |
118 | result->m[5] = 2.0f / tanAngleHeight; |
119 | result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight; |
120 | result->m[13] = 0.0f; |
121 | |
122 | result->m[2] = 0.0f; |
123 | result->m[6] = 0.0f; |
124 | result->m[10] = -1.0f; |
125 | result->m[14] = -(nearZ + offsetZ); |
126 | |
127 | result->m[3] = 0.0f; |
128 | result->m[7] = 0.0f; |
129 | result->m[11] = -1.0f; |
130 | result->m[15] = 0.0f; |
131 | } else { |
132 | // normal projection |
133 | result->m[0] = 2.0f / tanAngleWidth; |
134 | result->m[4] = 0.0f; |
135 | result->m[8] = (tanAngleRight + tanAngleLeft) / tanAngleWidth; |
136 | result->m[12] = 0.0f; |
137 | |
138 | result->m[1] = 0.0f; |
139 | result->m[5] = 2.0f / tanAngleHeight; |
140 | result->m[9] = (tanAngleUp + tanAngleDown) / tanAngleHeight; |
141 | result->m[13] = 0.0f; |
142 | |
143 | result->m[2] = 0.0f; |
144 | result->m[6] = 0.0f; |
145 | result->m[10] = -(farZ + offsetZ) / (farZ - nearZ); |
146 | result->m[14] = -(farZ * (nearZ + offsetZ)) / (farZ - nearZ); |
147 | |
148 | result->m[3] = 0.0f; |
149 | result->m[7] = 0.0f; |
150 | result->m[11] = -1.0f; |
151 | result->m[15] = 0.0f; |
152 | } |
153 | } |
154 | |
155 | // Creates a projection matrix based on the specified FOV. |
156 | void OpenXRUtil::XrMatrix4x4f_CreateProjectionFov(XrMatrix4x4f *result, GraphicsAPI graphicsApi, const XrFovf fov, |
157 | const float nearZ, const float farZ) { |
158 | const float tanLeft = tanf(fov.angleLeft); |
159 | const float tanRight = tanf(fov.angleRight); |
160 | |
161 | const float tanDown = tanf(fov.angleDown); |
162 | const float tanUp = tanf(fov.angleUp); |
163 | |
164 | XrMatrix4x4f_CreateProjection(result, graphicsApi, tanLeft, tanRight, tanUp, tanDown, nearZ, farZ); |
165 | } |
166 | |