summaryrefslogtreecommitdiffstats
path: root/graphics/src/primitive.rs
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-03-22 00:36:57 +0100
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-04-04 02:08:02 +0200
commit0f7abffc0e94b4bb9f8117db633bfd07d900eb93 (patch)
tree89b6606db2619574369bf8c4a29d5ef0ecb7969c /graphics/src/primitive.rs
parent6fae8bf6cbe7155bcee42eaeba68e31564df057c (diff)
downloadiced-0f7abffc0e94b4bb9f8117db633bfd07d900eb93.tar.gz
iced-0f7abffc0e94b4bb9f8117db633bfd07d900eb93.tar.bz2
iced-0f7abffc0e94b4bb9f8117db633bfd07d900eb93.zip
Draft (very) basic incremental rendering for `iced_tiny_skia`
Diffstat (limited to 'graphics/src/primitive.rs')
-rw-r--r--graphics/src/primitive.rs151
1 files changed, 147 insertions, 4 deletions
diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs
index 195b62da..bbf300b0 100644
--- a/graphics/src/primitive.rs
+++ b/graphics/src/primitive.rs
@@ -7,7 +7,7 @@ use bytemuck::{Pod, Zeroable};
use std::sync::Arc;
/// A rendering primitive.
-#[derive(Debug, Clone)]
+#[derive(Debug, Clone, PartialEq)]
#[non_exhaustive]
pub enum Primitive {
/// A text primitive
@@ -147,10 +147,153 @@ impl Primitive {
content: Box::new(self),
}
}
+
+ pub fn bounds(&self) -> Rectangle {
+ match self {
+ Self::Text {
+ bounds,
+ horizontal_alignment,
+ vertical_alignment,
+ ..
+ } => {
+ let mut bounds = *bounds;
+
+ bounds.x = match horizontal_alignment {
+ alignment::Horizontal::Left => bounds.x,
+ alignment::Horizontal::Center => {
+ bounds.x - bounds.width / 2.0
+ }
+ alignment::Horizontal::Right => bounds.x - bounds.width,
+ };
+
+ bounds.y = match vertical_alignment {
+ alignment::Vertical::Top => bounds.y,
+ alignment::Vertical::Center => {
+ bounds.y - bounds.height / 2.0
+ }
+ alignment::Vertical::Bottom => bounds.y - bounds.height,
+ };
+
+ bounds.expand(1.0)
+ }
+ Self::Quad { bounds, .. }
+ | Self::Image { bounds, .. }
+ | Self::Svg { bounds, .. }
+ | Self::Clip { bounds, .. } => bounds.expand(1.0),
+ Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => {
+ Rectangle::with_size(*size)
+ }
+ #[cfg(feature = "tiny-skia")]
+ Self::Fill { path, .. } | Self::Stroke { path, .. } => {
+ let bounds = path.bounds();
+
+ Rectangle {
+ x: bounds.x(),
+ y: bounds.y(),
+ width: bounds.width(),
+ height: bounds.height(),
+ }
+ .expand(1.0)
+ }
+ Self::Group { primitives } => primitives
+ .iter()
+ .map(Self::bounds)
+ .fold(Rectangle::with_size(Size::ZERO), |a, b| {
+ Rectangle::union(&a, &b)
+ }),
+ Self::Translate {
+ translation,
+ content,
+ } => content.bounds() + *translation,
+ Self::Cache { content } => content.bounds(),
+ }
+ }
+
+ pub fn damage(&self, other: &Self) -> Vec<Rectangle> {
+ match (self, other) {
+ (
+ Primitive::Group {
+ primitives: primitives_a,
+ },
+ Primitive::Group {
+ primitives: primitives_b,
+ },
+ ) => return Self::damage_list(primitives_a, primitives_b),
+ (
+ Primitive::Clip {
+ bounds: bounds_a,
+ content: content_a,
+ },
+ Primitive::Clip {
+ bounds: bounds_b,
+ content: content_b,
+ },
+ ) => {
+ if bounds_a == bounds_b {
+ return content_a.damage(content_b);
+ } else {
+ return vec![*bounds_a, *bounds_b];
+ }
+ }
+ (
+ Primitive::Translate {
+ translation: translation_a,
+ content: content_a,
+ },
+ Primitive::Translate {
+ translation: translation_b,
+ content: content_b,
+ },
+ ) => {
+ if translation_a == translation_b {
+ return content_a.damage(content_b);
+ }
+ }
+ (
+ Primitive::Cache { content: content_a },
+ Primitive::Cache { content: content_b },
+ ) => {
+ if Arc::ptr_eq(content_a, content_b) {
+ return vec![];
+ }
+ }
+ _ if self == other => return vec![],
+ _ => {}
+ }
+
+ let bounds_a = self.bounds();
+ let bounds_b = other.bounds();
+
+ if bounds_a == bounds_b {
+ vec![bounds_a]
+ } else {
+ vec![bounds_a, bounds_b]
+ }
+ }
+
+ pub fn damage_list(previous: &[Self], current: &[Self]) -> Vec<Rectangle> {
+ let damage =
+ previous.iter().zip(current).flat_map(|(a, b)| a.damage(b));
+
+ if previous.len() == current.len() {
+ damage.collect()
+ } else {
+ let (smaller, bigger) = if previous.len() < current.len() {
+ (previous, current)
+ } else {
+ (current, previous)
+ };
+
+ // Extend damage by the added/removed primitives
+ damage
+ .chain(bigger[smaller.len()..].iter().map(Primitive::bounds))
+ .collect()
+ }
+ }
}
/// A set of [`Vertex2D`] and indices representing a list of triangles.
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Mesh2D<T> {
/// The vertices of the mesh
pub vertices: Vec<T>,
@@ -162,7 +305,7 @@ pub struct Mesh2D<T> {
}
/// A two-dimensional vertex.
-#[derive(Copy, Clone, Debug, Zeroable, Pod)]
+#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)]
#[repr(C)]
pub struct Vertex2D {
/// The vertex position in 2D space.
@@ -170,7 +313,7 @@ pub struct Vertex2D {
}
/// A two-dimensional vertex with a color.
-#[derive(Copy, Clone, Debug, Zeroable, Pod)]
+#[derive(Copy, Clone, Debug, PartialEq, Zeroable, Pod)]
#[repr(C)]
pub struct ColoredVertex2D {
/// The vertex position in 2D space.