webxr_api/
util.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use euclid::Transform3D;
6
7use crate::{FrameUpdateEvent, HitTestId, HitTestSource};
8
9#[derive(Clone, Copy, Debug)]
10#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
11pub struct ClipPlanes {
12    pub near: f32,
13    pub far: f32,
14    /// Was there an update that needs propagation to the client?
15    update: bool,
16}
17
18impl Default for ClipPlanes {
19    fn default() -> Self {
20        ClipPlanes {
21            near: 0.1,
22            far: 1000.,
23            update: false,
24        }
25    }
26}
27
28impl ClipPlanes {
29    pub fn update(&mut self, near: f32, far: f32) {
30        self.near = near;
31        self.far = far;
32        self.update = true;
33    }
34
35    /// Checks for and clears the pending update flag
36    pub fn recently_updated(&mut self) -> bool {
37        if self.update {
38            self.update = false;
39            true
40        } else {
41            false
42        }
43    }
44}
45
46#[derive(Clone, Debug, Default)]
47#[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))]
48/// Holds on to hit tests
49pub struct HitTestList {
50    tests: Vec<HitTestSource>,
51    uncommitted_tests: Vec<HitTestSource>,
52}
53
54impl HitTestList {
55    pub fn request_hit_test(&mut self, source: HitTestSource) {
56        self.uncommitted_tests.push(source)
57    }
58
59    pub fn commit_tests(&mut self) -> Vec<FrameUpdateEvent> {
60        let mut events = vec![];
61        for test in self.uncommitted_tests.drain(..) {
62            events.push(FrameUpdateEvent::HitTestSourceAdded(test.id));
63            self.tests.push(test);
64        }
65        events
66    }
67
68    pub fn tests(&self) -> &[HitTestSource] {
69        &self.tests
70    }
71
72    pub fn cancel_hit_test(&mut self, id: HitTestId) {
73        self.tests.retain(|s| s.id != id);
74        self.uncommitted_tests.retain(|s| s.id != id);
75    }
76}
77
78#[inline]
79/// Construct a projection matrix given the four angles from the center for the faces of the viewing frustum
80pub fn fov_to_projection_matrix<T, U>(
81    left: f32,
82    right: f32,
83    top: f32,
84    bottom: f32,
85    clip_planes: ClipPlanes,
86) -> Transform3D<f32, T, U> {
87    let near = clip_planes.near;
88    // XXXManishearth deal with infinite planes
89    let left = left.tan() * near;
90    let right = right.tan() * near;
91    let top = top.tan() * near;
92    let bottom = bottom.tan() * near;
93
94    frustum_to_projection_matrix(left, right, top, bottom, clip_planes)
95}
96
97#[inline]
98/// Construct matrix given the actual extent of the viewing frustum on the near plane
99pub fn frustum_to_projection_matrix<T, U>(
100    left: f32,
101    right: f32,
102    top: f32,
103    bottom: f32,
104    clip_planes: ClipPlanes,
105) -> Transform3D<f32, T, U> {
106    let near = clip_planes.near;
107    let far = clip_planes.far;
108
109    let w = right - left;
110    let h = top - bottom;
111    let d = far - near;
112
113    // Column-major order
114    Transform3D::new(
115        2. * near / w,
116        0.,
117        0.,
118        0.,
119        0.,
120        2. * near / h,
121        0.,
122        0.,
123        (right + left) / w,
124        (top + bottom) / h,
125        -(far + near) / d,
126        -1.,
127        0.,
128        0.,
129        -2. * far * near / d,
130        0.,
131    )
132}