summaryrefslogtreecommitdiffstats
path: root/graphics
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-04-27 15:10:41 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2023-04-27 15:10:41 +0200
commitaf0303f95e27737d9de8915f939b60a2bc3282ae (patch)
treee0eb6d5a5a5cc1cedf057cf4ce83932eeb3c9d32 /graphics
parentd953d12c38ad368110f4f9f40fb0f185c11dec54 (diff)
downloadiced-af0303f95e27737d9de8915f939b60a2bc3282ae.tar.gz
iced-af0303f95e27737d9de8915f939b60a2bc3282ae.tar.bz2
iced-af0303f95e27737d9de8915f939b60a2bc3282ae.zip
Move damage tracking logic to `compositor` in `iced_tiny_skia`
Diffstat (limited to 'graphics')
-rw-r--r--graphics/src/damage.rs140
-rw-r--r--graphics/src/lib.rs1
-rw-r--r--graphics/src/primitive.rs90
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(&region);
+
+ 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.