diff options
author | 2023-04-27 15:10:41 +0200 | |
---|---|---|
committer | 2023-04-27 15:10:41 +0200 | |
commit | af0303f95e27737d9de8915f939b60a2bc3282ae (patch) | |
tree | e0eb6d5a5a5cc1cedf057cf4ce83932eeb3c9d32 /graphics | |
parent | d953d12c38ad368110f4f9f40fb0f185c11dec54 (diff) | |
download | iced-af0303f95e27737d9de8915f939b60a2bc3282ae.tar.gz iced-af0303f95e27737d9de8915f939b60a2bc3282ae.tar.bz2 iced-af0303f95e27737d9de8915f939b60a2bc3282ae.zip |
Move damage tracking logic to `compositor` in `iced_tiny_skia`
Diffstat (limited to '')
-rw-r--r-- | graphics/src/damage.rs | 140 | ||||
-rw-r--r-- | graphics/src/lib.rs | 1 | ||||
-rw-r--r-- | graphics/src/primitive.rs | 90 |
3 files changed, 141 insertions, 90 deletions
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<Rectangle> { + 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<Rectangle> { + 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<Rectangle>, + scale_factor: f32, + bounds: Size<u32>, +) -> Vec<Rectangle> { + 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 +} diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index 0c50db52..e3de4025 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -28,6 +28,7 @@ mod viewport; pub mod backend; pub mod compositor; +pub mod damage; pub mod primitive; pub mod renderer; diff --git a/graphics/src/primitive.rs b/graphics/src/primitive.rs index 7f2c8ae2..1751d03a 100644 --- a/graphics/src/primitive.rs +++ b/graphics/src/primitive.rs @@ -208,96 +208,6 @@ impl Primitive { 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) - .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 content_a - .damage(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 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. |