//! RenderElements specific to using a `GlesRenderer` use crate::{ backend::renderer::{ element::{texture::TextureRenderElement, Element, Id, Kind, RenderElement, UnderlyingStorage}, utils::{CommitCounter, DamageSet, OpaqueRegions}, }, utils::{Buffer, Logical, Physical, Point, Rectangle, Scale, Transform}, }; use super::{GlesError, GlesFrame, GlesPixelProgram, GlesRenderer, GlesTexProgram, GlesTexture, Uniform}; /// Render element for drawing with a gles2 pixel shader #[derive(Debug, Clone)] pub struct PixelShaderElement { shader: GlesPixelProgram, id: Id, commit_counter: CommitCounter, area: Rectangle, opaque_regions: Vec>, alpha: f32, additional_uniforms: Vec>, kind: Kind, } impl PixelShaderElement { /// Create a new [`PixelShaderElement`] from a [`GlesPixelProgram`], /// which can be constructed using [`GlesRenderer::compile_custom_pixel_shader`] pub fn new( shader: GlesPixelProgram, area: Rectangle, opaque_regions: Option>>, alpha: f32, additional_uniforms: Vec>, kind: Kind, ) -> Self { PixelShaderElement { shader, id: Id::new(), commit_counter: CommitCounter::default(), area, opaque_regions: opaque_regions.unwrap_or_default(), alpha, additional_uniforms: additional_uniforms.into_iter().map(|u| u.into_owned()).collect(), kind, } } /// Resize the canvas area pub fn resize( &mut self, area: Rectangle, opaque_regions: Option>>, ) { let opaque_regions = opaque_regions.unwrap_or_default(); if self.area != area || self.opaque_regions != opaque_regions { self.area = area; self.opaque_regions = opaque_regions; self.commit_counter.increment(); } } /// Update the additional uniforms /// (see [`GlesRenderer::compile_custom_pixel_shader`] and [`GlesFrame::render_pixel_shader_to`]). /// /// This replaces the stored uniforms, you have to update all of them, partial updates are not possible. pub fn update_uniforms(&mut self, additional_uniforms: Vec>) { self.additional_uniforms = additional_uniforms.into_iter().map(|u| u.into_owned()).collect(); self.commit_counter.increment(); } } impl Element for PixelShaderElement { fn id(&self) -> &Id { &self.id } fn current_commit(&self) -> CommitCounter { self.commit_counter } fn src(&self) -> Rectangle { Rectangle::from_size(self.area.size.to_f64().to_buffer(1.0, Transform::Normal)) } fn geometry(&self, scale: Scale) -> Rectangle { self.area.to_physical_precise_round(scale) } fn opaque_regions(&self, scale: Scale) -> OpaqueRegions { self.opaque_regions .iter() .map(|region| region.to_physical_precise_round(scale)) .collect() } fn alpha(&self) -> f32 { self.alpha } fn kind(&self) -> Kind { self.kind } } impl RenderElement for PixelShaderElement { #[profiling::function] fn draw( &self, frame: &mut GlesFrame<'_, '_>, src: Rectangle, dst: Rectangle, damage: &[Rectangle], _opaque_regions: &[Rectangle], ) -> Result<(), GlesError> { frame.render_pixel_shader_to( &self.shader, src, dst, self.area.size.to_buffer(1, Transform::Normal), Some(damage), self.alpha, &self.additional_uniforms, ) } #[inline] fn underlying_storage(&self, _renderer: &mut GlesRenderer) -> Option> { None } } /// Render element for drawing with a gles2 texture shader #[derive(Debug)] pub struct TextureShaderElement { inner: TextureRenderElement, program: GlesTexProgram, id: Id, additional_uniforms: Vec>, } impl TextureShaderElement { /// Create a new [`TextureShaderElement`] from a [`TextureRenderElement`] and a /// [`GlesTexProgram`], which can be constructed using /// [`GlesRenderer::compile_custom_texture_shader`] pub fn new( inner: TextureRenderElement, program: GlesTexProgram, additional_uniforms: Vec>, ) -> Self { Self { inner, program, id: Id::new(), additional_uniforms: additional_uniforms.into_iter().map(|u| u.into_owned()).collect(), } } } impl Element for TextureShaderElement { fn id(&self) -> &Id { &self.id } fn current_commit(&self) -> CommitCounter { self.inner.current_commit() } fn geometry(&self, scale: Scale) -> Rectangle { self.inner.geometry(scale) } fn transform(&self) -> Transform { self.inner.transform() } fn src(&self) -> Rectangle { self.inner.src() } fn damage_since(&self, scale: Scale, commit: Option) -> DamageSet { self.inner.damage_since(scale, commit) } fn opaque_regions(&self, scale: Scale) -> OpaqueRegions { self.inner.opaque_regions(scale) } fn alpha(&self) -> f32 { self.inner.alpha() } fn kind(&self) -> Kind { self.inner.kind() } fn location(&self, scale: Scale) -> Point { self.inner.location(scale) } } impl RenderElement for TextureShaderElement { #[profiling::function] fn draw( &self, frame: &mut GlesFrame<'_, '_>, src: Rectangle, dst: Rectangle, damage: &[Rectangle], opaque_regions: &[Rectangle], ) -> Result<(), GlesError> { frame.render_texture_from_to( &self.inner.texture, src, dst, damage, opaque_regions, self.transform(), self.alpha(), Some(&self.program), &self.additional_uniforms, ) } }