Reuse last buffer in Frame if mesh_style matches
This commit is contained in:
parent
d53e262425
commit
20a0577034
4 changed files with 53 additions and 42 deletions
|
|
@ -1,7 +1,7 @@
|
||||||
//! A collection of triangle primitives.
|
//! A collection of triangle primitives.
|
||||||
|
|
||||||
use crate::{Color, Point, Rectangle, triangle};
|
|
||||||
use crate::gradient::Gradient;
|
use crate::gradient::Gradient;
|
||||||
|
use crate::{triangle, Color, Point, Rectangle};
|
||||||
|
|
||||||
/// A mesh of triangles.
|
/// A mesh of triangles.
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
|
@ -19,16 +19,16 @@ pub struct Mesh<'a> {
|
||||||
pub style: &'a Style,
|
pub style: &'a Style,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
/// Supported shaders for primitives.
|
/// Supported shaders for primitives.
|
||||||
pub enum Style {
|
pub enum Style {
|
||||||
/// Fill a primitive with a solid color.
|
/// Fill a primitive with a solid color.
|
||||||
Solid(Color),
|
Solid(Color),
|
||||||
/// Fill a primitive with an interpolated color.
|
/// Fill a primitive with an interpolated color.
|
||||||
Gradient(Gradient)
|
Gradient(Gradient),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl <'a> Into<Style> for Gradient {
|
impl<'a> Into<Style> for Gradient {
|
||||||
fn into(self) -> Style {
|
fn into(self) -> Style {
|
||||||
match self {
|
match self {
|
||||||
Gradient::Linear(linear) => {
|
Gradient::Linear(linear) => {
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@
|
||||||
|
|
||||||
use crate::gradient::Gradient;
|
use crate::gradient::Gradient;
|
||||||
use crate::layer::mesh;
|
use crate::layer::mesh;
|
||||||
use iced_native::Color;
|
|
||||||
use crate::widget::canvas::frame::Transform;
|
use crate::widget::canvas::frame::Transform;
|
||||||
|
use iced_native::Color;
|
||||||
|
|
||||||
/// The style used to fill geometry.
|
/// The style used to fill geometry.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
@ -64,9 +64,7 @@ impl<'a> Style<'a> {
|
||||||
/// Converts a fill's [Style] to a [mesh::Style] for use in the renderer's shader.
|
/// Converts a fill's [Style] to a [mesh::Style] for use in the renderer's shader.
|
||||||
pub(crate) fn as_mesh_style(&self, transform: &Transform) -> mesh::Style {
|
pub(crate) fn as_mesh_style(&self, transform: &Transform) -> mesh::Style {
|
||||||
match self {
|
match self {
|
||||||
Style::Solid(color) => {
|
Style::Solid(color) => mesh::Style::Solid(*color),
|
||||||
mesh::Style::Solid(*color)
|
|
||||||
},
|
|
||||||
Style::Gradient(gradient) => mesh::Style::Gradient(
|
Style::Gradient(gradient) => mesh::Style::Gradient(
|
||||||
transform.transform_gradient((*gradient).clone()),
|
transform.transform_gradient((*gradient).clone()),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -18,13 +18,41 @@ use lyon::tessellation;
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
pub struct Frame {
|
pub struct Frame {
|
||||||
size: Size,
|
size: Size,
|
||||||
buffers: Vec<(tessellation::VertexBuffers<Vertex2D, u32>, mesh::Style)>,
|
buffers: BufferStack,
|
||||||
primitives: Vec<Primitive>,
|
primitives: Vec<Primitive>,
|
||||||
transforms: Transforms,
|
transforms: Transforms,
|
||||||
fill_tessellator: tessellation::FillTessellator,
|
fill_tessellator: tessellation::FillTessellator,
|
||||||
stroke_tessellator: tessellation::StrokeTessellator,
|
stroke_tessellator: tessellation::StrokeTessellator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct BufferStack {
|
||||||
|
stack: Vec<(tessellation::VertexBuffers<Vertex2D, u32>, mesh::Style)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BufferStack {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self { stack: Vec::new() }
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get(
|
||||||
|
&mut self,
|
||||||
|
mesh_style: mesh::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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
tessellation::BuffersBuilder::new(
|
||||||
|
&mut self.stack.last_mut().unwrap().0,
|
||||||
|
Vertex2DBuilder,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct Transforms {
|
struct Transforms {
|
||||||
previous: Vec<Transform>,
|
previous: Vec<Transform>,
|
||||||
|
|
@ -67,7 +95,7 @@ impl Frame {
|
||||||
pub fn new(size: Size) -> Frame {
|
pub fn new(size: Size) -> Frame {
|
||||||
Frame {
|
Frame {
|
||||||
size,
|
size,
|
||||||
buffers: Vec::new(),
|
buffers: BufferStack::new(),
|
||||||
primitives: Vec::new(),
|
primitives: Vec::new(),
|
||||||
transforms: Transforms {
|
transforms: Transforms {
|
||||||
previous: Vec::new(),
|
previous: Vec::new(),
|
||||||
|
|
@ -110,10 +138,9 @@ impl Frame {
|
||||||
pub fn fill<'a>(&mut self, path: &Path, fill: impl Into<Fill<'a>>) {
|
pub fn fill<'a>(&mut self, path: &Path, fill: impl Into<Fill<'a>>) {
|
||||||
let Fill { style, rule } = fill.into();
|
let Fill { style, rule } = fill.into();
|
||||||
|
|
||||||
let mut buf = tessellation::VertexBuffers::new();
|
let mut buffer = self
|
||||||
|
.buffers
|
||||||
let mut buffers =
|
.get(style.as_mesh_style(&self.transforms.current));
|
||||||
tessellation::BuffersBuilder::new(&mut buf, Vertex2DBuilder);
|
|
||||||
|
|
||||||
let options =
|
let options =
|
||||||
tessellation::FillOptions::default().with_fill_rule(rule.into());
|
tessellation::FillOptions::default().with_fill_rule(rule.into());
|
||||||
|
|
@ -122,7 +149,7 @@ impl Frame {
|
||||||
self.fill_tessellator.tessellate_path(
|
self.fill_tessellator.tessellate_path(
|
||||||
path.raw(),
|
path.raw(),
|
||||||
&options,
|
&options,
|
||||||
&mut buffers,
|
&mut buffer,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let path = path.transformed(&self.transforms.current.raw);
|
let path = path.transformed(&self.transforms.current.raw);
|
||||||
|
|
@ -130,13 +157,10 @@ impl Frame {
|
||||||
self.fill_tessellator.tessellate_path(
|
self.fill_tessellator.tessellate_path(
|
||||||
path.raw(),
|
path.raw(),
|
||||||
&options,
|
&options,
|
||||||
&mut buffers,
|
&mut buffer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.expect("Tessellate path.");
|
.expect("Tessellate path.");
|
||||||
|
|
||||||
self.buffers
|
|
||||||
.push((buf, style.as_mesh_style(&self.transforms.current)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws an axis-aligned rectangle given its top-left corner coordinate and
|
/// Draws an axis-aligned rectangle given its top-left corner coordinate and
|
||||||
|
|
@ -149,10 +173,9 @@ impl Frame {
|
||||||
) {
|
) {
|
||||||
let Fill { style, rule } = fill.into();
|
let Fill { style, rule } = fill.into();
|
||||||
|
|
||||||
let mut buf = tessellation::VertexBuffers::new();
|
let mut buffer = self
|
||||||
|
.buffers
|
||||||
let mut buffers =
|
.get(style.as_mesh_style(&self.transforms.current));
|
||||||
tessellation::BuffersBuilder::new(&mut buf, Vertex2DBuilder);
|
|
||||||
|
|
||||||
let top_left =
|
let top_left =
|
||||||
self.transforms.current.raw.transform_point(
|
self.transforms.current.raw.transform_point(
|
||||||
|
|
@ -171,12 +194,9 @@ impl Frame {
|
||||||
.tessellate_rectangle(
|
.tessellate_rectangle(
|
||||||
&lyon::math::Box2D::new(top_left, top_left + size),
|
&lyon::math::Box2D::new(top_left, top_left + size),
|
||||||
&options,
|
&options,
|
||||||
&mut buffers,
|
&mut buffer,
|
||||||
)
|
)
|
||||||
.expect("Fill rectangle");
|
.expect("Fill rectangle");
|
||||||
|
|
||||||
self.buffers
|
|
||||||
.push((buf, style.as_mesh_style(&self.transforms.current)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the stroke of the given [`Path`] on the [`Frame`] with the
|
/// Draws the stroke of the given [`Path`] on the [`Frame`] with the
|
||||||
|
|
@ -184,10 +204,9 @@ impl Frame {
|
||||||
pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
|
pub fn stroke<'a>(&mut self, path: &Path, stroke: impl Into<Stroke<'a>>) {
|
||||||
let stroke = stroke.into();
|
let stroke = stroke.into();
|
||||||
|
|
||||||
let mut buf = tessellation::VertexBuffers::new();
|
let mut buffer = self
|
||||||
|
.buffers
|
||||||
let mut buffers =
|
.get(stroke.style.as_mesh_style(&self.transforms.current));
|
||||||
tessellation::BuffersBuilder::new(&mut buf, Vertex2DBuilder);
|
|
||||||
|
|
||||||
let mut options = tessellation::StrokeOptions::default();
|
let mut options = tessellation::StrokeOptions::default();
|
||||||
options.line_width = stroke.width;
|
options.line_width = stroke.width;
|
||||||
|
|
@ -205,7 +224,7 @@ impl Frame {
|
||||||
self.stroke_tessellator.tessellate_path(
|
self.stroke_tessellator.tessellate_path(
|
||||||
path.raw(),
|
path.raw(),
|
||||||
&options,
|
&options,
|
||||||
&mut buffers,
|
&mut buffer,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let path = path.transformed(&self.transforms.current.raw);
|
let path = path.transformed(&self.transforms.current.raw);
|
||||||
|
|
@ -213,13 +232,10 @@ impl Frame {
|
||||||
self.stroke_tessellator.tessellate_path(
|
self.stroke_tessellator.tessellate_path(
|
||||||
path.raw(),
|
path.raw(),
|
||||||
&options,
|
&options,
|
||||||
&mut buffers,
|
&mut buffer,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
.expect("Stroke path");
|
.expect("Stroke path");
|
||||||
|
|
||||||
self.buffers
|
|
||||||
.push((buf, stroke.style.as_mesh_style(&self.transforms.current)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws the characters of the given [`Text`] on the [`Frame`], filling
|
/// Draws the characters of the given [`Text`] on the [`Frame`], filling
|
||||||
|
|
@ -361,7 +377,7 @@ impl Frame {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_primitives(mut self) -> Vec<Primitive> {
|
fn into_primitives(mut self) -> Vec<Primitive> {
|
||||||
for (buffer, style) in self.buffers {
|
for (buffer, style) in self.buffers.stack {
|
||||||
if !buffer.indices.is_empty() {
|
if !buffer.indices.is_empty() {
|
||||||
self.primitives.push(Primitive::Mesh2D {
|
self.primitives.push(Primitive::Mesh2D {
|
||||||
buffers: triangle::Mesh2D {
|
buffers: triangle::Mesh2D {
|
||||||
|
|
|
||||||
|
|
@ -54,11 +54,8 @@ impl Pipeline {
|
||||||
}],
|
}],
|
||||||
});
|
});
|
||||||
|
|
||||||
let bind_group = Pipeline::bind_group(
|
let bind_group =
|
||||||
device,
|
Pipeline::bind_group(device, &buffer.raw(), &bind_group_layout);
|
||||||
&buffer.raw(),
|
|
||||||
&bind_group_layout,
|
|
||||||
);
|
|
||||||
|
|
||||||
let layout =
|
let layout =
|
||||||
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue