Clip and cull Mesh2D primitives in iced_wgpu

This commit is contained in:
Héctor Ramón Jiménez 2020-04-28 04:41:09 +02:00
parent 69c60d372c
commit e65585ae17
5 changed files with 45 additions and 25 deletions

View File

@ -88,6 +88,7 @@ mod rainbow {
Primitive::Translate {
translation: Vector::new(b.x, b.y),
content: Box::new(Primitive::Mesh2D {
size: b.size(),
buffers: Mesh2D {
vertices: vec![
Vertex2D {

View File

@ -1,5 +1,5 @@
use iced_native::{
image, svg, Background, Color, Font, HorizontalAlignment, Rectangle,
image, svg, Background, Color, Font, HorizontalAlignment, Rectangle, Size,
Vector, VerticalAlignment,
};
@ -72,7 +72,7 @@ pub enum Primitive {
},
/// A primitive that applies a translation
Translate {
/// The top-left coordinate of the mesh
/// The translation vector
translation: Vector,
/// The primitive to translate
@ -82,6 +82,11 @@ pub enum Primitive {
///
/// It can be used to render many kinds of geometry freely.
Mesh2D {
/// The size of the drawable region of the mesh.
///
/// Any geometry that falls out of this region will be clipped.
size: Size,
/// The vertex and index buffers of the mesh
buffers: triangle::Mesh2D,
},

View File

@ -29,7 +29,7 @@ pub struct Renderer {
struct Layer<'a> {
bounds: Rectangle<u32>,
quads: Vec<Quad>,
meshes: Vec<(Vector, &'a triangle::Mesh2D)>,
meshes: Vec<(Vector, Rectangle<u32>, &'a triangle::Mesh2D)>,
text: Vec<wgpu_glyph::Section<'a>>,
#[cfg(any(feature = "image", feature = "svg"))]
@ -48,6 +48,12 @@ impl<'a> Layer<'a> {
images: Vec::new(),
}
}
pub fn intersection(&self, rectangle: Rectangle) -> Option<Rectangle<u32>> {
let layer_bounds: Rectangle<f32> = self.bounds.into();
layer_bounds.intersection(&rectangle).map(Into::into)
}
}
impl Renderer {
@ -214,10 +220,20 @@ impl Renderer {
border_color: border_color.into_linear(),
});
}
Primitive::Mesh2D { buffers } => {
Primitive::Mesh2D { size, buffers } => {
let layer = layers.last_mut().unwrap();
layer.meshes.push((translation, buffers));
// Only draw visible content
if let Some(clip_bounds) = layer.intersection(Rectangle::new(
Point::new(translation.x, translation.y),
*size,
)) {
layer.meshes.push((
translation,
clip_bounds.into(),
buffers,
));
}
}
Primitive::Clip {
bounds,
@ -226,16 +242,10 @@ impl Renderer {
} => {
let layer = layers.last_mut().unwrap();
let layer_bounds: Rectangle<f32> = layer.bounds.into();
let clip = Rectangle {
x: bounds.x + translation.x,
y: bounds.y + translation.y,
..*bounds
};
// Only draw visible content
if let Some(clip_bounds) = layer_bounds.intersection(&clip) {
if let Some(clip_bounds) =
layer.intersection(*bounds + translation)
{
let clip_layer = Layer::new(clip_bounds.into());
let new_layer = Layer::new(layer.bounds);
@ -356,8 +366,8 @@ impl Renderer {
target_width,
target_height,
scaled,
scale_factor,
&layer.meshes,
bounds,
);
}

View File

@ -201,15 +201,15 @@ impl Pipeline {
target_width: u32,
target_height: u32,
transformation: Transformation,
meshes: &[(Vector, &Mesh2D)],
bounds: Rectangle<u32>,
scale_factor: f32,
meshes: &[(Vector, Rectangle<u32>, &Mesh2D)],
) {
// This looks a bit crazy, but we are just counting how many vertices
// and indices we will need to handle.
// TODO: Improve readability
let (total_vertices, total_indices) = meshes
.iter()
.map(|(_, mesh)| (mesh.vertices.len(), mesh.indices.len()))
.map(|(_, _, mesh)| (mesh.vertices.len(), mesh.indices.len()))
.fold((0, 0), |(total_v, total_i), (v, i)| {
(total_v + v, total_i + i)
});
@ -230,7 +230,7 @@ impl Pipeline {
let mut last_index = 0;
// We upload everything upfront
for (origin, mesh) in meshes {
for (origin, _, mesh) in meshes {
let transform = (transformation
* Transformation::translate(origin.x, origin.y))
.into();
@ -316,16 +316,19 @@ impl Pipeline {
});
render_pass.set_pipeline(&self.pipeline);
render_pass.set_scissor_rect(
bounds.x,
bounds.y,
bounds.width,
bounds.height,
);
for (i, (vertex_offset, index_offset, indices)) in
offsets.into_iter().enumerate()
{
let bounds = meshes[i].1 * scale_factor;
render_pass.set_scissor_rect(
bounds.x,
bounds.y,
bounds.width,
bounds.height,
);
render_pass.set_bind_group(
0,
&self.constants,

View File

@ -267,6 +267,7 @@ impl Frame {
pub fn into_geometry(mut self) -> Geometry {
if !self.buffers.indices.is_empty() {
self.primitives.push(Primitive::Mesh2D {
size: self.size,
buffers: triangle::Mesh2D {
vertices: self.buffers.vertices,
indices: self.buffers.indices,