Skip to content

Fix gradient transformation #588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Apr 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions editor/src/viewport_tools/tools/gradient_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,10 +81,12 @@ impl Default for GradientToolFsmState {

/// Computes the transform from gradient space to layer space (where gradient space is 0..1 in layer space)
fn gradient_space_transform(path: &[LayerId], layer: &Layer, document: &DocumentMessageHandler) -> DAffine2 {
let bounds = layer.aabounding_box().unwrap();
let bounds = layer.aabounding_box_for_transform(DAffine2::IDENTITY).unwrap();
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);

document.graphene_document.multiply_transforms(&path[..path.len() - 1]).unwrap() * bound_transform
let multiplied = document.graphene_document.multiply_transforms(path).unwrap();

multiplied * bound_transform
}

/// Contains info on the overlays for a single gradient
Expand Down Expand Up @@ -225,7 +227,7 @@ impl SelectedGradient {
self.gradient.end = mouse;
}

self.gradient.transform = self.transform.inverse();
self.gradient.transform = self.transform;
let fill = Fill::LinearGradient(self.gradient.clone());
let path = self.path.clone();
responses.push_back(Operation::SetLayerFill { path, fill }.into());
Expand Down
14 changes: 13 additions & 1 deletion graphene/src/layers/shape_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ pub struct ShapeLayer {
impl LayerData for ShapeLayer {
fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec<DAffine2>, view_mode: ViewMode) {
let mut path = self.path.clone();

let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
let layer_bounds = [(x0, y0).into(), (x1, y1).into()];

let transform = self.transform(transforms, view_mode);
let inverse = transform.inverse();
if !inverse.is_finite() {
Expand All @@ -40,12 +44,20 @@ impl LayerData for ShapeLayer {
}
path.apply_affine(glam_to_kurbo(transform));

let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
let transformed_bounds = [(x0, y0).into(), (x1, y1).into()];

let _ = writeln!(svg, r#"<g transform="matrix("#);
inverse.to_cols_array().iter().enumerate().for_each(|(i, entry)| {
let _ = svg.write_str(&(entry.to_string() + if i == 5 { "" } else { "," }));
});
let _ = svg.write_str(r#")">"#);
let _ = write!(svg, r#"<path d="{}" {} />"#, path.to_svg(), self.style.render(view_mode, svg_defs));
let _ = write!(
svg,
r#"<path d="{}" {} />"#,
path.to_svg(),
self.style.render(view_mode, svg_defs, transform, layer_bounds, transformed_bounds)
);
let _ = svg.write_str("</g>");
}

Expand Down
26 changes: 16 additions & 10 deletions graphene/src/layers/style/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,19 +61,25 @@ impl Gradient {
}

/// Adds the gradient def with the uuid specified
fn render_defs(&self, svg_defs: &mut String) {
fn render_defs(&self, svg_defs: &mut String, multiplied_transform: DAffine2, bounds: [DVec2; 2], transformed_bounds: [DVec2; 2]) {
let bound_transform = DAffine2::from_scale_angle_translation(bounds[1] - bounds[0], 0., bounds[0]);
let transformed_bound_transform = DAffine2::from_scale_angle_translation(transformed_bounds[1] - transformed_bounds[0], 0., transformed_bounds[0]);
let updated_transform = multiplied_transform * bound_transform;

let positions = self
.positions
.iter()
.filter_map(|(pos, color)| color.map(|color| (pos, color)))
.map(|(position, color)| format!(r##"<stop offset="{}" stop-color="#{}" />"##, position, color.rgba_hex()))
.collect::<String>();

let start = self.transform.inverse().transform_point2(self.start);
let end = self.transform.inverse().transform_point2(self.end);
let mod_gradient = transformed_bound_transform.inverse();
let mod_points = mod_gradient.inverse() * transformed_bound_transform.inverse() * updated_transform;

let start = mod_points.transform_point2(self.start);
let end = mod_points.transform_point2(self.end);

let transform = self
.transform
let transform = mod_gradient
.to_cols_array()
.iter()
.enumerate()
Expand Down Expand Up @@ -122,12 +128,12 @@ impl Fill {
}

/// Renders the fill, adding necessary defs.
pub fn render(&self, svg_defs: &mut String) -> String {
pub fn render(&self, svg_defs: &mut String, multiplied_transform: DAffine2, bounds: [DVec2; 2], transformed_bounds: [DVec2; 2]) -> String {
match self {
Self::None => r#" fill="none""#.to_string(),
Self::Solid(color) => format!(r##" fill="#{}"{}"##, color.rgb_hex(), format_opacity("fill", color.a())),
Self::LinearGradient(gradient) => {
gradient.render_defs(svg_defs);
gradient.render_defs(svg_defs, multiplied_transform, bounds, transformed_bounds);
format!(r##" fill="url('#{}')""##, gradient.uuid)
}
}
Expand Down Expand Up @@ -430,10 +436,10 @@ impl PathStyle {
self.stroke = None;
}

pub fn render(&self, view_mode: ViewMode, svg_defs: &mut String) -> String {
pub fn render(&self, view_mode: ViewMode, svg_defs: &mut String, multiplied_transform: DAffine2, bounds: [DVec2; 2], transformed_bounds: [DVec2; 2]) -> String {
let fill_attribute = match (view_mode, &self.fill) {
(ViewMode::Outline, _) => Fill::None.render(svg_defs),
(_, fill) => fill.render(svg_defs),
(ViewMode::Outline, _) => Fill::None.render(svg_defs, multiplied_transform, bounds, transformed_bounds),
(_, fill) => fill.render(svg_defs, multiplied_transform, bounds, transformed_bounds),
};
let stroke_attribute = match (view_mode, &self.stroke) {
(ViewMode::Outline, _) => Stroke::new(LAYER_OUTLINE_STROKE_COLOR, LAYER_OUTLINE_STROKE_WIDTH).render(),
Expand Down
13 changes: 12 additions & 1 deletion graphene/src/layers/text_layer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,9 +63,20 @@ impl LayerData for TextLayer {
} else {
let mut path = self.to_bez_path();

let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
let bounds = [(x0, y0).into(), (x1, y1).into()];

path.apply_affine(glam_to_kurbo(transform));

let _ = write!(svg, r#"<path d="{}" {} />"#, path.to_svg(), self.style.render(view_mode, svg_defs));
let kurbo::Rect { x0, y0, x1, y1 } = path.bounding_box();
let transformed_bounds = [(x0, y0).into(), (x1, y1).into()];

let _ = write!(
svg,
r#"<path d="{}" {} />"#,
path.to_svg(),
self.style.render(view_mode, svg_defs, transform, bounds, transformed_bounds)
);
}
let _ = svg.write_str("</g>");
}
Expand Down