1use euclid::Transform3D;
6use serde::{Deserialize, Serialize};
7
8use crate::{FrameUpdateEvent, HitTestId, HitTestSource};
9
10#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
11pub struct ClipPlanes {
12 pub near: f32,
13 pub far: f32,
14 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 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, Serialize, Deserialize)]
47pub struct HitTestList {
49 tests: Vec<HitTestSource>,
50 uncommitted_tests: Vec<HitTestSource>,
51}
52
53impl HitTestList {
54 pub fn request_hit_test(&mut self, source: HitTestSource) {
55 self.uncommitted_tests.push(source)
56 }
57
58 pub fn commit_tests(&mut self) -> Vec<FrameUpdateEvent> {
59 let mut events = vec![];
60 for test in self.uncommitted_tests.drain(..) {
61 events.push(FrameUpdateEvent::HitTestSourceAdded(test.id));
62 self.tests.push(test);
63 }
64 events
65 }
66
67 pub fn tests(&self) -> &[HitTestSource] {
68 &self.tests
69 }
70
71 pub fn cancel_hit_test(&mut self, id: HitTestId) {
72 self.tests.retain(|s| s.id != id);
73 self.uncommitted_tests.retain(|s| s.id != id);
74 }
75}
76
77#[inline]
78pub fn fov_to_projection_matrix<T, U>(
80 left: f32,
81 right: f32,
82 top: f32,
83 bottom: f32,
84 clip_planes: ClipPlanes,
85) -> Transform3D<f32, T, U> {
86 let near = clip_planes.near;
87 let left = left.tan() * near;
89 let right = right.tan() * near;
90 let top = top.tan() * near;
91 let bottom = bottom.tan() * near;
92
93 frustum_to_projection_matrix(left, right, top, bottom, clip_planes)
94}
95
96#[inline]
97pub fn frustum_to_projection_matrix<T, U>(
99 left: f32,
100 right: f32,
101 top: f32,
102 bottom: f32,
103 clip_planes: ClipPlanes,
104) -> Transform3D<f32, T, U> {
105 let near = clip_planes.near;
106 let far = clip_planes.far;
107
108 let w = right - left;
109 let h = top - bottom;
110 let d = far - near;
111
112 Transform3D::new(
114 2. * near / w,
115 0.,
116 0.,
117 0.,
118 0.,
119 2. * near / h,
120 0.,
121 0.,
122 (right + left) / w,
123 (top + bottom) / h,
124 -(far + near) / d,
125 -1.,
126 0.,
127 0.,
128 -2. * far * near / d,
129 0.,
130 )
131}