/* 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, uncommitted_tests: Vec, } impl HitTestList { pub fn request_hit_test(&mut self, source: HitTestSource) { self.uncommitted_tests.push(source) } pub fn commit_tests(&mut self) -> Vec { 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( left: f32, right: f32, top: f32, bottom: f32, clip_planes: ClipPlanes, ) -> Transform3D { 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( left: f32, right: f32, top: f32, bottom: f32, clip_planes: ClipPlanes, ) -> Transform3D { 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., ) }