Skip to content

Commit

Permalink
Merge pull request #449 from cmeissl/fix/desktop_abstraction_damage_c…
Browse files Browse the repository at this point in the history
…lamping
  • Loading branch information
Drakulix authored Jan 7, 2022
2 parents 399bc6e + e9904ce commit 753d386
Show file tree
Hide file tree
Showing 2 changed files with 228 additions and 12 deletions.
23 changes: 16 additions & 7 deletions src/backend/renderer/gles2/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1283,15 +1283,24 @@ impl Frame for Gles2Frame {
(texture_mat * Vector3::new(src.loc.x as f32, (src.loc.y + src.size.h) as f32, 0.0)).truncate(), // bottom-left
];

let damage_viewport = Rectangle::from_extemities((0f64, 0f64), dest.size.to_point());

let damage = damage
.iter()
.map(|rect| {
[
rect.loc.x as f32 / dest.size.w as f32,
rect.loc.y as f32 / dest.size.h as f32,
rect.size.w as f32 / dest.size.w as f32,
rect.size.h as f32 / dest.size.h as f32,
]
.flat_map(|rect| {
let damage = rect
.to_f64()
.intersection(damage_viewport)
.map(|rect_constrained| {
[
(rect_constrained.loc.x / dest.size.w) as f32,
(rect_constrained.loc.y / dest.size.h) as f32,
(rect_constrained.size.w / dest.size.w) as f32,
(rect_constrained.size.h / dest.size.h) as f32,
]
});
debug_assert!(damage.is_some());
damage
})
.flatten()
.collect::<Vec<_>>();
Expand Down
217 changes: 212 additions & 5 deletions src/utils/geometry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,23 @@ impl<N: Coordinate, Kind> Point<N, Kind> {
}
}

impl<N: Coordinate, Kind> Point<N, Kind> {
/// Constrain this [`Point`] within a [`Rectangle`] with the same coordinates
///
/// The [`Point`] returned is guaranteed to be not smaller than the [`Rectangle`]
/// location and not greater than the [`Rectangle`] location + size.
#[inline]
pub fn constrain(self, rect: impl Into<Rectangle<N, Kind>>) -> Point<N, Kind> {
let rect = rect.into();

Point {
x: self.x.max(rect.loc.x).min(rect.loc.x.saturating_add(rect.size.w)),
y: self.y.max(rect.loc.y).min(rect.loc.y.saturating_add(rect.size.h)),
_kind: std::marker::PhantomData,
}
}
}

impl<N: Coordinate, Kind> Point<N, Kind> {
/// Convert the underlying numerical type to f64 for floating point manipulations
#[inline]
Expand Down Expand Up @@ -543,6 +560,20 @@ impl<N: Coordinate, Kind> Size<N, Kind> {
}
}

impl<N: Coordinate, Kind> Size<N, Kind> {
/// Restrict this [`Size`] to min and max [`Size`] with the same coordinates
pub fn clamp(self, min: impl Into<Size<N, Kind>>, max: impl Into<Size<N, Kind>>) -> Size<N, Kind> {
let min = min.into();
let max = max.into();

Size {
w: self.w.max(min.w).min(max.w),
h: self.h.max(min.h).min(max.h),
_kind: std::marker::PhantomData,
}
}
}

impl<N: Coordinate, Kind> Size<N, Kind> {
/// Convert the underlying numerical type to f64 for floating point manipulations
#[inline]
Expand Down Expand Up @@ -895,11 +926,8 @@ impl<N: Coordinate, Kind> Rectangle<N, Kind> {
return None;
}
Some(Rectangle::from_extemities(
(self.loc.x.max(other.loc.x), self.loc.y.max(other.loc.y)),
(
(self.loc.x.saturating_add(self.size.w)).min(other.loc.x.saturating_add(other.size.w)),
(self.loc.y.saturating_add(self.size.h)).min(other.loc.y.saturating_add(other.size.h)),
),
self.loc.constrain(other),
self.loc.add(self.size).constrain(other),
))
}

Expand Down Expand Up @@ -1040,3 +1068,182 @@ impl<N: Default, Kind> Default for Rectangle<N, Kind> {
}
}
}

