use crate::core::renderer; use crate::core::{Background, Color, Point, Rectangle, Transformation}; use crate::graphics::color; use crate::graphics::text::{Editor, Paragraph}; use crate::graphics::Mesh; use crate::image::{self, Image}; use crate::quad::{self, Quad}; use crate::text::{self, Text}; use crate::triangle; pub struct Layer { pub bounds: Rectangle, pub quads: quad::Batch, pub triangles: triangle::Batch, pub text: text::Batch, pub images: image::Batch, } impl Default for Layer { fn default() -> Self { Self { bounds: Rectangle::INFINITE, quads: quad::Batch::default(), triangles: triangle::Batch::default(), text: text::Batch::default(), images: image::Batch::default(), } } } pub struct Stack { layers: Vec, transformations: Vec, previous: Vec, pending_meshes: Vec>, pending_text: Vec>, current: usize, active_count: usize, } impl Stack { pub fn new() -> Self { Self { layers: vec![Layer::default()], transformations: vec![Transformation::IDENTITY], previous: vec![], pending_meshes: vec![Vec::new()], pending_text: vec![Vec::new()], current: 0, active_count: 1, } } pub fn draw_quad(&mut self, quad: renderer::Quad, background: Background) { let transformation = self.transformations.last().unwrap(); let bounds = quad.bounds * *transformation; let quad = Quad { position: [bounds.x, bounds.y], size: [bounds.width, bounds.height], border_color: color::pack(quad.border.color), border_radius: quad.border.radius.into(), border_width: quad.border.width, shadow_color: color::pack(quad.shadow.color), shadow_offset: quad.shadow.offset.into(), shadow_blur_radius: quad.shadow.blur_radius, }; self.layers[self.current].quads.add(quad, &background); } pub fn draw_paragraph( &mut self, paragraph: &Paragraph, position: Point, color: Color, clip_bounds: Rectangle, ) { let paragraph = Text::Paragraph { paragraph: paragraph.downgrade(), position, color, clip_bounds, transformation: self.transformations.last().copied().unwrap(), }; self.pending_text[self.current].push(paragraph); } pub fn draw_editor( &mut self, editor: &Editor, position: Point, color: Color, clip_bounds: Rectangle, ) { let editor = Text::Editor { editor: editor.downgrade(), position, color, clip_bounds, transformation: self.transformation(), }; self.pending_text[self.current].push(editor); } pub fn draw_text( &mut self, text: crate::core::Text, position: Point, color: Color, clip_bounds: Rectangle, ) { let transformation = self.transformation(); let text = Text::Cached { content: text.content, bounds: Rectangle::new(position, text.bounds) * transformation, color, size: text.size * transformation.scale_factor(), line_height: text.line_height.to_absolute(text.size) * transformation.scale_factor(), font: text.font, horizontal_alignment: text.horizontal_alignment, vertical_alignment: text.vertical_alignment, shaping: text.shaping, clip_bounds: clip_bounds * transformation, }; self.pending_text[self.current].push(text); } pub fn draw_image( &mut self, handle: crate::core::image::Handle, filter_method: crate::core::image::FilterMethod, bounds: Rectangle, ) { let image = Image::Raster { handle, filter_method, bounds: bounds * self.transformation(), }; self.layers[self.current].images.push(image); } pub fn draw_svg( &mut self, handle: crate::core::svg::Handle, color: Option, bounds: Rectangle, ) { let svg = Image::Vector { handle, color, bounds: bounds * self.transformation(), }; self.layers[self.current].images.push(svg); } pub fn draw_mesh(&mut self, mut mesh: Mesh) { match &mut mesh { Mesh::Solid { transformation, .. } | Mesh::Gradient { transformation, .. } => { *transformation = *transformation * self.transformation(); } } self.pending_meshes[self.current].push(mesh); } pub fn draw_mesh_group(&mut self, meshes: Vec) { self.flush_pending(); let transformation = self.transformation(); self.layers[self.current] .triangles .push(triangle::Item::Group { transformation, meshes, }); } pub fn draw_mesh_cache(&mut self, cache: triangle::Cache) { self.flush_pending(); let transformation = self.transformation(); self.layers[self.current] .triangles .push(triangle::Item::Cached { transformation, cache, }); } pub fn draw_text_group(&mut self, text: Vec) { self.flush_pending(); let transformation = self.transformation(); self.layers[self.current].text.push(text::Item::Group { transformation, text, }); } pub fn draw_text_cache(&mut self, cache: text::Cache) { self.flush_pending(); let transformation = self.transformation(); self.layers[self.current].text.push(text::Item::Cached { transformation, cache, }); } pub fn push_clip(&mut self, bounds: Rectangle) { self.previous.push(self.current); self.current = self.active_count; self.active_count += 1; let bounds = bounds * self.transformation(); if self.current == self.layers.len() { self.layers.push(Layer { bounds, ..Layer::default() }); self.pending_meshes.push(Vec::new()); self.pending_text.push(Vec::new()); } else { self.layers[self.current].bounds = bounds; } } pub fn pop_clip(&mut self) { self.flush_pending(); self.current = self.previous.pop().unwrap(); } pub fn push_transformation(&mut self, transformation: Transformation) { self.flush_pending(); self.transformations .push(self.transformation() * transformation); } pub fn pop_transformation(&mut self) { let _ = self.transformations.pop(); } fn transformation(&self) -> Transformation { self.transformations.last().copied().unwrap() } pub fn iter_mut(&mut self) -> impl Iterator { self.flush_pending(); self.layers[..self.active_count].iter_mut() } pub fn iter(&self) -> impl Iterator { self.layers[..self.active_count].iter() } pub fn clear(&mut self) { for (live, pending_meshes) in self.layers[..self.active_count] .iter_mut() .zip(self.pending_meshes.iter_mut()) { live.bounds = Rectangle::INFINITE; live.quads.clear(); live.triangles.clear(); live.text.clear(); live.images.clear(); pending_meshes.clear(); } self.current = 0; self.active_count = 1; self.previous.clear(); } // We want to keep the allocated memory #[allow(clippy::drain_collect)] fn flush_pending(&mut self) { let transformation = self.transformation(); let pending_meshes = &mut self.pending_meshes[self.current]; if !pending_meshes.is_empty() { self.layers[self.current] .triangles .push(triangle::Item::Group { transformation, meshes: pending_meshes.drain(..).collect(), }); } let pending_text = &mut self.pending_text[self.current]; if !pending_text.is_empty() { self.layers[self.current].text.push(text::Item::Group { transformation, text: pending_text.drain(..).collect(), }); } } } impl Default for Stack { fn default() -> Self { Self::new() } }