The open source OpenXR runtime
1// Copyright 2018-2020, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Input transform tests.
6 * @author Ryan Pavlik <ryan.pavlik@collabora.com>
7 */
8
9#include "catch/catch.hpp"
10
11#include <xrt/xrt_defines.h>
12
13#include <oxr/oxr_input_transform.h>
14#include <oxr/oxr_logger.h>
15#include <oxr/oxr_objects.h>
16
17using Catch::Generators::values;
18
19TEST_CASE("input_transform")
20{
21 struct oxr_logger log;
22 oxr_log_init(&log, "test");
23 struct oxr_sink_logger slog = {};
24
25 struct oxr_input_transform *transforms = NULL;
26 size_t num_transforms = 0;
27
28 oxr_input_value_tagged input = {};
29 oxr_input_value_tagged output = {};
30
31 SECTION("Float action")
32 {
33 XrActionType action_type = XR_ACTION_TYPE_FLOAT_INPUT;
34
35 SECTION("From Vec1 -1 to 1 identity")
36 {
37 input.type = XRT_INPUT_TYPE_VEC1_MINUS_ONE_TO_ONE;
38
39 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type, "float_action",
40 "/dummy_float", &transforms, &num_transforms));
41
42 // Just identity
43 CHECK(num_transforms == 1);
44 CHECK(transforms != nullptr);
45
46 SECTION("Roundtrip")
47 {
48 auto value = GENERATE(values({-1.f, -0.5f, 0.f, -0.f, 0.5f, 1.f}));
49 input.value.vec1.x = value;
50
51 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
52 CHECK(input.value.vec1.x == output.value.vec1.x);
53 }
54 }
55
56 SECTION("From Vec1 0 to 1 identity")
57 {
58 input.type = XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE;
59
60 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type, "float_action",
61 "/dummy_float", &transforms, &num_transforms));
62
63 // Just identity
64 CHECK(num_transforms == 1);
65 CHECK(transforms != nullptr);
66
67 SECTION("Roundtrip")
68 {
69 auto value = GENERATE(values({0.f, -0.f, 0.5f, 1.f}));
70 input.value.vec1.x = value;
71
72 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
73 CHECK(input.value.vec1.x == output.value.vec1.x);
74 }
75 }
76
77 SECTION("From Vec2 input")
78 {
79 input.type = XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE;
80 input.value.vec2.x = -1;
81 input.value.vec2.y = 1;
82
83 SECTION("path component x")
84 {
85 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type,
86 "float_action", "/dummy_vec2/x", &transforms,
87 &num_transforms));
88
89 // A get-x
90 CHECK(num_transforms == 1);
91 CHECK(transforms != nullptr);
92
93 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
94 CHECK(input.value.vec2.x == output.value.vec1.x);
95 }
96
97 SECTION("path component y")
98 {
99 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type,
100 "float_action", "/dummy_vec2/y", &transforms,
101 &num_transforms));
102
103 // A get-y
104 CHECK(num_transforms == 1);
105 CHECK(transforms != nullptr);
106
107 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
108 CHECK(input.value.vec2.y == output.value.vec1.x);
109 }
110
111 SECTION("no component")
112 {
113 CHECK_FALSE(oxr_input_transform_create_chain(&log, &slog, input.type, action_type,
114 "float_action", "/dummy_vec2", &transforms,
115 &num_transforms));
116
117 // Shouldn't make a transform, not possible
118 CHECK(num_transforms == 0);
119 CHECK(transforms == nullptr);
120
121 // shouldn't do anything, but shouldn't explode.
122 CHECK_FALSE(oxr_input_transform_process(transforms, num_transforms, &input, &output));
123 }
124 }
125
126 SECTION("From bool input")
127 {
128 input.type = XRT_INPUT_TYPE_BOOLEAN;
129 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type, "float_action",
130 "/dummy_bool", &transforms, &num_transforms));
131
132 // A bool-to-float
133 CHECK(num_transforms == 1);
134 CHECK(transforms != nullptr);
135
136 SECTION("False")
137 {
138 input.value.boolean = false;
139
140 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
141 CHECK(0.0f == output.value.vec1.x);
142 }
143
144 SECTION("True")
145 {
146 input.value.boolean = true;
147
148 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
149 CHECK(1.0f == output.value.vec1.x);
150 }
151 }
152 }
153
154 SECTION("Bool action")
155 {
156 XrActionType action_type = XR_ACTION_TYPE_BOOLEAN_INPUT;
157 SECTION("From Bool identity")
158 {
159 input.type = XRT_INPUT_TYPE_BOOLEAN;
160
161 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type, "bool_action",
162 "/dummy_bool", &transforms, &num_transforms));
163 CHECK(num_transforms == 1);
164 CHECK(transforms != nullptr);
165
166 SECTION("Roundtrip")
167 {
168 auto value = GENERATE(values({0, 1}));
169 input.value.boolean = bool(value);
170 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
171 CHECK(input.value.boolean == output.value.boolean);
172 }
173 }
174
175 SECTION("From Vec1 -1 to 1")
176 {
177 input.type = XRT_INPUT_TYPE_VEC1_MINUS_ONE_TO_ONE;
178
179 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type, "bool_action",
180 "/dummy_float", &transforms, &num_transforms));
181 CHECK(num_transforms == 1);
182 CHECK(transforms != nullptr);
183
184 SECTION("True")
185 {
186 auto value = GENERATE(values({0.5f, 1.f}));
187 input.value.vec1.x = value;
188
189 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
190 CHECK(output.value.boolean == true);
191 }
192
193 SECTION("False")
194 {
195 auto value = GENERATE(values({0.0f, -1.f}));
196 input.value.vec1.x = value;
197
198 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
199 CHECK(output.value.boolean == false);
200 }
201 }
202
203 SECTION("From Vec1 0 to 1")
204 {
205 input.type = XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE;
206
207 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type, "bool_action",
208 "/dummy_float", &transforms, &num_transforms));
209 // A bool to float
210 CHECK(num_transforms == 1);
211 CHECK(transforms != nullptr);
212
213 SECTION("True")
214 {
215 auto value = GENERATE(values({0.95f, 1.f}));
216 input.value.vec1.x = value;
217
218 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
219 CHECK(output.value.boolean == true);
220 }
221
222 SECTION("False")
223 {
224 auto value = GENERATE(values({0.0f, 0.5f}));
225 input.value.vec1.x = value;
226
227 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
228 CHECK(output.value.boolean == false);
229 }
230 }
231
232 SECTION("From Vec2")
233 {
234 input.type = XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE;
235 input.value.vec2.x = -1;
236 input.value.vec2.y = 1;
237
238 SECTION("x")
239 {
240 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type,
241 "float_action", "/dummy_vec2/x", &transforms,
242 &num_transforms));
243 CHECK(num_transforms == 2);
244 CHECK(transforms != nullptr);
245
246 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
247 CHECK(false == output.value.boolean);
248 }
249
250 SECTION("y")
251 {
252 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type,
253 "float_action", "/dummy_vec2/y", &transforms,
254 &num_transforms));
255 CHECK(num_transforms == 2);
256 CHECK(transforms != nullptr);
257
258 CHECK(oxr_input_transform_process(transforms, num_transforms, &input, &output));
259 CHECK(true == output.value.boolean);
260 }
261
262 SECTION("no component")
263 {
264 CHECK_FALSE(oxr_input_transform_create_chain(&log, &slog, input.type, action_type,
265 "float_action", "/dummy", &transforms,
266 &num_transforms));
267
268 // Shouldn't make a transform, not possible
269 CHECK(num_transforms == 0);
270 CHECK(transforms == nullptr);
271
272 // shouldn't do anything, but shouldn't explode.
273 CHECK_FALSE(oxr_input_transform_process(transforms, num_transforms, &input, &output));
274 }
275 }
276 }
277
278 SECTION("Pose action")
279 {
280 XrActionType action_type = XR_ACTION_TYPE_POSE_INPUT;
281
282 SECTION("From Pose identity")
283 {
284 input.type = XRT_INPUT_TYPE_POSE;
285 CHECK(oxr_input_transform_create_chain(&log, &slog, input.type, action_type, "pose_action",
286 "/dummy_pose", &transforms, &num_transforms));
287 // Identity, just so this binding doesn't get culled.
288 CHECK(num_transforms == 1);
289 }
290
291 SECTION("From other input")
292 {
293 auto input_type = GENERATE(values({
294 XRT_INPUT_TYPE_BOOLEAN,
295 XRT_INPUT_TYPE_VEC1_MINUS_ONE_TO_ONE,
296 XRT_INPUT_TYPE_VEC1_ZERO_TO_ONE,
297 XRT_INPUT_TYPE_VEC2_MINUS_ONE_TO_ONE,
298 XRT_INPUT_TYPE_VEC3_MINUS_ONE_TO_ONE,
299 }));
300
301 CAPTURE(input_type);
302 input.type = input_type;
303
304 CHECK_FALSE(oxr_input_transform_create_chain(&log, &slog, input.type, action_type,
305 "pose_action", "/dummy", &transforms,
306 &num_transforms));
307
308 // not possible
309 CHECK(num_transforms == 0);
310 CHECK(transforms == nullptr);
311 }
312 }
313
314 oxr_log_slog(&log, &slog);
315 oxr_input_transform_destroy(&transforms);
316 CHECK(NULL == transforms);
317}