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