summaryrefslogtreecommitdiffstats
path: root/wgpu/src/geometry.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-04-03 21:07:54 +0200
committerLibravatar Héctor Ramón Jiménez <hector@hecrj.dev>2024-04-03 21:07:54 +0200
commitb05e61f5c8ae61c9f3c7cc08cded53901ebbccfd (patch)
tree3d35a011d94d4936f09b5a9be4031358a09c60da /wgpu/src/geometry.rs
parent99a904112ca111f2ab0e60e30b6c369741b1653b (diff)
downloadiced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.gz
iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.tar.bz2
iced-b05e61f5c8ae61c9f3c7cc08cded53901ebbccfd.zip
Redesign `iced_wgpu` layering architecture
Diffstat (limited to 'wgpu/src/geometry.rs')
-rw-r--r--wgpu/src/geometry.rs175
1 files changed, 105 insertions, 70 deletions
diff --git a/wgpu/src/geometry.rs b/wgpu/src/geometry.rs
index ba56c59d..7c8c0a35 100644
--- a/wgpu/src/geometry.rs
+++ b/wgpu/src/geometry.rs
@@ -10,31 +10,82 @@ use crate::graphics::geometry::{
};
use crate::graphics::gradient::{self, Gradient};
use crate::graphics::mesh::{self, Mesh};
-use crate::primitive::{self, Primitive};
+use crate::graphics::{self, Cached};
+use crate::layer;
+use crate::text;
use lyon::geom::euclid;
use lyon::tessellation;
use std::borrow::Cow;
+use std::cell::RefCell;
+use std::rc::Rc;
/// A frame for drawing some geometry.
#[allow(missing_debug_implementations)]
pub struct Frame {
size: Size,
buffers: BufferStack,
- primitives: Vec<Primitive>,
+ layers: Vec<layer::Live>,
+ text: text::Batch,
transforms: Transforms,
fill_tessellator: tessellation::FillTessellator,
stroke_tessellator: tessellation::StrokeTessellator,
}
+pub enum Geometry {
+ Live(Vec<layer::Live>),
+ Cached(Rc<[Rc<RefCell<layer::Cached>>]>),
+}
+
+impl Cached for Geometry {
+ type Cache = Rc<[Rc<RefCell<layer::Cached>>]>;
+
+ fn load(cache: &Self::Cache) -> Self {
+ Geometry::Cached(cache.clone())
+ }
+
+ fn cache(self, previous: Option<Self::Cache>) -> Self::Cache {
+ match self {
+ Self::Live(live) => {
+ let mut layers = live.into_iter();
+
+ let mut new: Vec<_> = previous
+ .map(|previous| {
+ previous
+ .iter()
+ .cloned()
+ .zip(layers.by_ref())
+ .map(|(cached, live)| {
+ cached.borrow_mut().update(live);
+ cached
+ })
+ .collect()
+ })
+ .unwrap_or_default();
+
+ new.extend(
+ layers
+ .map(layer::Live::into_cached)
+ .map(RefCell::new)
+ .map(Rc::new),
+ );
+
+ Rc::from(new)
+ }
+ Self::Cached(cache) => cache,
+ }
+ }
+}
+
impl Frame {
/// Creates a new [`Frame`] with the given [`Size`].
pub fn new(size: Size) -> Frame {
Frame {
size,
buffers: BufferStack::new(),
- primitives: Vec::new(),
+ layers: Vec::new(),
+ text: text::Batch::new(),
transforms: Transforms {
previous: Vec::new(),
current: Transform(lyon::math::Transform::identity()),
@@ -44,49 +95,54 @@ impl Frame {
}
}
- fn into_primitives(mut self) -> Vec<Primitive> {
- for buffer in self.buffers.stack {
- match buffer {
- Buffer::Solid(buffer) => {
- if !buffer.indices.is_empty() {
- self.primitives.push(Primitive::Custom(
- primitive::Custom::Mesh(Mesh::Solid {
- buffers: mesh::Indexed {
- vertices: buffer.vertices,
- indices: buffer.indices,
- },
- size: self.size,
- }),
- ));
- }
- }
- Buffer::Gradient(buffer) => {
- if !buffer.indices.is_empty() {
- self.primitives.push(Primitive::Custom(
- primitive::Custom::Mesh(Mesh::Gradient {
- buffers: mesh::Indexed {
- vertices: buffer.vertices,
- indices: buffer.indices,
- },
- size: self.size,
- }),
- ));
- }
- }
- }
+ fn into_layers(mut self) -> Vec<layer::Live> {
+ if !self.text.is_empty() || !self.buffers.stack.is_empty() {
+ let clip_bounds = Rectangle::with_size(self.size);
+ let transformation = Transformation::IDENTITY;
+
+ // TODO: Generate different meshes for different transformations (?)
+ // Instead of transforming each path
+ let meshes = self
+ .buffers
+ .stack
+ .into_iter()
+ .map(|buffer| match buffer {
+ Buffer::Solid(buffer) => Mesh::Solid {
+ buffers: mesh::Indexed {
+ vertices: buffer.vertices,
+ indices: buffer.indices,
+ },
+ transformation: Transformation::IDENTITY,
+ size: self.size,
+ },
+ Buffer::Gradient(buffer) => Mesh::Gradient {
+ buffers: mesh::Indexed {
+ vertices: buffer.vertices,
+ indices: buffer.indices,
+ },
+ transformation: Transformation::IDENTITY,
+ size: self.size,
+ },
+ })
+ .collect();
+
+ let layer = layer::Live {
+ bounds: Some(clip_bounds),
+ transformation,
+ meshes,
+ text: self.text,
+ ..layer::Live::default()
+ };
+
+ self.layers.push(layer);
}
- self.primitives
+ self.layers
}
}
impl geometry::frame::Backend for Frame {
- type Geometry = Primitive;
-
- /// 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.
+ type Geometry = Geometry;
#[inline]
fn width(&self) -> f32 {
@@ -246,8 +302,7 @@ impl geometry::frame::Backend for Frame {
height: f32::INFINITY,
};
- // TODO: Honor layering!
- self.primitives.push(Primitive::Text {
+ self.text.push(graphics::Text::Cached {
content: text.content,
bounds,
color: text.color,
@@ -313,37 +368,17 @@ impl geometry::frame::Backend for Frame {
}
fn paste(&mut self, frame: Frame, at: Point) {
- let size = frame.size();
- let primitives = frame.into_primitives();
- let transformation = Transformation::translate(at.x, at.y);
-
- let (text, meshes) = primitives
- .into_iter()
- .partition(|primitive| matches!(primitive, Primitive::Text { .. }));
-
- self.primitives.push(Primitive::Group {
- primitives: vec![
- Primitive::Transform {
- transformation,
- content: Box::new(Primitive::Group { primitives: meshes }),
- },
- Primitive::Transform {
- transformation,
- content: Box::new(Primitive::Clip {
- bounds: Rectangle::with_size(size),
- content: Box::new(Primitive::Group {
- primitives: text,
- }),
- }),
- },
- ],
- });
+ let translation = Transformation::translate(at.x, at.y);
+
+ self.layers
+ .extend(frame.into_layers().into_iter().map(|mut layer| {
+ layer.transformation = layer.transformation * translation;
+ layer
+ }));
}
fn into_geometry(self) -> Self::Geometry {
- Primitive::Group {
- primitives: self.into_primitives(),
- }
+ Geometry::Live(self.into_layers())
}
}