mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-22 14:08:12 +08:00
New node: Morph (#1576)
* Add morph node * Range slider time parameter, better lerping * Lerp more fill and stroke parameters --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
co-authored by
Keavon Chambers
parent
768bbe820d
commit
484acbcde3
+16
-1
@@ -2580,7 +2580,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
DocumentInputType::value("Start", TaggedValue::DVec2(DVec2::new(0., 0.5)), false),
|
||||
DocumentInputType::value("End", TaggedValue::DVec2(DVec2::new(1., 0.5)), false),
|
||||
DocumentInputType::value("Transform", TaggedValue::DAffine2(DAffine2::IDENTITY), false),
|
||||
DocumentInputType::value("Positions", TaggedValue::GradientPositions(vec![(0., Some(Color::BLACK)), (1., Some(Color::WHITE))]), false),
|
||||
DocumentInputType::value("Positions", TaggedValue::GradientPositions(vec![(0., Color::BLACK), (1., Color::WHITE)]), false),
|
||||
],
|
||||
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
|
||||
properties: node_properties::fill_properties,
|
||||
@@ -2715,6 +2715,21 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
properties: node_properties::node_no_properties,
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
name: "Morph",
|
||||
category: "Vector",
|
||||
implementation: NodeImplementation::proto("graphene_core::vector::MorphNode<_, _, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Source", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
|
||||
DocumentInputType::value("Target", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
|
||||
DocumentInputType::value("Start Index", TaggedValue::U32(0), false),
|
||||
DocumentInputType::value("Time", TaggedValue::F64(0.5), false),
|
||||
],
|
||||
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
|
||||
manual_composition: Some(concrete!(Footprint)),
|
||||
properties: node_properties::morph_properties,
|
||||
..Default::default()
|
||||
},
|
||||
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
|
||||
DocumentNodeDefinition {
|
||||
name: "Image Segmentation",
|
||||
|
||||
+16
-7
@@ -623,18 +623,18 @@ fn gradient_type_widget(document_node: &DocumentNode, node_id: NodeId, index: us
|
||||
LayoutGroup::Row { widgets }
|
||||
}
|
||||
|
||||
fn gradient_row(row: &mut Vec<WidgetHolder>, positions: &Vec<(f64, Option<Color>)>, index: usize, node_id: NodeId, input_index: usize) {
|
||||
fn gradient_row(row: &mut Vec<WidgetHolder>, positions: &Vec<(f64, Color)>, index: usize, node_id: NodeId, input_index: usize) {
|
||||
let label = TextLabel::new(format!("Gradient: {:.0}%", positions[index].0 * 100.)).tooltip("Adjustable by dragging the gradient stops in the viewport with the Gradient tool active");
|
||||
row.push(label.widget_holder());
|
||||
let on_update = {
|
||||
let positions = positions.clone();
|
||||
move |color_button: &ColorButton| {
|
||||
let mut new_positions = positions.clone();
|
||||
new_positions[index].1 = color_button.value;
|
||||
new_positions[index].1 = color_button.value.unwrap();
|
||||
TaggedValue::GradientPositions(new_positions)
|
||||
}
|
||||
};
|
||||
let color = ColorButton::new(positions[index].1).on_update(update_value(on_update, node_id, input_index));
|
||||
let color = ColorButton::new(Some(positions[index].1)).on_update(update_value(on_update, node_id, input_index)).allow_none(false);
|
||||
add_blank_assist(row);
|
||||
row.push(Separator::new(SeparatorType::Unrelated).widget_holder());
|
||||
row.push(color.widget_holder());
|
||||
@@ -668,10 +668,9 @@ fn gradient_row(row: &mut Vec<WidgetHolder>, positions: &Vec<(f64, Option<Color>
|
||||
let mut new_positions = positions.clone();
|
||||
|
||||
// Blend linearly between the two colors.
|
||||
let get_color = |index: usize| match (new_positions[index].1, new_positions.get(index + 1).and_then(|x| x.1)) {
|
||||
(Some(a), Some(b)) => Color::from_rgbaf32((a.r() + b.r()) / 2., (a.g() + b.g()) / 2., (a.b() + b.b()) / 2., ((a.a() + b.a()) / 2.).clamp(0., 1.)),
|
||||
(Some(v), _) | (_, Some(v)) => Some(v),
|
||||
_ => Some(Color::WHITE),
|
||||
let get_color = |index: usize| match (new_positions[index].1, new_positions.get(index + 1).map(|x| x.1)) {
|
||||
(a, Some(b)) => Color::from_rgbaf32_unchecked((a.r() + b.r()) / 2., (a.g() + b.g()) / 2., (a.b() + b.b()) / 2., ((a.a() + b.a()) / 2.).clamp(0., 1.)),
|
||||
(_, None) => Color::WHITE,
|
||||
};
|
||||
let get_pos = |index: usize| (new_positions[index].0 + new_positions.get(index + 1).map(|v| v.0).unwrap_or(1.)) / 2.;
|
||||
|
||||
@@ -2056,6 +2055,16 @@ pub fn sample_points_properties(document_node: &DocumentNode, node_id: NodeId, _
|
||||
]
|
||||
}
|
||||
|
||||
pub fn morph_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let start_index = number_widget(document_node, node_id, 2, "Start Index", NumberInput::default().min(0.), true);
|
||||
let time = number_widget(document_node, node_id, 3, "Time", NumberInput::default().min(0.).max(1.).mode_range(), true);
|
||||
|
||||
vec![
|
||||
LayoutGroup::Row { widgets: start_index }.with_tooltip("The index of point on the target that morphs to the first point of the source"),
|
||||
LayoutGroup::Row { widgets: time }.with_tooltip("Linear time of transition - 0. is source, 1. is target"),
|
||||
]
|
||||
}
|
||||
|
||||
/// Fill Node Widgets LayoutGroup
|
||||
pub fn fill_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let fill_type_index = 1;
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::messages::portfolio::document::utility_types::document_metadata::Laye
|
||||
use crate::messages::tool::common_functionality::graph_modification_utils::get_gradient;
|
||||
use crate::messages::tool::common_functionality::snapping::SnapManager;
|
||||
|
||||
use graphene_core::raster::color::Color;
|
||||
use graphene_core::vector::style::{Fill, Gradient, GradientType};
|
||||
|
||||
#[derive(Default)]
|
||||
@@ -335,7 +334,7 @@ impl Fsm for GradientToolFsmState {
|
||||
if selected_gradient.gradient.positions.len() == 1 {
|
||||
responses.add(GraphOperationMessage::FillSet {
|
||||
layer: selected_gradient.layer,
|
||||
fill: Fill::Solid(selected_gradient.gradient.positions[0].1.unwrap_or(Color::BLACK)),
|
||||
fill: Fill::Solid(selected_gradient.gradient.positions[0].1),
|
||||
});
|
||||
return self;
|
||||
}
|
||||
@@ -344,7 +343,7 @@ impl Fsm for GradientToolFsmState {
|
||||
let min_position = selected_gradient.gradient.positions.iter().map(|(pos, _)| *pos).reduce(f64::min).expect("No min");
|
||||
let max_position = selected_gradient.gradient.positions.iter().map(|(pos, _)| *pos).reduce(f64::max).expect("No max");
|
||||
|
||||
// Recompute the start and end posiiton of the gradient (in viewport transform)
|
||||
// Recompute the start and end position of the gradient (in viewport transform)
|
||||
let transform = selected_gradient.transform;
|
||||
let (start, end) = (transform.transform_point2(selected_gradient.gradient.start), transform.transform_point2(selected_gradient.gradient.end));
|
||||
let (new_start, new_end) = (start.lerp(end, min_position), start.lerp(end, max_position));
|
||||
|
||||
Reference in New Issue
Block a user