From f436f20eb86b2324126a54d4164b4cedf2134a45 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Feb 2020 03:47:36 +0100 Subject: Draft `Canvas` types and `clock` example --- wgpu/src/widget/canvas/frame.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 wgpu/src/widget/canvas/frame.rs (limited to 'wgpu/src/widget/canvas/frame.rs') diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs new file mode 100644 index 00000000..65c22c0c --- /dev/null +++ b/wgpu/src/widget/canvas/frame.rs @@ -0,0 +1,39 @@ +use iced_native::Point; + +use crate::{ + canvas::{Fill, Path, Stroke}, + triangle, +}; + +#[derive(Debug)] +pub struct Frame { + width: u32, + height: u32, + buffers: lyon::tessellation::VertexBuffers, +} + +impl Frame { + pub(crate) fn new(width: u32, height: u32) -> Frame { + Frame { + width, + height, + buffers: lyon::tessellation::VertexBuffers::new(), + } + } + + pub fn width(&self) -> u32 { + self.width + } + + pub fn height(&self) -> u32 { + self.height + } + + pub fn center(&self) -> Point { + Point::new(self.width as f32 / 2.0, self.height as f32 / 2.0) + } + + pub fn fill(&mut self, path: Path, fill: Fill) {} + + pub fn stroke(&mut self, path: Path, stroke: Stroke) {} +} -- cgit From 74dd79e97f83d3e9e13d87444740edeb353f9be8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Feb 2020 06:41:24 +0100 Subject: Rename current `Path` to `path::Builder` --- wgpu/src/widget/canvas/frame.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'wgpu/src/widget/canvas/frame.rs') diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index 65c22c0c..e5daeedb 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -33,7 +33,7 @@ impl Frame { Point::new(self.width as f32 / 2.0, self.height as f32 / 2.0) } - pub fn fill(&mut self, path: Path, fill: Fill) {} + pub fn fill(&mut self, path: &Path, fill: Fill) {} - pub fn stroke(&mut self, path: Path, stroke: Stroke) {} + pub fn stroke(&mut self, path: &Path, stroke: Stroke) {} } -- cgit From f34407bfdaf06c4bf204dc31b152be9451c243b8 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Feb 2020 07:08:49 +0100 Subject: Implement `Frame::fill` and `Frame::stroke` --- wgpu/src/widget/canvas/frame.rs | 76 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 74 insertions(+), 2 deletions(-) (limited to 'wgpu/src/widget/canvas/frame.rs') diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index e5daeedb..82ff526b 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -33,7 +33,79 @@ impl Frame { Point::new(self.width as f32 / 2.0, self.height as f32 / 2.0) } - pub fn fill(&mut self, path: &Path, fill: Fill) {} + pub fn fill(&mut self, path: &Path, fill: Fill) { + use lyon::tessellation::{ + BuffersBuilder, FillOptions, FillTessellator, + }; - pub fn stroke(&mut self, path: &Path, stroke: Stroke) {} + let mut buffers = BuffersBuilder::new( + &mut self.buffers, + FillVertex(match fill { + Fill::Color(color) => color.into_linear(), + }), + ); + + let mut tessellator = FillTessellator::new(); + + let _ = tessellator + .tessellate_path(path.raw(), &FillOptions::default(), &mut buffers) + .expect("Tessellate path"); + } + + pub fn stroke(&mut self, path: &Path, stroke: Stroke) { + use lyon::tessellation::{ + BuffersBuilder, StrokeOptions, StrokeTessellator, + }; + + let mut buffers = BuffersBuilder::new( + &mut self.buffers, + StrokeVertex(stroke.color.into_linear()), + ); + + let mut tessellator = StrokeTessellator::new(); + + let mut options = StrokeOptions::default(); + options.line_width = stroke.width; + options.start_cap = stroke.line_cap.into(); + options.end_cap = stroke.line_cap.into(); + options.line_join = stroke.line_join.into(); + + let _ = tessellator + .tessellate_path(path.raw(), &options, &mut buffers) + .expect("Stroke path"); + } +} + +struct FillVertex([f32; 4]); + +impl lyon::tessellation::FillVertexConstructor + for FillVertex +{ + fn new_vertex( + &mut self, + position: lyon::math::Point, + _attributes: lyon::tessellation::FillAttributes<'_>, + ) -> triangle::Vertex2D { + triangle::Vertex2D { + position: [position.x, position.y], + color: self.0, + } + } +} + +struct StrokeVertex([f32; 4]); + +impl lyon::tessellation::StrokeVertexConstructor + for StrokeVertex +{ + fn new_vertex( + &mut self, + position: lyon::math::Point, + _attributes: lyon::tessellation::StrokeAttributes<'_, '_>, + ) -> triangle::Vertex2D { + triangle::Vertex2D { + position: [position.x, position.y], + color: self.0, + } + } } -- cgit From 578ea4abb8a2dd0d53d7087322796bf9ad541b56 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Wed, 12 Feb 2020 08:49:42 +0100 Subject: Finish `clock` example --- wgpu/src/widget/canvas/frame.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) (limited to 'wgpu/src/widget/canvas/frame.rs') diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index 82ff526b..3c667426 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -7,13 +7,13 @@ use crate::{ #[derive(Debug)] pub struct Frame { - width: u32, - height: u32, + width: f32, + height: f32, buffers: lyon::tessellation::VertexBuffers, } impl Frame { - pub(crate) fn new(width: u32, height: u32) -> Frame { + pub fn new(width: f32, height: f32) -> Frame { Frame { width, height, @@ -21,16 +21,16 @@ impl Frame { } } - pub fn width(&self) -> u32 { + pub fn width(&self) -> f32 { self.width } - pub fn height(&self) -> u32 { + pub fn height(&self) -> f32 { self.height } pub fn center(&self) -> Point { - Point::new(self.width as f32 / 2.0, self.height as f32 / 2.0) + Point::new(self.width / 2.0, self.height / 2.0) } pub fn fill(&mut self, path: &Path, fill: Fill) { @@ -74,6 +74,13 @@ impl Frame { .tessellate_path(path.raw(), &options, &mut buffers) .expect("Stroke path"); } + + pub fn into_mesh(self) -> triangle::Mesh2D { + triangle::Mesh2D { + vertices: self.buffers.vertices, + indices: self.buffers.indices, + } + } } struct FillVertex([f32; 4]); -- cgit From 558abf648bdeb86d92e7092f4b023d5e55cc673c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 14 Feb 2020 04:59:31 +0100 Subject: Add transform stack to `canvas::Frame` --- wgpu/src/widget/canvas/frame.rs | 102 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 95 insertions(+), 7 deletions(-) (limited to 'wgpu/src/widget/canvas/frame.rs') diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index 3c667426..687f6c37 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -1,4 +1,4 @@ -use iced_native::Point; +use iced_native::{Point, Size, Vector}; use crate::{ canvas::{Fill, Path, Stroke}, @@ -10,6 +10,20 @@ pub struct Frame { width: f32, height: f32, buffers: lyon::tessellation::VertexBuffers, + + transforms: Transforms, +} + +#[derive(Debug)] +struct Transforms { + previous: Vec, + current: Transform, +} + +#[derive(Debug, Clone, Copy)] +struct Transform { + raw: lyon::math::Transform, + is_identity: bool, } impl Frame { @@ -18,17 +32,32 @@ impl Frame { width, height, buffers: lyon::tessellation::VertexBuffers::new(), + transforms: Transforms { + previous: Vec::new(), + current: Transform { + raw: lyon::math::Transform::identity(), + is_identity: true, + }, + }, } } + #[inline] pub fn width(&self) -> f32 { self.width } + #[inline] pub fn height(&self) -> f32 { self.height } + #[inline] + pub fn size(&self) -> Size { + Size::new(self.width, self.height) + } + + #[inline] pub fn center(&self) -> Point { Point::new(self.width / 2.0, self.height / 2.0) } @@ -47,9 +76,23 @@ impl Frame { let mut tessellator = FillTessellator::new(); - let _ = tessellator - .tessellate_path(path.raw(), &FillOptions::default(), &mut buffers) - .expect("Tessellate path"); + let result = if self.transforms.current.is_identity { + tessellator.tessellate_path( + path.raw(), + &FillOptions::default(), + &mut buffers, + ) + } else { + let path = path.transformed(&self.transforms.current.raw); + + tessellator.tessellate_path( + path.raw(), + &FillOptions::default(), + &mut buffers, + ) + }; + + let _ = result.expect("Tessellate path"); } pub fn stroke(&mut self, path: &Path, stroke: Stroke) { @@ -70,9 +113,54 @@ impl Frame { options.end_cap = stroke.line_cap.into(); options.line_join = stroke.line_join.into(); - let _ = tessellator - .tessellate_path(path.raw(), &options, &mut buffers) - .expect("Stroke path"); + let result = if self.transforms.current.is_identity { + tessellator.tessellate_path(path.raw(), &options, &mut buffers) + } else { + let path = path.transformed(&self.transforms.current.raw); + + tessellator.tessellate_path(path.raw(), &options, &mut buffers) + }; + + let _ = result.expect("Stroke path"); + } + + #[inline] + pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) { + self.transforms.previous.push(self.transforms.current); + + f(self); + + self.transforms.current = self.transforms.previous.pop().unwrap(); + } + + #[inline] + pub fn translate(&mut self, translation: Vector) { + self.transforms.current.raw = self + .transforms + .current + .raw + .pre_translate(lyon::math::Vector::new( + translation.x, + translation.y, + )); + self.transforms.current.is_identity = false; + } + + #[inline] + pub fn rotate(&mut self, angle: f32) { + self.transforms.current.raw = self + .transforms + .current + .raw + .pre_rotate(lyon::math::Angle::radians(-angle)); + self.transforms.current.is_identity = false; + } + + #[inline] + pub fn scale(&mut self, scale: f32) { + self.transforms.current.raw = + self.transforms.current.raw.pre_scale(scale, scale); + self.transforms.current.is_identity = false; } pub fn into_mesh(self) -> triangle::Mesh2D { -- cgit From f5c80a6d75d5022b175d3562f0965598b6398bd7 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Fri, 14 Feb 2020 05:42:19 +0100 Subject: Upgrade `Mesh2D` indices from `u16` to `u32` --- wgpu/src/widget/canvas/frame.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'wgpu/src/widget/canvas/frame.rs') diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index 687f6c37..27d676d6 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -9,7 +9,7 @@ use crate::{ pub struct Frame { width: f32, height: f32, - buffers: lyon::tessellation::VertexBuffers, + buffers: lyon::tessellation::VertexBuffers, transforms: Transforms, } -- cgit From 9c067562fa765cfc49d09cd9b12fbba96d5619fa Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Tue, 18 Feb 2020 08:48:54 +0100 Subject: Write documentation for new `canvas` module --- wgpu/src/widget/canvas/frame.rs | 51 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) (limited to 'wgpu/src/widget/canvas/frame.rs') diff --git a/wgpu/src/widget/canvas/frame.rs b/wgpu/src/widget/canvas/frame.rs index 27d676d6..fa6d8c0a 100644 --- a/wgpu/src/widget/canvas/frame.rs +++ b/wgpu/src/widget/canvas/frame.rs @@ -5,12 +5,14 @@ use crate::{ triangle, }; +/// The frame of a [`Canvas`]. +/// +/// [`Canvas`]: struct.Canvas.html #[derive(Debug)] pub struct Frame { width: f32, height: f32, buffers: lyon::tessellation::VertexBuffers, - transforms: Transforms, } @@ -27,6 +29,12 @@ struct Transform { } impl Frame { + /// Creates a new empty [`Frame`] with the given dimensions. + /// + /// The default coordinate system of a [`Frame`] has its origin at the + /// top-left corner of its bounds. + /// + /// [`Frame`]: struct.Frame.html pub fn new(width: f32, height: f32) -> Frame { Frame { width, @@ -42,26 +50,43 @@ impl Frame { } } + /// Returns the width of the [`Frame`]. + /// + /// [`Frame`]: struct.Frame.html #[inline] pub fn width(&self) -> f32 { self.width } + /// Returns the width of the [`Frame`]. + /// + /// [`Frame`]: struct.Frame.html #[inline] pub fn height(&self) -> f32 { self.height } + /// Returns the dimensions of the [`Frame`]. + /// + /// [`Frame`]: struct.Frame.html #[inline] pub fn size(&self) -> Size { Size::new(self.width, self.height) } + /// Returns the coordinate of the center of the [`Frame`]. + /// + /// [`Frame`]: struct.Frame.html #[inline] pub fn center(&self) -> Point { Point::new(self.width / 2.0, self.height / 2.0) } + /// Draws the given [`Path`] on the [`Frame`] by filling it with the + /// provided style. + /// + /// [`Path`]: path/struct.Path.html + /// [`Frame`]: struct.Frame.html pub fn fill(&mut self, path: &Path, fill: Fill) { use lyon::tessellation::{ BuffersBuilder, FillOptions, FillTessellator, @@ -95,6 +120,11 @@ impl Frame { let _ = result.expect("Tessellate path"); } + /// Draws the stroke of the given [`Path`] on the [`Frame`] with the + /// provided style. + /// + /// [`Path`]: path/struct.Path.html + /// [`Frame`]: struct.Frame.html pub fn stroke(&mut self, path: &Path, stroke: Stroke) { use lyon::tessellation::{ BuffersBuilder, StrokeOptions, StrokeTessellator, @@ -124,6 +154,13 @@ impl Frame { let _ = result.expect("Stroke path"); } + /// Stores the current transform of the [`Frame`] and executes the given + /// drawing operations, restoring the transform afterwards. + /// + /// This method is useful to compose transforms and perform drawing + /// operations in different coordinate systems. + /// + /// [`Frame`]: struct.Frame.html #[inline] pub fn with_save(&mut self, f: impl FnOnce(&mut Frame)) { self.transforms.previous.push(self.transforms.current); @@ -133,6 +170,9 @@ impl Frame { self.transforms.current = self.transforms.previous.pop().unwrap(); } + /// Applies a translation to the current transform of the [`Frame`]. + /// + /// [`Frame`]: struct.Frame.html #[inline] pub fn translate(&mut self, translation: Vector) { self.transforms.current.raw = self @@ -146,6 +186,9 @@ impl Frame { self.transforms.current.is_identity = false; } + /// Applies a rotation to the current transform of the [`Frame`]. + /// + /// [`Frame`]: struct.Frame.html #[inline] pub fn rotate(&mut self, angle: f32) { self.transforms.current.raw = self @@ -156,6 +199,9 @@ impl Frame { self.transforms.current.is_identity = false; } + /// Applies a scaling to the current transform of the [`Frame`]. + /// + /// [`Frame`]: struct.Frame.html #[inline] pub fn scale(&mut self, scale: f32) { self.transforms.current.raw = @@ -163,6 +209,9 @@ impl Frame { self.transforms.current.is_identity = false; } + /// Produces the geometry that has been drawn on the [`Frame`]. + /// + /// [`Frame`]: struct.Frame.html pub fn into_mesh(self) -> triangle::Mesh2D { triangle::Mesh2D { vertices: self.buffers.vertices, -- cgit