Make Brush tool use per-stroke options and improve its performance (#1242)

* Laid groundwork for per-stroke brush parameters.

* Added new spacing parameter.

* Added back interpolation, using spacing parameter.

* Move bounding box code into core.

* Initial working prototype of per-stroke styles.

* Removed now useless brush node properties.

* Made default spacing 50% for performance comparison.

* Quick and dirty prototype for BlitNode copied from blend.

* Fixed error after rebase.

* Optimized the blitting loop.

* Pretty big optimization for into_flat_u8.

* Insert brush node for images

* Fix starting position transform

* UX polish

* Code review nits

---------

Co-authored-by: 0hypercube <0hypercube@gmail.com>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
Orson Peters
2023-05-27 22:55:49 +02:00
committed by Keavon Chambers
co-authored by 0hypercube Keavon Chambers
parent 0586d52f3a
commit 7148b199ec
15 changed files with 491 additions and 337 deletions
+86
View File
@@ -0,0 +1,86 @@
use dyn_any::{DynAny, StaticType};
use glam::{DAffine2, DVec2};
#[derive(Debug, Clone, DynAny)]
pub struct AxisAlignedBbox {
pub start: DVec2,
pub end: DVec2,
}
impl AxisAlignedBbox {
pub const ZERO: Self = Self { start: DVec2::ZERO, end: DVec2::ZERO };
pub fn size(&self) -> DVec2 {
self.end - self.start
}
pub fn to_transform(&self) -> DAffine2 {
DAffine2::from_translation(self.start) * DAffine2::from_scale(self.size())
}
pub fn contains(&self, point: DVec2) -> bool {
point.x >= self.start.x && point.x <= self.end.x && point.y >= self.start.y && point.y <= self.end.y
}
pub fn intersects(&self, other: &AxisAlignedBbox) -> bool {
other.start.x <= self.end.x && other.end.x >= self.start.x && other.start.y <= self.end.y && other.end.y >= self.start.y
}
pub fn union(&self, other: &AxisAlignedBbox) -> AxisAlignedBbox {
AxisAlignedBbox {
start: DVec2::new(self.start.x.min(other.start.x), self.start.y.min(other.start.y)),
end: DVec2::new(self.end.x.max(other.end.x), self.end.y.max(other.end.y)),
}
}
pub fn union_non_empty(&self, other: &AxisAlignedBbox) -> Option<AxisAlignedBbox> {
match (self.size() == DVec2::ZERO, other.size() == DVec2::ZERO) {
(true, true) => None,
(true, _) => Some(other.clone()),
(_, true) => Some(self.clone()),
_ => Some(AxisAlignedBbox {
start: DVec2::new(self.start.x.min(other.start.x), self.start.y.min(other.start.y)),
end: DVec2::new(self.end.x.max(other.end.x), self.end.y.max(other.end.y)),
}),
}
}
}
#[derive(Debug, Clone)]
pub struct Bbox {
pub top_left: DVec2,
pub top_right: DVec2,
pub bottom_left: DVec2,
pub bottom_right: DVec2,
}
impl Bbox {
pub fn unit() -> Self {
Self {
top_left: DVec2::new(0., 1.),
top_right: DVec2::new(1., 1.),
bottom_left: DVec2::new(0., 0.),
bottom_right: DVec2::new(1., 0.),
}
}
pub fn affine_transform(self, transform: DAffine2) -> Self {
Self {
top_left: transform.transform_point2(self.top_left),
top_right: transform.transform_point2(self.top_right),
bottom_left: transform.transform_point2(self.bottom_left),
bottom_right: transform.transform_point2(self.bottom_right),
}
}
pub fn to_axis_aligned_bbox(&self) -> AxisAlignedBbox {
let start_x = self.top_left.x.min(self.top_right.x).min(self.bottom_left.x).min(self.bottom_right.x);
let start_y = self.top_left.y.min(self.top_right.y).min(self.bottom_left.y).min(self.bottom_right.y);
let end_x = self.top_left.x.max(self.top_right.x).max(self.bottom_left.x).max(self.bottom_right.x);
let end_y = self.top_left.y.max(self.top_right.y).max(self.bottom_left.y).max(self.bottom_right.y);
AxisAlignedBbox {
start: DVec2::new(start_x, start_y),
end: DVec2::new(end_x, end_y),
}
}
}