use crate::{ backend::renderer::{ element::{Element, Id, RenderElement}, utils::{CommitCounter, DamageSet, OpaqueRegions}, Color32F, Frame, Renderer, }, render_elements, utils::{Buffer, Physical, Rectangle, Scale, Transform}, }; render_elements! { pub DrmRenderElements<'a, R, E>; Holepunch=HolepunchRenderElement, Overlay=OverlayPlaneElement, Other=&'a E, } pub struct HolepunchRenderElement { id: Id, geometry: Rectangle, } impl HolepunchRenderElement { pub fn from_render_element(id: Id, element: &E, scale: impl Into>) -> Self where R: Renderer, E: RenderElement, { HolepunchRenderElement { id, geometry: element.geometry(scale.into()), } } } impl RenderElement for HolepunchRenderElement where R: Renderer, { fn draw( &self, frame: &mut R::Frame<'_, '_>, _src: Rectangle, dst: Rectangle, damage: &[Rectangle], _opaque_regions: &[Rectangle], ) -> Result<(), R::Error> { frame.clear( Color32F::TRANSPARENT, &damage .iter() .cloned() .map(|mut d| { d.loc += dst.loc; d }) .collect::>(), ) } } impl Element for HolepunchRenderElement { fn id(&self) -> &Id { &self.id } fn current_commit(&self) -> CommitCounter { CommitCounter::default() } fn src(&self) -> Rectangle { Rectangle::default() } fn geometry(&self, _scale: Scale) -> Rectangle { self.geometry } fn transform(&self) -> Transform { Transform::Normal } fn opaque_regions(&self, _scale: Scale) -> OpaqueRegions { OpaqueRegions::from_slice(&[Rectangle::from_size(self.geometry.size)]) } } pub struct OverlayPlaneElement { id: Id, geometry: Rectangle, opaque_regions: OpaqueRegions, } impl OverlayPlaneElement { pub fn from_render_element(id: Id, element: &E, scale: impl Into>) -> Option where R: Renderer, E: RenderElement, { let scale = scale.into(); let opaque_regions = element.opaque_regions(scale); let geometry = element.geometry(scale); // We use the opaque regions to create a bounding box around them to // create a fake geometry that only includes the opaque regions. // If the element is not fully opaque this can save the renderer // from some damage when the element is moved. let mut opaque_geometry = opaque_regions .iter() .fold(Rectangle::default(), |acc, item| acc.merge(*item)); if opaque_geometry.is_empty() { return None; } // Because we will move the geometry by the top-left corner of // the opaque geometry we calculated we have to subtract // that from the element local opaque regions. let opaque_regions = opaque_regions .into_iter() .map(|mut region| { region.loc -= opaque_geometry.loc; region }) .collect(); // Move the opaque geometry relative to the original // element location opaque_geometry.loc += geometry.loc; Some(OverlayPlaneElement { id, geometry: opaque_geometry, opaque_regions, }) } } impl Element for OverlayPlaneElement { fn id(&self) -> &Id { &self.id } fn current_commit(&self) -> CommitCounter { CommitCounter::default() } fn src(&self) -> Rectangle { Rectangle::default() } fn geometry(&self, _scale: Scale) -> Rectangle { self.geometry } fn transform(&self) -> Transform { Transform::Normal } fn damage_since(&self, _scale: Scale, _commit: Option) -> DamageSet { DamageSet::default() } fn opaque_regions(&self, _scale: Scale) -> OpaqueRegions { OpaqueRegions::from_slice(&self.opaque_regions) } } impl RenderElement for OverlayPlaneElement where R: Renderer, { fn draw( &self, _frame: &mut R::Frame<'_, '_>, _src: Rectangle, _dst: Rectangle, _damage: &[Rectangle], _opaque_regions: &[Rectangle], ) -> Result<(), R::Error> { // We do not actually draw anything here Ok(()) } }