From af0303f95e27737d9de8915f939b60a2bc3282ae Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 27 Apr 2023 15:10:41 +0200 Subject: Move damage tracking logic to `compositor` in `iced_tiny_skia` --- graphics/src/damage.rs | 140 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) create mode 100644 graphics/src/damage.rs (limited to 'graphics/src/damage.rs') diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs new file mode 100644 index 00000000..63604150 --- /dev/null +++ b/graphics/src/damage.rs @@ -0,0 +1,140 @@ +use crate::core::{Rectangle, Size}; +use crate::Primitive; + +use std::sync::Arc; + +pub fn regions(a: &Primitive, b: &Primitive) -> Vec { + match (a, b) { + ( + Primitive::Group { + primitives: primitives_a, + }, + Primitive::Group { + primitives: primitives_b, + }, + ) => return 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 regions(content_a, content_b) + .into_iter() + .filter_map(|r| r.intersection(bounds_a)) + .collect(); + } 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 regions(content_a, content_b) + .into_iter() + .map(|r| r + *translation_a) + .collect(); + } + } + ( + Primitive::Cache { content: content_a }, + Primitive::Cache { content: content_b }, + ) => { + if Arc::ptr_eq(content_a, content_b) { + return vec![]; + } + } + _ if a == b => return vec![], + _ => {} + } + + let bounds_a = a.bounds(); + let bounds_b = b.bounds(); + + if bounds_a == bounds_b { + vec![bounds_a] + } else { + vec![bounds_a, bounds_b] + } +} + +pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec { + let damage = previous + .iter() + .zip(current) + .flat_map(|(a, b)| regions(a, 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() + } +} + +pub fn group( + mut damage: Vec, + scale_factor: f32, + bounds: Size, +) -> Vec { + use std::cmp::Ordering; + + const AREA_THRESHOLD: f32 = 20_000.0; + + let bounds = Rectangle { + x: 0.0, + y: 0.0, + width: bounds.width as f32, + height: bounds.height as f32, + }; + + damage.sort_by(|a, b| { + a.x.partial_cmp(&b.x) + .unwrap_or(Ordering::Equal) + .then_with(|| a.y.partial_cmp(&b.y).unwrap_or(Ordering::Equal)) + }); + + let mut output = Vec::new(); + let mut scaled = damage + .into_iter() + .filter_map(|region| (region * scale_factor).intersection(&bounds)) + .filter(|region| region.width >= 1.0 && region.height >= 1.0); + + if let Some(mut current) = scaled.next() { + for region in scaled { + let union = current.union(®ion); + + if union.area() - current.area() - region.area() <= AREA_THRESHOLD { + current = union; + } else { + output.push(current); + current = region; + } + } + + output.push(current); + } + + output +} -- cgit From 38f82ab35fd24a1aaf96728148b2826211956a9f Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 27 Apr 2023 15:25:59 +0200 Subject: Expand damage regions of `Clip` primitives a bit --- graphics/src/damage.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'graphics/src/damage.rs') diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs index 63604150..5aab06b1 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -17,19 +17,21 @@ pub fn regions(a: &Primitive, b: &Primitive) -> Vec { Primitive::Clip { bounds: bounds_a, content: content_a, + .. }, Primitive::Clip { bounds: bounds_b, content: content_b, + .. }, ) => { if bounds_a == bounds_b { return regions(content_a, content_b) .into_iter() - .filter_map(|r| r.intersection(bounds_a)) + .filter_map(|r| r.intersection(&bounds_a.expand(1.0))) .collect(); } else { - return vec![*bounds_a, *bounds_b]; + return vec![bounds_a.expand(1.0), bounds_b.expand(1.0)]; } } ( -- cgit From 8622e998f2701e7f4ca8d2f71c85150f436a9945 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 11 May 2023 15:25:58 +0200 Subject: Write missing documentation in `iced_graphics` --- graphics/src/damage.rs | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'graphics/src/damage.rs') diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs index 5aab06b1..c6b0f759 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -1,8 +1,10 @@ +//! Track and compute the damage of graphical primitives. use crate::core::{Rectangle, Size}; use crate::Primitive; use std::sync::Arc; +/// Computes the damage regions between the two given primitives. pub fn regions(a: &Primitive, b: &Primitive) -> Vec { match (a, b) { ( @@ -73,6 +75,7 @@ pub fn regions(a: &Primitive, b: &Primitive) -> Vec { } } +/// Computes the damage regions between the two given lists of primitives. pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec { let damage = previous .iter() @@ -95,6 +98,8 @@ pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec { } } +/// Groups the given damage regions that are close together inside the given +/// bounds. pub fn group( mut damage: Vec, scale_factor: f32, -- cgit From 0ae1baa37bd7b6607f79b33b8a6d8c5daafde0b2 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 22 Jun 2023 00:38:36 +0200 Subject: Introduce custom backend-specific primitives --- graphics/src/damage.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 64 insertions(+), 4 deletions(-) (limited to 'graphics/src/damage.rs') diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs index c6b0f759..1add6707 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -1,11 +1,68 @@ //! Track and compute the damage of graphical primitives. +use crate::core::alignment; use crate::core::{Rectangle, Size}; use crate::Primitive; use std::sync::Arc; -/// Computes the damage regions between the two given primitives. -pub fn regions(a: &Primitive, b: &Primitive) -> Vec { +pub trait Damage: PartialEq { + /// Returns the bounds of the [`Damage`]. + fn bounds(&self) -> Rectangle; +} + +impl Damage for Primitive { + 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.5) + } + Self::Quad { bounds, .. } + | Self::Image { bounds, .. } + | Self::Svg { bounds, .. } => bounds.expand(1.0), + Self::Clip { bounds, .. } => bounds.expand(1.0), + Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => { + Rectangle::with_size(*size) + } + 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(), + Self::Custom(custom) => custom.bounds(), + } + } +} + +fn regions(a: &Primitive, b: &Primitive) -> Vec { match (a, b) { ( Primitive::Group { @@ -76,7 +133,10 @@ pub fn regions(a: &Primitive, b: &Primitive) -> Vec { } /// Computes the damage regions between the two given lists of primitives. -pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec { +pub fn list( + previous: &[Primitive], + current: &[Primitive], +) -> Vec { let damage = previous .iter() .zip(current) @@ -93,7 +153,7 @@ pub fn list(previous: &[Primitive], current: &[Primitive]) -> Vec { // Extend damage by the added/removed primitives damage - .chain(bigger[smaller.len()..].iter().map(Primitive::bounds)) + .chain(bigger[smaller.len()..].iter().map(Damage::bounds)) .collect() } } -- cgit From fa5650cfd1115e6ccec2ad795cf58fd970d5b43c Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 29 Jun 2023 07:48:03 +0200 Subject: Decouple `Mesh` primitives from main `Primitive` type --- graphics/src/damage.rs | 3 --- 1 file changed, 3 deletions(-) (limited to 'graphics/src/damage.rs') diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs index 1add6707..be17b935 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -43,9 +43,6 @@ impl Damage for Primitive { | Self::Image { bounds, .. } | Self::Svg { bounds, .. } => bounds.expand(1.0), Self::Clip { bounds, .. } => bounds.expand(1.0), - Self::SolidMesh { size, .. } | Self::GradientMesh { size, .. } => { - Rectangle::with_size(*size) - } Self::Group { primitives } => primitives .iter() .map(Self::bounds) -- cgit From 6921564c9f66e8103e19ec658099c5f5c32e8cc5 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Thu, 29 Jun 2023 07:55:52 +0200 Subject: Write missing docs in `iced_graphics` and `iced_wgpu` --- graphics/src/damage.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'graphics/src/damage.rs') diff --git a/graphics/src/damage.rs b/graphics/src/damage.rs index be17b935..2f29956e 100644 --- a/graphics/src/damage.rs +++ b/graphics/src/damage.rs @@ -5,6 +5,7 @@ use crate::Primitive; use std::sync::Arc; +/// A type that has some damage bounds. pub trait Damage: PartialEq { /// Returns the bounds of the [`Damage`]. fn bounds(&self) -> Rectangle; -- cgit