| /* This Source Code Form is subject to the terms of the Mozilla Public |
| * License, v. 2.0. If a copy of the MPL was not distributed with this |
| * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ |
| |
| use euclid::Transform3D; |
| |
| use crate::{FrameUpdateEvent, HitTestId, HitTestSource}; |
| |
| #[derive(Clone, Copy, Debug)] |
| #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] |
| pub struct ClipPlanes { |
| pub near: f32, |
| pub far: f32, |
| /// Was there an update that needs propagation to the client? |
| update: bool, |
| } |
| |
| impl Default for ClipPlanes { |
| fn default() -> Self { |
| ClipPlanes { |
| near: 0.1, |
| far: 1000., |
| update: false, |
| } |
| } |
| } |
| |
| impl ClipPlanes { |
| pub fn update(&mut self, near: f32, far: f32) { |
| self.near = near; |
| self.far = far; |
| self.update = true; |
| } |
| |
| /// Checks for and clears the pending update flag |
| pub fn recently_updated(&mut self) -> bool { |
| if self.update { |
| self.update = false; |
| true |
| } else { |
| false |
| } |
| } |
| } |
| |
| #[derive(Clone, Debug, Default)] |
| #[cfg_attr(feature = "ipc", derive(serde::Serialize, serde::Deserialize))] |
| /// Holds on to hit tests |
| pub struct HitTestList { |
| tests: Vec<HitTestSource>, |
| uncommitted_tests: Vec<HitTestSource>, |
| } |
| |
| impl HitTestList { |
| pub fn request_hit_test(&mut self, source: HitTestSource) { |
| self.uncommitted_tests.push(source) |
| } |
| |
| pub fn commit_tests(&mut self) -> Vec<FrameUpdateEvent> { |
| let mut events = vec![]; |
| for test in self.uncommitted_tests.drain(..) { |
| events.push(FrameUpdateEvent::HitTestSourceAdded(test.id)); |
| self.tests.push(test); |
| } |
| events |
| } |
| |
| pub fn tests(&self) -> &[HitTestSource] { |
| &self.tests |
| } |
| |
| pub fn cancel_hit_test(&mut self, id: HitTestId) { |
| self.tests.retain(|s| s.id != id); |
| self.uncommitted_tests.retain(|s| s.id != id); |
| } |
| } |
| |
| #[inline] |
| /// Construct a projection matrix given the four angles from the center for the faces of the viewing frustum |
| pub fn fov_to_projection_matrix<T, U>( |
| left: f32, |
| right: f32, |
| top: f32, |
| bottom: f32, |
| clip_planes: ClipPlanes, |
| ) -> Transform3D<f32, T, U> { |
| let near = clip_planes.near; |
| // XXXManishearth deal with infinite planes |
| let left = left.tan() * near; |
| let right = right.tan() * near; |
| let top = top.tan() * near; |
| let bottom = bottom.tan() * near; |
| |
| frustum_to_projection_matrix(left, right, top, bottom, clip_planes) |
| } |
| |
| #[inline] |
| /// Construct matrix given the actual extent of the viewing frustum on the near plane |
| pub fn frustum_to_projection_matrix<T, U>( |
| left: f32, |
| right: f32, |
| top: f32, |
| bottom: f32, |
| clip_planes: ClipPlanes, |
| ) -> Transform3D<f32, T, U> { |
| let near = clip_planes.near; |
| let far = clip_planes.far; |
| |
| let w = right - left; |
| let h = top - bottom; |
| let d = far - near; |
| |
| // Column-major order |
| Transform3D::new( |
| 2. * near / w, |
| 0., |
| 0., |
| 0., |
| 0., |
| 2. * near / h, |
| 0., |
| 0., |
| (right + left) / w, |
| (top + bottom) / h, |
| -(far + near) / d, |
| -1., |
| 0., |
| 0., |
| -2. * far * near / d, |
| 0., |
| ) |
| } |