mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 19:08:05 +08:00
Implement the Brush tool (#1099)
* Implement Brush Node * Add color Input * Add VectorPointsNode * Add Erase Node * Adapt compilation infrastructure to allow non Image Frame inputs * Remove debug output from TransformNode * Fix transform calculation * Fix Blending by making the brush texture use associated alpha * Code improvements and UX polish * Rename Opacity to Flow * Add erase option to brush node + fix freehand tool * Fix crash * Revert erase implementation * Fix flattening id calculation * Fix some transformation issues * Fix changing the pivot location * Fix vector data modify bounds * Minor fn name cleanup * Fix some tests * Fix tests --------- Co-authored-by: Keavon Chambers <keavon@keavon.com> Co-authored-by: hypercube <0hypercube@gmail.com>
This commit is contained in:
committed by
Keavon Chambers
parent
758f757775
commit
589ff9a2d3
@@ -6,6 +6,61 @@ use crate::raster::ImageFrame;
|
||||
use crate::vector::VectorData;
|
||||
use crate::Node;
|
||||
|
||||
pub trait Transform {
|
||||
fn transform(&self) -> DAffine2;
|
||||
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
|
||||
pivot
|
||||
}
|
||||
}
|
||||
|
||||
pub trait TransformMut: Transform {
|
||||
fn transform_mut(&mut self) -> &mut DAffine2;
|
||||
fn translate(&mut self, offset: DVec2) {
|
||||
*self.transform_mut() = DAffine2::from_translation(offset) * self.transform();
|
||||
}
|
||||
}
|
||||
|
||||
impl Transform for ImageFrame {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
self.transform
|
||||
}
|
||||
}
|
||||
impl Transform for &ImageFrame {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
self.transform
|
||||
}
|
||||
}
|
||||
impl TransformMut for ImageFrame {
|
||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||
&mut self.transform
|
||||
}
|
||||
}
|
||||
|
||||
impl Transform for VectorData {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
self.transform
|
||||
}
|
||||
fn local_pivot(&self, pivot: DVec2) -> DVec2 {
|
||||
self.local_pivot(pivot)
|
||||
}
|
||||
}
|
||||
impl TransformMut for VectorData {
|
||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||
&mut self.transform
|
||||
}
|
||||
}
|
||||
|
||||
impl Transform for DAffine2 {
|
||||
fn transform(&self) -> DAffine2 {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl TransformMut for DAffine2 {
|
||||
fn transform_mut(&mut self) -> &mut DAffine2 {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TransformNode<Translation, Rotation, Scale, Shear, Pivot> {
|
||||
pub(crate) translate: Translation,
|
||||
@@ -16,45 +71,12 @@ pub struct TransformNode<Translation, Rotation, Scale, Shear, Pivot> {
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(TransformNode)]
|
||||
pub(crate) fn transform_vector_data(mut vector_data: VectorData, translate: DVec2, rotate: f64, scale: DVec2, shear: DVec2, pivot: DVec2) -> VectorData {
|
||||
let pivot = DAffine2::from_translation(vector_data.local_pivot(pivot));
|
||||
pub(crate) fn transform_vector_data<Data: TransformMut>(mut data: Data, translate: DVec2, rotate: f64, scale: DVec2, shear: DVec2, pivot: DVec2) -> Data {
|
||||
let pivot = DAffine2::from_translation(data.local_pivot(pivot));
|
||||
|
||||
let modification = DAffine2::from_scale_angle_translation(scale, rotate, translate) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]) * pivot.inverse();
|
||||
vector_data.transform = modification * vector_data.transform;
|
||||
let modification = pivot * DAffine2::from_scale_angle_translation(scale, rotate, translate) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]) * pivot.inverse();
|
||||
let data_transform = data.transform_mut();
|
||||
*data_transform = modification * (*data_transform);
|
||||
|
||||
vector_data
|
||||
}
|
||||
|
||||
impl<'input, Translation: 'input, Rotation: 'input, Scale: 'input, Shear: 'input, Pivot: 'input> Node<'input, ImageFrame> for TransformNode<Translation, Rotation, Scale, Shear, Pivot>
|
||||
where
|
||||
Translation: for<'any_input> Node<'any_input, (), Output = DVec2>,
|
||||
Rotation: for<'any_input> Node<'any_input, (), Output = f64>,
|
||||
Scale: for<'any_input> Node<'any_input, (), Output = DVec2>,
|
||||
Shear: for<'any_input> Node<'any_input, (), Output = DVec2>,
|
||||
Pivot: for<'any_input> Node<'any_input, (), Output = DVec2>,
|
||||
{
|
||||
type Output = ImageFrame;
|
||||
#[inline]
|
||||
fn eval<'node: 'input>(&'node self, mut image_frame: ImageFrame) -> Self::Output {
|
||||
let translate = self.translate.eval(());
|
||||
let rotate = self.rotate.eval(());
|
||||
let scale = self.scale.eval(());
|
||||
let shear = self.shear.eval(());
|
||||
let pivot = self.pivot.eval(());
|
||||
|
||||
let pivot = DAffine2::from_translation(pivot);
|
||||
let modification = pivot * DAffine2::from_scale_angle_translation(scale, rotate, translate) * DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]) * pivot.inverse();
|
||||
image_frame.transform = modification * image_frame.transform;
|
||||
|
||||
image_frame
|
||||
}
|
||||
}
|
||||
|
||||
// Generates a transform matrix that rotates around the center of the image
|
||||
fn generate_transform(shear: DVec2, transform: &DAffine2, scale: DVec2, rotate: f64, translate: DVec2) -> DAffine2 {
|
||||
let shear_matrix = DAffine2::from_cols_array(&[1., shear.y, shear.x, 1., 0., 0.]);
|
||||
let pivot = transform.transform_point2(DVec2::splat(0.5));
|
||||
let translate_to_center = DAffine2::from_translation(-pivot);
|
||||
|
||||
translate_to_center.inverse() * DAffine2::from_scale_angle_translation(scale, rotate, translate) * shear_matrix * translate_to_center
|
||||
data
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user