From 5fd5d1cdf8e5354788dc40729c4565ef377d3bba Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 1 Mar 2023 21:34:26 +0100 Subject: Implement `Canvas` support for `iced_tiny_skia` --- wgpu/src/layer.rs | 274 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 274 insertions(+) create mode 100644 wgpu/src/layer.rs (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs new file mode 100644 index 00000000..0840555a --- /dev/null +++ b/wgpu/src/layer.rs @@ -0,0 +1,274 @@ +//! Organize rendering primitives into a flattened list of layers. +mod image; +mod quad; +mod text; + +pub mod mesh; + +pub use image::Image; +pub use mesh::Mesh; +pub use quad::Quad; +pub use text::Text; + +use crate::Primitive; + +use iced_graphics::alignment; +use iced_graphics::{ + Background, Color, Font, Point, Rectangle, Size, Vector, Viewport, +}; + +/// A group of primitives that should be clipped together. +#[derive(Debug)] +pub struct Layer<'a> { + /// The clipping bounds of the [`Layer`]. + pub bounds: Rectangle, + + /// The quads of the [`Layer`]. + pub quads: Vec, + + /// The triangle meshes of the [`Layer`]. + pub meshes: Vec>, + + /// The text of the [`Layer`]. + pub text: Vec>, + + /// The images of the [`Layer`]. + pub images: Vec, +} + +impl<'a> Layer<'a> { + /// Creates a new [`Layer`] with the given clipping bounds. + pub fn new(bounds: Rectangle) -> Self { + Self { + bounds, + quads: Vec::new(), + meshes: Vec::new(), + text: Vec::new(), + images: Vec::new(), + } + } + + /// Creates a new [`Layer`] for the provided overlay text. + /// + /// This can be useful for displaying debug information. + pub fn overlay(lines: &'a [impl AsRef], viewport: &Viewport) -> Self { + let mut overlay = + Layer::new(Rectangle::with_size(viewport.logical_size())); + + for (i, line) in lines.iter().enumerate() { + let text = Text { + content: line.as_ref(), + bounds: Rectangle::new( + Point::new(11.0, 11.0 + 25.0 * i as f32), + Size::INFINITY, + ), + color: Color::new(0.9, 0.9, 0.9, 1.0), + size: 20.0, + font: Font::Monospace, + horizontal_alignment: alignment::Horizontal::Left, + vertical_alignment: alignment::Vertical::Top, + }; + + overlay.text.push(text); + + overlay.text.push(Text { + bounds: text.bounds + Vector::new(-1.0, -1.0), + color: Color::BLACK, + ..text + }); + } + + overlay + } + + /// Distributes the given [`Primitive`] and generates a list of layers based + /// on its contents. + pub fn generate( + primitives: &'a [Primitive], + viewport: &Viewport, + ) -> Vec { + let first_layer = + Layer::new(Rectangle::with_size(viewport.logical_size())); + + let mut layers = vec![first_layer]; + + for primitive in primitives { + Self::process_primitive( + &mut layers, + Vector::new(0.0, 0.0), + primitive, + 0, + ); + } + + layers + } + + fn process_primitive( + layers: &mut Vec, + translation: Vector, + primitive: &'a Primitive, + current_layer: usize, + ) { + match primitive { + Primitive::Text { + content, + bounds, + size, + color, + font, + horizontal_alignment, + vertical_alignment, + } => { + let layer = &mut layers[current_layer]; + + layer.text.push(Text { + content, + bounds: *bounds + translation, + size: *size, + color: *color, + font: *font, + horizontal_alignment: *horizontal_alignment, + vertical_alignment: *vertical_alignment, + }); + } + Primitive::Quad { + bounds, + background, + border_radius, + border_width, + border_color, + } => { + let layer = &mut layers[current_layer]; + + // TODO: Move some of these computations to the GPU (?) + layer.quads.push(Quad { + position: [ + bounds.x + translation.x, + bounds.y + translation.y, + ], + size: [bounds.width, bounds.height], + color: match background { + Background::Color(color) => color.into_linear(), + }, + border_radius: *border_radius, + border_width: *border_width, + border_color: border_color.into_linear(), + }); + } + Primitive::Image { handle, bounds } => { + let layer = &mut layers[current_layer]; + + layer.images.push(Image::Raster { + handle: handle.clone(), + bounds: *bounds + translation, + }); + } + Primitive::Svg { + handle, + color, + bounds, + } => { + let layer = &mut layers[current_layer]; + + layer.images.push(Image::Vector { + handle: handle.clone(), + color: *color, + bounds: *bounds + translation, + }); + } + Primitive::SolidMesh { buffers, size } => { + let layer = &mut layers[current_layer]; + + let bounds = Rectangle::new( + Point::new(translation.x, translation.y), + *size, + ); + + // Only draw visible content + if let Some(clip_bounds) = layer.bounds.intersection(&bounds) { + layer.meshes.push(Mesh::Solid { + origin: Point::new(translation.x, translation.y), + buffers, + clip_bounds, + }); + } + } + Primitive::GradientMesh { + buffers, + size, + gradient, + } => { + let layer = &mut layers[current_layer]; + + let bounds = Rectangle::new( + Point::new(translation.x, translation.y), + *size, + ); + + // Only draw visible content + if let Some(clip_bounds) = layer.bounds.intersection(&bounds) { + layer.meshes.push(Mesh::Gradient { + origin: Point::new(translation.x, translation.y), + buffers, + clip_bounds, + gradient, + }); + } + } + Primitive::Group { primitives } => { + // TODO: Inspect a bit and regroup (?) + for primitive in primitives { + Self::process_primitive( + layers, + translation, + primitive, + current_layer, + ) + } + } + Primitive::Clip { bounds, content } => { + let layer = &mut layers[current_layer]; + let translated_bounds = *bounds + translation; + + // Only draw visible content + if let Some(clip_bounds) = + layer.bounds.intersection(&translated_bounds) + { + let clip_layer = Layer::new(clip_bounds); + layers.push(clip_layer); + + Self::process_primitive( + layers, + translation, + content, + layers.len() - 1, + ); + } + } + Primitive::Translate { + translation: new_translation, + content, + } => { + Self::process_primitive( + layers, + translation + *new_translation, + content, + current_layer, + ); + } + Primitive::Cache { content } => { + Self::process_primitive( + layers, + translation, + content, + current_layer, + ); + } + Primitive::Fill { .. } | Primitive::Stroke { .. } => { + // Unsupported! + // TODO: Draw a placeholder (?) + } + } + } +} -- cgit From bbeaf10c04a922af5c1c3b898f0c4301d23feab0 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 3 Mar 2023 03:55:07 +0100 Subject: Mark `Primitive` as `non-exhaustive` in `iced_graphics` --- wgpu/src/layer.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 0840555a..69fcf899 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -265,9 +265,8 @@ impl<'a> Layer<'a> { current_layer, ); } - Primitive::Fill { .. } | Primitive::Stroke { .. } => { + _ => { // Unsupported! - // TODO: Draw a placeholder (?) } } } -- cgit From 3a0d34c0240f4421737a6a08761f99d6f8140d02 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 4 Mar 2023 05:37:11 +0100 Subject: Create `iced_widget` subcrate and re-organize the whole codebase --- wgpu/src/layer.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 69fcf899..cb9d5e2f 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -10,12 +10,9 @@ pub use mesh::Mesh; pub use quad::Quad; pub use text::Text; -use crate::Primitive; - -use iced_graphics::alignment; -use iced_graphics::{ - Background, Color, Font, Point, Rectangle, Size, Vector, Viewport, -}; +use crate::core::alignment; +use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; +use crate::graphics::{Primitive, Viewport}; /// A group of primitives that should be clipped together. #[derive(Debug)] -- cgit From 707de9d788dc3c49d4ac57a19afac1bb938b78d9 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 30 Mar 2023 00:56:00 +0200 Subject: Introduce support for `Font` attributes --- wgpu/src/layer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index cb9d5e2f..c4723397 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -61,7 +61,7 @@ impl<'a> Layer<'a> { ), color: Color::new(0.9, 0.9, 0.9, 1.0), size: 20.0, - font: Font::Monospace, + font: Font::MONOSPACE, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, }; -- cgit From 33b5a900197e2798a393d6d9a0834039666eddbb Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 19 Apr 2023 01:19:56 +0200 Subject: Make basic text shaping the default shaping strategy --- wgpu/src/layer.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index c4723397..7c5b43a3 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -64,6 +64,7 @@ impl<'a> Layer<'a> { font: Font::MONOSPACE, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, + advanced_shape: false, }; overlay.text.push(text); @@ -116,6 +117,7 @@ impl<'a> Layer<'a> { font, horizontal_alignment, vertical_alignment, + advanced_shape, } => { let layer = &mut layers[current_layer]; @@ -127,6 +129,7 @@ impl<'a> Layer<'a> { font: *font, horizontal_alignment: *horizontal_alignment, vertical_alignment: *vertical_alignment, + advanced_shape: *advanced_shape, }); } Primitive::Quad { -- cgit From 4bd290afe7d81d9aaf7467b3ce91491f6600261a Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 19 Apr 2023 02:00:45 +0200 Subject: Introduce `text::Shaping` enum and replace magic boolean --- wgpu/src/layer.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index 7c5b43a3..b9fd044e 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -10,6 +10,7 @@ pub use mesh::Mesh; pub use quad::Quad; pub use text::Text; +use crate::core; use crate::core::alignment; use crate::core::{Background, Color, Font, Point, Rectangle, Size, Vector}; use crate::graphics::{Primitive, Viewport}; @@ -64,7 +65,7 @@ impl<'a> Layer<'a> { font: Font::MONOSPACE, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, - advanced_shape: false, + shaping: core::text::Shaping::Basic, }; overlay.text.push(text); @@ -117,7 +118,7 @@ impl<'a> Layer<'a> { font, horizontal_alignment, vertical_alignment, - advanced_shape, + shaping, } => { let layer = &mut layers[current_layer]; @@ -129,7 +130,7 @@ impl<'a> Layer<'a> { font: *font, horizontal_alignment: *horizontal_alignment, vertical_alignment: *vertical_alignment, - advanced_shape: *advanced_shape, + shaping: *shaping, }); } Primitive::Quad { -- cgit From 9499a8f9e6f9971dedfae563cb133232aa3cebc2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 4 May 2023 13:00:16 +0200 Subject: Support configurable `LineHeight` in text widgets --- wgpu/src/layer.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index b9fd044e..dcae0648 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -62,6 +62,7 @@ impl<'a> Layer<'a> { ), color: Color::new(0.9, 0.9, 0.9, 1.0), size: 20.0, + line_height: core::text::LineHeight::Relative(1.2), font: Font::MONOSPACE, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, @@ -114,6 +115,7 @@ impl<'a> Layer<'a> { content, bounds, size, + line_height, color, font, horizontal_alignment, @@ -126,6 +128,7 @@ impl<'a> Layer<'a> { content, bounds: *bounds + translation, size: *size, + line_height: *line_height, color: *color, font: *font, horizontal_alignment: *horizontal_alignment, -- cgit From c189ef62a6a5dd183b8098496ac31d30f7814ff3 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 8 May 2023 14:46:56 +0200 Subject: Use `LineHeight::default` in `iced_wgpu::layer` --- wgpu/src/layer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index dcae0648..ab66264c 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -62,7 +62,7 @@ impl<'a> Layer<'a> { ), color: Color::new(0.9, 0.9, 0.9, 1.0), size: 20.0, - line_height: core::text::LineHeight::Relative(1.2), + line_height: core::text::LineHeight::default(), font: Font::MONOSPACE, horizontal_alignment: alignment::Horizontal::Left, vertical_alignment: alignment::Vertical::Top, -- cgit From 91ef07e6ebe56e46ea235f6657b17a3a078ddf5b Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Mon, 8 May 2023 14:51:53 +0200 Subject: Warn about unsupported primitives in `iced_wgpu` --- wgpu/src/layer.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'wgpu/src/layer.rs') diff --git a/wgpu/src/layer.rs b/wgpu/src/layer.rs index ab66264c..8af72b9d 100644 --- a/wgpu/src/layer.rs +++ b/wgpu/src/layer.rs @@ -270,7 +270,11 @@ impl<'a> Layer<'a> { ); } _ => { - // Unsupported! + // Not supported! + log::warn!( + "Unsupported primitive in `iced_wgpu`: {:?}", + primitive + ); } } } -- cgit