diff options
author | 2022-11-14 00:02:42 +0100 | |
---|---|---|
committer | 2022-11-16 09:24:16 +0100 | |
commit | 33c3c0c0aa774bb7462e3c42aa04c591a66376a7 (patch) | |
tree | 08ea046e6ac8a9ad43a7ef1f56256a056a4a4d6c /graphics/src | |
parent | 5b0dfcd0b0a9f25a3004dbc2cad3dea8220a76a1 (diff) | |
download | iced-33c3c0c0aa774bb7462e3c42aa04c591a66376a7.tar.gz iced-33c3c0c0aa774bb7462e3c42aa04c591a66376a7.tar.bz2 iced-33c3c0c0aa774bb7462e3c42aa04c591a66376a7.zip |
Group all solid triangles independently of color
Diffstat (limited to '')
-rw-r--r-- | graphics/src/layer.rs | 25 | ||||
-rw-r--r-- | graphics/src/layer/mesh.rs | 94 | ||||
-rw-r--r-- | graphics/src/primitive.rs | 25 | ||||
-rw-r--r-- | graphics/src/triangle.rs | 37 | ||||
-rw-r--r-- | graphics/src/widget/canvas.rs | 2 | ||||
-rw-r--r-- | graphics/src/widget/canvas/fill.rs | 2 | ||||
-rw-r--r-- | graphics/src/widget/canvas/frame.rs | 196 | ||||
-rw-r--r-- | graphics/src/widget/canvas/stroke.rs | 2 | ||||
-rw-r--r-- | graphics/src/widget/canvas/style.rs | 11 |
9 files changed, 294 insertions, 100 deletions
diff --git a/graphics/src/layer.rs b/graphics/src/layer.rs index e95934b0..fd670f48 100644 --- a/graphics/src/layer.rs +++ b/graphics/src/layer.rs @@ -166,10 +166,27 @@ impl<'a> Layer<'a> { border_color: border_color.into_linear(), }); } - Primitive::Mesh2D { + 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, - style, + gradient, } => { let layer = &mut layers[current_layer]; @@ -180,11 +197,11 @@ impl<'a> Layer<'a> { // Only draw visible content if let Some(clip_bounds) = layer.bounds.intersection(&bounds) { - layer.meshes.push(Mesh { + layer.meshes.push(Mesh::Gradient { origin: Point::new(translation.x, translation.y), buffers, clip_bounds, - style, + gradient, }); } } diff --git a/graphics/src/layer/mesh.rs b/graphics/src/layer/mesh.rs index 979081f1..7661c5c9 100644 --- a/graphics/src/layer/mesh.rs +++ b/graphics/src/layer/mesh.rs @@ -1,31 +1,93 @@ //! A collection of triangle primitives. use crate::triangle; -use crate::{Point, Rectangle}; +use crate::{Gradient, Point, Rectangle}; /// A mesh of triangles. #[derive(Debug, Clone, Copy)] -pub struct Mesh<'a> { - /// The origin of the vertices of the [`Mesh`]. - pub origin: Point, +pub enum Mesh<'a> { + /// A mesh of triangles with a solid color. + Solid { + /// The origin of the vertices of the [`Mesh`]. + origin: Point, - /// The vertex and index buffers of the [`Mesh`]. - pub buffers: &'a triangle::Mesh2D, + /// The vertex and index buffers of the [`Mesh`]. + buffers: &'a triangle::Mesh2D<triangle::ColoredVertex2D>, - /// The clipping bounds of the [`Mesh`]. - pub clip_bounds: Rectangle<f32>, + /// The clipping bounds of the [`Mesh`]. + clip_bounds: Rectangle<f32>, + }, + /// A mesh of triangles with a gradient color. + Gradient { + /// The origin of the vertices of the [`Mesh`]. + origin: Point, - /// The shader of the [`Mesh`]. - pub style: &'a triangle::Style, + /// The vertex and index buffers of the [`Mesh`]. + buffers: &'a triangle::Mesh2D<triangle::Vertex2D>, + + /// The clipping bounds of the [`Mesh`]. + clip_bounds: Rectangle<f32>, + + /// The gradient to apply to the [`Mesh`]. + gradient: &'a Gradient, + }, +} + +impl Mesh<'_> { + /// Returns the origin of the [`Mesh`]. + pub fn origin(&self) -> Point { + match self { + Self::Solid { origin, .. } | Self::Gradient { origin, .. } => { + *origin + } + } + } + + /// Returns the indices of the [`Mesh`]. + pub fn indices(&self) -> &[u32] { + match self { + Self::Solid { buffers, .. } => &buffers.indices, + Self::Gradient { buffers, .. } => &buffers.indices, + } + } + + /// Returns the clip bounds of the [`Mesh`]. + pub fn clip_bounds(&self) -> Rectangle<f32> { + match self { + Self::Solid { clip_bounds, .. } + | Self::Gradient { clip_bounds, .. } => *clip_bounds, + } + } +} + +/// The result of counting the attributes of a set of meshes. +#[derive(Debug, Clone, Copy, Default)] +pub struct AttributeCount { + /// The total amount of solid vertices. + pub solid_vertices: usize, + + /// The total amount of gradient vertices. + pub gradient_vertices: usize, + + /// The total amount of indices. + pub indices: usize, } /// Returns the number of total vertices & total indices of all [`Mesh`]es. -pub fn attribute_count_of<'a>(meshes: &'a [Mesh<'a>]) -> (usize, usize) { +pub fn attribute_count_of<'a>(meshes: &'a [Mesh<'a>]) -> AttributeCount { meshes .iter() - .map(|Mesh { buffers, .. }| { - (buffers.vertices.len(), buffers.indices.len()) - }) - .fold((0, 0), |(total_v, total_i), (v, i)| { - (total_v + v, total_i + i) + .fold(AttributeCount::default(), |mut count, mesh| { + match mesh { + Mesh::Solid { buffers, .. } => { + count.solid_vertices += buffers.vertices.len(); + count.indices += buffers.indices.len(); + } + Mesh::Gradient { buffers, .. } => { + count.gradient_vertices += buffers.vertices.len(); + count.indices += buffers.indices.len(); + } + } + + count }) } diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index b481ac0b..9759d97a 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -3,6 +3,7 @@ use iced_native::svg; use iced_native::{Background, Color, Font, Rectangle, Size, Vector}; use crate::alignment; +use crate::gradient::Gradient; use crate::triangle; use std::sync::Arc; @@ -77,20 +78,32 @@ pub enum Primitive { /// The primitive to translate content: Box<Primitive>, }, - /// A low-level primitive to render a mesh of triangles. + /// A low-level primitive to render a mesh of triangles with a solid color. /// /// It can be used to render many kinds of geometry freely. - Mesh2D { - /// The vertex and index buffers of the mesh - buffers: triangle::Mesh2D, + SolidMesh { + /// The vertices and indices of the mesh. + buffers: triangle::Mesh2D<triangle::ColoredVertex2D>, + + /// The size of the drawable region of the mesh. + /// + /// Any geometry that falls out of this region will be clipped. + size: Size, + }, + /// A low-level primitive to render a mesh of triangles with a gradient. + /// + /// It can be used to render many kinds of geometry freely. + GradientMesh { + /// The vertices and indices of the mesh. + buffers: triangle::Mesh2D<triangle::Vertex2D>, /// The size of the drawable region of the mesh. /// /// Any geometry that falls out of this region will be clipped. size: Size, - /// The shader of the mesh - style: triangle::Style, + /// The [`Gradient`] to apply to the mesh. + gradient: Gradient, }, /// A cached primitive. /// diff --git a/graphics/src/triangle.rs b/graphics/src/triangle.rs index 8b41bfc4..f52b2339 100644 --- a/graphics/src/triangle.rs +++ b/graphics/src/triangle.rs @@ -1,15 +1,12 @@ //! Draw geometry using meshes of triangles. -use crate::Color; -#[cfg(not(target_arch = "wasm32"))] -use crate::Gradient; - use bytemuck::{Pod, Zeroable}; /// A set of [`Vertex2D`] and indices representing a list of triangles. #[derive(Clone, Debug)] -pub struct Mesh2D { +pub struct Mesh2D<T> { /// The vertices of the mesh - pub vertices: Vec<Vertex2D>, + pub vertices: Vec<T>, + /// The list of vertex indices that defines the triangles of the mesh. /// /// Therefore, this list should always have a length that is a multiple of 3. @@ -24,25 +21,13 @@ pub struct Vertex2D { pub position: [f32; 2], } -#[derive(Debug, Clone, PartialEq)] -/// Supported shaders for triangle primitives. -pub enum Style { - /// Fill a primitive with a solid color. - Solid(Color), - #[cfg(not(target_arch = "wasm32"))] - /// Fill a primitive with an interpolated color. - Gradient(Gradient), -} - -impl From<Color> for Style { - fn from(color: Color) -> Self { - Self::Solid(color) - } -} +/// A two-dimensional vertex with a color. +#[derive(Copy, Clone, Debug, Zeroable, Pod)] +#[repr(C)] +pub struct ColoredVertex2D { + /// The vertex position in 2D space. + pub position: [f32; 2], -#[cfg(not(target_arch = "wasm32"))] -impl From<Gradient> for Style { - fn from(gradient: Gradient) -> Self { - Self::Gradient(gradient) - } + /// The color of the vertex in __linear__ RGBA. + pub color: [f32; 4], } diff --git a/graphics/src/widget/canvas.rs b/graphics/src/widget/canvas.rs index a14940d9..b070d0a6 100644 --- a/graphics/src/widget/canvas.rs +++ b/graphics/src/widget/canvas.rs @@ -13,6 +13,7 @@ mod cursor; mod frame; mod geometry; mod program; +mod style; mod text; pub use crate::gradient::{self, Gradient}; @@ -25,6 +26,7 @@ pub use geometry::Geometry; pub use path::Path; pub use program::Program; pub use stroke::{LineCap, LineDash, LineJoin, Stroke}; +pub use style::Style; pub use text::Text; use crate::{Backend, Primitive, Renderer}; diff --git a/graphics/src/widget/canvas/fill.rs b/graphics/src/widget/canvas/fill.rs index e2fc1cfe..e954ebb5 100644 --- a/graphics/src/widget/canvas/fill.rs +++ b/graphics/src/widget/canvas/fill.rs @@ -1,7 +1,7 @@ //! Fill [crate::widget::canvas::Geometry] with a certain style. use crate::{Color, Gradient}; -pub use crate::triangle::Style; +pub use crate::widget::canvas::Style; /// The style used to fill geometry. #[derive(Debug, Clone)] diff --git a/graphics/src/widget/canvas/frame.rs b/graphics/src/widget/canvas/frame.rs index a7b88502..d68548ae 100644 --- a/graphics/src/widget/canvas/frame.rs +++ b/graphics/src/widget/canvas/frame.rs @@ -1,7 +1,6 @@ use crate::gradient::Gradient; use crate::triangle; -use crate::triangle::Vertex2D; -use crate::widget::canvas::{path, Fill, Geometry, Path, Stroke, Text}; +use crate::widget::canvas::{path, Fill, Geometry, Path, Stroke, Style, Text}; use crate::Primitive; use iced_native::{Point, Rectangle, Size, Vector}; @@ -23,8 +22,16 @@ pub struct Frame { stroke_tessellator: tessellation::StrokeTessellator, } +enum Buffer { + Solid(tessellation::VertexBuffers<triangle::ColoredVertex2D, u32>), + Gradient( + tessellation::VertexBuffers<triangle::Vertex2D, u32>, + Gradient, + ), +} + struct BufferStack { - stack: Vec<(tessellation::VertexBuffers<Vertex2D, u32>, triangle::Style)>, + stack: Vec<Buffer>, } impl BufferStack { @@ -32,22 +39,64 @@ impl BufferStack { Self { stack: Vec::new() } } - fn get( - &mut self, - mesh_style: triangle::Style, - ) -> tessellation::BuffersBuilder<'_, Vertex2D, u32, Vertex2DBuilder> { - match self.stack.last_mut() { - Some((_, current_style)) if current_style == &mesh_style => {} - _ => { - self.stack - .push((tessellation::VertexBuffers::new(), mesh_style)); + fn get_mut(&mut self, style: &Style) -> &mut Buffer { + match style { + Style::Solid(_) => match self.stack.last() { + Some(Buffer::Solid(_)) => {} + _ => { + self.stack.push(Buffer::Solid( + tessellation::VertexBuffers::new(), + )); + } + }, + Style::Gradient(gradient) => match self.stack.last() { + Some(Buffer::Gradient(_, last)) if gradient == last => {} + _ => { + self.stack.push(Buffer::Gradient( + tessellation::VertexBuffers::new(), + gradient.clone(), + )); + } + }, + } + + self.stack.last_mut().unwrap() + } + + fn get_fill<'a>( + &'a mut self, + style: &Style, + ) -> Box<dyn tessellation::FillGeometryBuilder + 'a> { + match (style, self.get_mut(style)) { + (Style::Solid(color), Buffer::Solid(buffer)) => { + Box::new(tessellation::BuffersBuilder::new( + buffer, + TriangleVertex2DBuilder(color.into_linear()), + )) } - }; + (Style::Gradient(_), Buffer::Gradient(buffer, _)) => Box::new( + tessellation::BuffersBuilder::new(buffer, Vertex2DBuilder), + ), + _ => unreachable!(), + } + } - tessellation::BuffersBuilder::new( - &mut self.stack.last_mut().unwrap().0, - Vertex2DBuilder, - ) + fn get_stroke<'a>( + &'a mut self, + style: &Style, + ) -> Box<dyn tessellation::StrokeGeometryBuilder + 'a> { + match (style, self.get_mut(style)) { + (Style::Solid(color), Buffer::Solid(buffer)) => { + Box::new(tessellation::BuffersBuilder::new( + buffer, + TriangleVertex2DBuilder(color.into_linear()), + )) + } + (Style::Gradient(_), Buffer::Gradient(buffer, _)) => Box::new( + tessellation::BuffersBuilder::new(buffer, Vertex2DBuilder), + ), + _ => unreachable!(), + } } } @@ -73,12 +122,11 @@ impl Transform { point.y = transformed.y; } - fn transform_style(&self, style: triangle::Style) -> triangle::Style { + fn transform_style(&self, style: Style) -> Style { match style { - triangle::Style::Solid(color) => triangle::Style::Solid(color), - #[cfg(not(target_arch = "wasm32"))] - triangle::Style::Gradient(gradient) => { - triangle::Style::Gradient(self.transform_gradient(gradient)) + Style::Solid(color) => Style::Solid(color), + Style::Gradient(gradient) => { + Style::Gradient(self.transform_gradient(gradient)) } } } @@ -146,7 +194,7 @@ impl Frame { let mut buffer = self .buffers - .get(self.transforms.current.transform_style(style)); + .get_fill(&self.transforms.current.transform_style(style)); let options = tessellation::FillOptions::default().with_fill_rule(rule.into()); @@ -155,7 +203,7 @@ impl Frame { self.fill_tessellator.tessellate_path( path.raw(), &options, - &mut buffer, + buffer.as_mut(), ) } else { let path = path.transformed(&self.transforms.current.raw); @@ -163,7 +211,7 @@ impl Frame { self.fill_tessellator.tessellate_path( path.raw(), &options, - &mut buffer, + buffer.as_mut(), ) } .expect("Tessellate path."); @@ -181,7 +229,7 @@ impl Frame { let mut buffer = self .buffers - .get(self.transforms.current.transform_style(style)); + .get_fill(&self.transforms.current.transform_style(style)); let top_left = self.transforms.current.raw.transform_point( @@ -200,7 +248,7 @@ impl Frame { .tessellate_rectangle( &lyon::math::Box2D::new(top_left, top_left + size), &options, - &mut buffer, + buffer.as_mut(), ) .expect("Fill rectangle"); } @@ -212,7 +260,7 @@ impl Frame { let mut buffer = self .buffers - .get(self.transforms.current.transform_style(stroke.style)); + .get_stroke(&self.transforms.current.transform_style(stroke.style)); let mut options = tessellation::StrokeOptions::default(); options.line_width = stroke.width; @@ -230,7 +278,7 @@ impl Frame { self.stroke_tessellator.tessellate_path( path.raw(), &options, - &mut buffer, + buffer.as_mut(), ) } else { let path = path.transformed(&self.transforms.current.raw); @@ -238,7 +286,7 @@ impl Frame { self.stroke_tessellator.tessellate_path( path.raw(), &options, - &mut buffer, + buffer.as_mut(), ) } .expect("Stroke path"); @@ -383,16 +431,31 @@ impl Frame { } fn into_primitives(mut self) -> Vec<Primitive> { - for (buffer, style) in self.buffers.stack { - if !buffer.indices.is_empty() { - self.primitives.push(Primitive::Mesh2D { - buffers: triangle::Mesh2D { - vertices: buffer.vertices, - indices: buffer.indices, - }, - size: self.size, - style, - }) + for buffer in self.buffers.stack { + match buffer { + Buffer::Solid(buffer) => { + if !buffer.indices.is_empty() { + self.primitives.push(Primitive::SolidMesh { + buffers: triangle::Mesh2D { + vertices: buffer.vertices, + indices: buffer.indices, + }, + size: self.size, + }) + } + } + Buffer::Gradient(buffer, gradient) => { + if !buffer.indices.is_empty() { + self.primitives.push(Primitive::GradientMesh { + buffers: triangle::Mesh2D { + vertices: buffer.vertices, + indices: buffer.indices, + }, + size: self.size, + gradient, + }) + } + } } } @@ -402,25 +465,66 @@ impl Frame { struct Vertex2DBuilder; -impl tessellation::FillVertexConstructor<Vertex2D> for Vertex2DBuilder { - fn new_vertex(&mut self, vertex: tessellation::FillVertex<'_>) -> Vertex2D { +impl tessellation::FillVertexConstructor<triangle::Vertex2D> + for Vertex2DBuilder +{ + fn new_vertex( + &mut self, + vertex: tessellation::FillVertex<'_>, + ) -> triangle::Vertex2D { + let position = vertex.position(); + + triangle::Vertex2D { + position: [position.x, position.y], + } + } +} + +impl tessellation::StrokeVertexConstructor<triangle::Vertex2D> + for Vertex2DBuilder +{ + fn new_vertex( + &mut self, + vertex: tessellation::StrokeVertex<'_, '_>, + ) -> triangle::Vertex2D { + let position = vertex.position(); + + triangle::Vertex2D { + position: [position.x, position.y], + } + } +} + +struct TriangleVertex2DBuilder([f32; 4]); + +impl tessellation::FillVertexConstructor<triangle::ColoredVertex2D> + for TriangleVertex2DBuilder +{ + fn new_vertex( + &mut self, + vertex: tessellation::FillVertex<'_>, + ) -> triangle::ColoredVertex2D { let position = vertex.position(); - Vertex2D { + triangle::ColoredVertex2D { position: [position.x, position.y], + color: self.0, } } } -impl tessellation::StrokeVertexConstructor<Vertex2D> for Vertex2DBuilder { +impl tessellation::StrokeVertexConstructor<triangle::ColoredVertex2D> + for TriangleVertex2DBuilder +{ fn new_vertex( &mut self, vertex: tessellation::StrokeVertex<'_, '_>, - ) -> Vertex2D { + ) -> triangle::ColoredVertex2D { let position = vertex.position(); - Vertex2D { + triangle::ColoredVertex2D { position: [position.x, position.y], + color: self.0, } } } diff --git a/graphics/src/widget/canvas/stroke.rs b/graphics/src/widget/canvas/stroke.rs index a882531a..4c19251d 100644 --- a/graphics/src/widget/canvas/stroke.rs +++ b/graphics/src/widget/canvas/stroke.rs @@ -1,5 +1,5 @@ //! Create lines from a [crate::widget::canvas::Path] and assigns them various attributes/styles. -pub use crate::triangle::Style; +pub use crate::widget::canvas::Style; use iced_native::Color; diff --git a/graphics/src/widget/canvas/style.rs b/graphics/src/widget/canvas/style.rs new file mode 100644 index 00000000..794109bd --- /dev/null +++ b/graphics/src/widget/canvas/style.rs @@ -0,0 +1,11 @@ +use crate::{Color, Gradient}; + +/// The coloring style of some drawing. +#[derive(Debug, Clone, PartialEq)] +pub enum Style { + /// A solid [`Color`]. + Solid(Color), + + /// A [`Gradient`] color. + Gradient(Gradient), +} |