The open source OpenXR runtime
1// Copyright 2020, Collabora, Ltd.
2// SPDX-License-Identifier: BSL-1.0
3/*!
4 * @file
5 * @brief Code to handle distortion parameters and fov.
6 * @author Jakob Bornecrantz <jakob@collabora.com>
7 * @ingroup aux_distortion
8 */
9
10#include "xrt/xrt_device.h"
11
12#include "math/m_mathinclude.h"
13
14#include "util/u_misc.h"
15#include "util/u_device.h"
16#include "util/u_distortion.h"
17
18#include <assert.h>
19
20static inline float
21vertical_offset_meters(const struct u_cardboard_distortion_arguments *args)
22{
23 switch (args->vertical_alignment) {
24 case U_CARDBOARD_VERTICAL_ALIGNMENT_TOP:
25 return args->screen.h_meters - args->tray_to_lens_distance_meters - 0.003f;
26 case U_CARDBOARD_VERTICAL_ALIGNMENT_BOTTOM: return args->tray_to_lens_distance_meters - 0.003f;
27 case U_CARDBOARD_VERTICAL_ALIGNMENT_CENTER:
28 default: return args->screen.h_meters * 0.5f;
29 }
30}
31
32void
33u_distortion_cardboard_calculate(const struct u_cardboard_distortion_arguments *args,
34 struct xrt_hmd_parts *parts,
35 struct u_cardboard_distortion *out_dist)
36{
37 /*
38 * HMD parts
39 */
40
41 uint32_t view_count = parts->view_count;
42
43 // Cardboard always has two views
44 assert(view_count == 2);
45
46 uint32_t w_pixels = args->screen.w_pixels / view_count;
47 uint32_t h_pixels = args->screen.h_pixels;
48
49 // Base assumption, the driver can change afterwards.
50 if (parts->blend_mode_count == 0) {
51 size_t idx = 0;
52 parts->blend_modes[idx++] = XRT_BLEND_MODE_OPAQUE;
53 parts->blend_mode_count = idx;
54 }
55
56 // Use the full screen.
57 parts->screens[0].w_pixels = args->screen.w_pixels;
58 parts->screens[0].h_pixels = args->screen.h_pixels;
59
60 // Copy the arguments.
61 out_dist->args = *args;
62
63 // Save the results.
64 for (uint32_t i = 0; i < view_count; ++i) {
65 parts->views[i].viewport.x_pixels = 0 + i * w_pixels;
66 parts->views[i].viewport.y_pixels = 0;
67 parts->views[i].viewport.w_pixels = w_pixels;
68 parts->views[i].viewport.h_pixels = h_pixels;
69 parts->views[i].display.w_pixels = w_pixels;
70 parts->views[i].display.h_pixels = h_pixels;
71 parts->views[i].rot = u_device_rotation_ident;
72 parts->distortion.fov[i] = args->fov;
73
74 struct u_cardboard_distortion_values *values = &out_dist->values[i];
75 values->distortion_k[0] = args->distortion_k[0];
76 values->distortion_k[1] = args->distortion_k[1];
77 values->distortion_k[2] = args->distortion_k[2];
78 values->distortion_k[3] = args->distortion_k[3];
79 values->distortion_k[4] = args->distortion_k[4];
80
81 // Divide by view count since each view takes a part of the screen on the X axis
82 values->screen.size.x = args->screen.w_meters / args->screen_to_lens_distance_meters;
83 values->screen.size.y = args->screen.h_meters / args->screen_to_lens_distance_meters;
84
85 if (i == 0) {
86 values->screen.offset.x = ((args->screen.w_meters - args->inter_lens_distance_meters) / 2) /
87 args->screen_to_lens_distance_meters;
88 } else if (i == 1) {
89 values->screen.offset.x = ((args->screen.w_meters + args->inter_lens_distance_meters) / 2) /
90 args->screen_to_lens_distance_meters;
91 }
92
93 // Cardboard vertical alignment
94 values->screen.offset.y = vertical_offset_meters(args) / args->screen_to_lens_distance_meters;
95
96 // Tanangle to texture coordinates
97 values->texture.size.x = tanf(-args->fov.angle_left) + tanf(args->fov.angle_right);
98 values->texture.size.y = tanf(args->fov.angle_up) + tanf(-args->fov.angle_down);
99 values->texture.offset.x = tanf(-args->fov.angle_left);
100 values->texture.offset.y = tanf(-args->fov.angle_down);
101
102 // Fix up views not covering the entire screen.
103 values->screen.size.x /= view_count;
104 values->screen.offset.x -= values->screen.size.x * i;
105 }
106}