mod tests {
#[test]
fn test_point_constrain_stays() {
use super::{Physical, Point, Rectangle};

let point: Point<_, Physical> = Point::from((100f64, 100f64));
let rect: Rectangle<_, Physical> = Rectangle::from_loc_and_size((50f64, 50f64), (100f64, 100f64));

let constrained = point.constrain(rect);
assert_eq!(constrained, point);
}

#[test]
fn test_point_constrain_right() {
use super::{Physical, Point, Rectangle};

let point: Point<_, Physical> = Point::from((200f64, 100f64));
let rect: Rectangle<_, Physical> = Rectangle::from_loc_and_size((50f64, 50f64), (100f64, 100f64));

let constrained = point.constrain(rect);
assert_eq!(constrained, Point::from((150f64, 100f64)));
}

#[test]
fn test_point_constrain_left() {
use super::{Physical, Point, Rectangle};

let point: Point<_, Physical> = Point::from((50f64, 100f64));
let rect: Rectangle<_, Physical> = Rectangle::from_loc_and_size((50f64, 50f64), (100f64, 100f64));

let constrained = point.constrain(rect);
assert_eq!(constrained, Point::from((50f64, 100f64)));
}

#[test]
fn test_point_constrain_top() {
use super::{Physical, Point, Rectangle};

let point: Point<_, Physical> = Point::from((100f64, 20f64));
let rect: Rectangle<_, Physical> = Rectangle::from_loc_and_size((50f64, 50f64), (100f64, 100f64));

let constrained = point.constrain(rect);
assert_eq!(constrained, Point::from((100f64, 50f64)));
}

#[test]
fn test_point_constrain_bottom() {
use super::{Physical, Point, Rectangle};

let point: Point<_, Physical> = Point::from((100f64, 200f64));
let rect: Rectangle<_, Physical> = Rectangle::from_loc_and_size((50f64, 50f64), (100f64, 100f64));

let constrained = point.constrain(rect);
assert_eq!(constrained, Point::from((100f64, 150f64)));
}

#[test]
fn test_size_clamp_stays() {
use super::{Physical, Size};

let size: Size<_, Physical> = Size::from((100f64, 50f64));
let min: Size<_, Physical> = Size::from((20f64, 10f64));
let max: Size<_, Physical> = Size::from((1000f64, 500f64));

let clamped = size.clamp(min, max);
assert_eq!(clamped, size);
}

#[test]
fn test_size_clamp_wider() {
use super::{Physical, Size};

let size: Size<_, Physical> = Size::from((1100f64, 50f64));
let min: Size<_, Physical> = Size::from((20f64, 10f64));
let max: Size<_, Physical> = Size::from((1000f64, 500f64));

let clamped = size.clamp(min, max);
assert_eq!(clamped, Size::from((1000f64, 50f64)));
}

#[test]
fn test_size_clamp_taler() {
use super::{Physical, Size};

let size: Size<_, Physical> = Size::from((100f64, 550f64));
let min: Size<_, Physical> = Size::from((20f64, 10f64));
let max: Size<_, Physical> = Size::from((1000f64, 500f64));

let clamped = size.clamp(min, max);
assert_eq!(clamped, Size::from((100f64, 500f64)));
}

#[test]
fn test_size_clamp_smaller_width() {
use super::{Physical, Size};

let size: Size<_, Physical> = Size::from((10f64, 50f64));
let min: Size<_, Physical> = Size::from((20f64, 10f64));
let max: Size<_, Physical> = Size::from((1000f64, 500f64));

let clamped = size.clamp(min, max);
assert_eq!(clamped, Size::from((20f64, 50f64)));
}

#[test]
fn test_size_clamp_smaller_height() {
use super::{Physical, Size};

let size: Size<_, Physical> = Size::from((100f64, 5f64));
let min: Size<_, Physical> = Size::from((20f64, 10f64));
let max: Size<_, Physical> = Size::from((1000f64, 500f64));

let clamped = size.clamp(min, max);
assert_eq!(clamped, Size::from((100f64, 10f64)));
}

#[test]
fn test_intersection_self_inner_overlaps() {
use super::{Physical, Rectangle};

let rect_self: Rectangle<_, Physical> = Rectangle::from_extemities((20f64, 10f64), (100f64, 60f64));
let rect_other: Rectangle<_, Physical> = Rectangle::from_extemities((0f64, 0f64), (150f64, 150f64));

let intersection = rect_self.intersection(rect_other);
assert_eq!(intersection, Some(rect_self),);
}

#[test]
fn test_intersection_self_outer_overlaps() {
use super::{Physical, Rectangle};

let rect_self: Rectangle<_, Physical> = Rectangle::from_extemities((0f64, 0f64), (150f64, 150f64));
let rect_other: Rectangle<_, Physical> = Rectangle::from_extemities((20f64, 10f64), (100f64, 60f64));

let intersection = rect_self.intersection(rect_other);
assert_eq!(intersection, Some(rect_other),);
}

#[test]
fn test_intersection_self_left_overlaps() {
use super::{Physical, Rectangle};

let rect_self: Rectangle<_, Physical> = Rectangle::from_extemities((20f64, 10f64), (100f64, 60f64));
let rect_other: Rectangle<_, Physical> = Rectangle::from_extemities((70f64, 40f64), (150f64, 90f64));

let intersection = rect_self.intersection(rect_other);
assert_eq!(
intersection,
Some(Rectangle::from_extemities((70f64, 40f64), (100f64, 60f64)))
);
}

#[test]
fn test_intersection_self_right_overlaps() {
use super::{Physical, Rectangle};

let rect_other: Rectangle<_, Physical> = Rectangle::from_extemities((20f64, 10f64), (100f64, 60f64));
let rect_self: Rectangle<_, Physical> = Rectangle::from_extemities((70f64, 40f64), (150f64, 90f64));

let intersection = rect_self.intersection(rect_other);
assert_eq!(
intersection,
Some(Rectangle::from_extemities((70f64, 40f64), (100f64, 60f64)))
);
}

#[test]
fn test_intersection_non_overlap() {
use super::{Physical, Rectangle};

let rect_self: Rectangle<_, Physical> = Rectangle::from_extemities((20f64, 10f64), (100f64, 60f64));
let rect_other: Rectangle<_, Physical> =
Rectangle::from_extemities((170f64, 140f64), (250f64, 190f64));

let intersection = rect_self.intersection(rect_other);
assert_eq!(intersection, None,);
}
}

0 comments on commit 753d386

Please sign in to comment.