Add seed parameters to all nodes with RNG

This commit is contained in:
Keavon Chambers
2024-08-17 07:40:02 -07:00
parent e647ca9f91
commit c39032ab54
7 changed files with 141 additions and 60 deletions
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
@@ -3521,7 +3521,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
category: "Vector: Style", category: "Vector: Style",
node_template: NodeTemplate { node_template: NodeTemplate {
document_node: DocumentNode { document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_core::vector::AssignColorsNode<_, _, _, _, _, _>"), implementation: DocumentNodeImplementation::proto("graphene_core::vector::AssignColorsNode<_, _, _, _, _, _, _>"),
inputs: vec![ inputs: vec![
NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroup::default()), true), NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroup::default()), true),
NodeInput::value(TaggedValue::Bool(true), false), NodeInput::value(TaggedValue::Bool(true), false),
@@ -3530,6 +3530,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
NodeInput::value(TaggedValue::Bool(false), false), NodeInput::value(TaggedValue::Bool(false), false),
NodeInput::value(TaggedValue::Bool(false), false), NodeInput::value(TaggedValue::Bool(false), false),
NodeInput::value(TaggedValue::U32(0), false), NodeInput::value(TaggedValue::U32(0), false),
NodeInput::value(TaggedValue::U32(0), false),
], ],
..Default::default() ..Default::default()
}, },
@@ -3541,6 +3542,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
"Gradient".to_string(), "Gradient".to_string(),
"Reverse".to_string(), "Reverse".to_string(),
"Randomize".to_string(), "Randomize".to_string(),
"Seed".to_string(),
"Repeat Every".to_string(), "Repeat Every".to_string(),
], ],
output_names: vec!["Vector Group".to_string()], output_names: vec!["Vector Group".to_string()],
@@ -3745,14 +3747,16 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
node_template: NodeTemplate { node_template: NodeTemplate {
document_node: DocumentNode { document_node: DocumentNode {
// TODO: Wrap this implementation with a document node that has a cache node so the output is cached? // TODO: Wrap this implementation with a document node that has a cache node so the output is cached?
implementation: DocumentNodeImplementation::proto("graphene_core::vector::CopyToPoints<_, _, _, _, _, _>"), implementation: DocumentNodeImplementation::proto("graphene_core::vector::CopyToPoints<_, _, _, _, _, _, _, _>"),
inputs: vec![ inputs: vec![
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
NodeInput::value(TaggedValue::F64(1.), false), NodeInput::value(TaggedValue::F64(1.), false),
NodeInput::value(TaggedValue::F64(1.), false), NodeInput::value(TaggedValue::F64(1.), false),
NodeInput::value(TaggedValue::F64(0.), false), NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::U32(0), false),
NodeInput::value(TaggedValue::F64(0.), false), NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::U32(0), false),
], ],
manual_composition: Some(concrete!(Footprint)), manual_composition: Some(concrete!(Footprint)),
..Default::default() ..Default::default()
@@ -3764,7 +3768,9 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
"Random Scale Min".to_string(), "Random Scale Min".to_string(),
"Random Scale Max".to_string(), "Random Scale Max".to_string(),
"Random Scale Bias".to_string(), "Random Scale Bias".to_string(),
"Random Scale Seed".to_string(),
"Random Rotation".to_string(), "Random Rotation".to_string(),
"Random Rotation Seed".to_string(),
], ],
output_names: vec!["Vector".to_string()], output_names: vec!["Vector".to_string()],
..Default::default() ..Default::default()
@@ -3876,8 +3882,12 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(1), 0)], exports: vec![NodeInput::node(NodeId(1), 0)],
nodes: [ nodes: [
DocumentNode { DocumentNode {
inputs: vec![NodeInput::network(concrete!(graphene_core::vector::VectorData), 0), NodeInput::network(concrete!(f64), 1)], inputs: vec![
implementation: DocumentNodeImplementation::proto("graphene_core::vector::PoissonDiskPoints<_>"), NodeInput::network(concrete!(graphene_core::vector::VectorData), 0),
NodeInput::network(concrete!(f64), 1),
NodeInput::network(concrete!(u32), 2),
],
implementation: DocumentNodeImplementation::proto("graphene_core::vector::PoissonDiskPoints<_, _>"),
..Default::default() ..Default::default()
}, },
DocumentNode { DocumentNode {
@@ -3896,6 +3906,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
inputs: vec![ inputs: vec![
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
NodeInput::value(TaggedValue::F64(10.), false), NodeInput::value(TaggedValue::F64(10.), false),
NodeInput::value(TaggedValue::U32(0), false),
], ],
..Default::default() ..Default::default()
}, },
@@ -3926,7 +3937,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
}, },
..Default::default() ..Default::default()
}), }),
input_names: vec!["Vector Data".to_string(), "Separation Disk Diameter".to_string()], input_names: vec!["Vector Data".to_string(), "Separation Disk Diameter".to_string(), "Seed".to_string()],
output_names: vec!["Vector".to_string()], output_names: vec!["Vector".to_string()],
..Default::default() ..Default::default()
}, },
@@ -1825,7 +1825,7 @@ impl NodeGraphMessageHandler {
fn build_wire_path_locations(output_position: DVec2, input_position: DVec2, vertical_out: bool, vertical_in: bool) -> Vec<DVec2> { fn build_wire_path_locations(output_position: DVec2, input_position: DVec2, vertical_out: bool, vertical_in: bool) -> Vec<DVec2> {
let horizontal_gap = (output_position.x - input_position.x).abs(); let horizontal_gap = (output_position.x - input_position.x).abs();
let vertical_gap = (output_position.y - input_position.y).abs(); let vertical_gap = (output_position.y - input_position.y).abs();
// TODO: Finish this commented out code replacement for the code below it based on this diagram: <https://files.keavon.com/-/InsubstantialElegantQueenant/capture.png> // TODO: Finish this commented out code replacement for the code below it based on this diagram: <https://files.keavon.com/-/SuperbWideFoxterrier/capture.png>
// // Straight: stacking lines which are always straight, or a straight horizontal wire between two aligned nodes // // Straight: stacking lines which are always straight, or a straight horizontal wire between two aligned nodes
// if ((verticalOut && vertical_in) || (!verticalOut && !vertical_in && vertical_gap === 0)) { // if ((verticalOut && vertical_in) || (!verticalOut && !vertical_in && vertical_gap === 0)) {
// return [ // return [
@@ -122,7 +122,7 @@ fn text_area_widget(document_node: &DocumentNode, node_id: NodeId, index: usize,
widgets widgets
} }
fn bool_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> Vec<WidgetHolder> { fn bool_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, checkbox_input: CheckboxInput, blank_assist: bool) -> Vec<WidgetHolder> {
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist);
let Some(input) = document_node.inputs.get(index) else { let Some(input) = document_node.inputs.get(index) else {
@@ -132,7 +132,8 @@ fn bool_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
if let Some(&TaggedValue::Bool(x)) = &input.as_non_exposed_value() { if let Some(&TaggedValue::Bool(x)) = &input.as_non_exposed_value() {
widgets.extend_from_slice(&[ widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder(),
CheckboxInput::new(x) checkbox_input
.checked(x)
.on_update(update_value(|x: &CheckboxInput| TaggedValue::Bool(x.checked), node_id, index)) .on_update(update_value(|x: &CheckboxInput| TaggedValue::Bool(x.checked), node_id, index))
.on_commit(commit_value) .on_commit(commit_value)
.widget_holder(), .widget_holder(),
@@ -372,7 +373,7 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
LayoutGroup::Row { widgets } LayoutGroup::Row { widgets }
} }
fn vec_f64_input(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, text_props: TextInput, blank_assist: bool) -> Vec<WidgetHolder> { fn vec_f64_input(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, text_input: TextInput, blank_assist: bool) -> Vec<WidgetHolder> {
let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::Number, blank_assist); let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::Number, blank_assist);
let from_string = |string: &str| { let from_string = |string: &str| {
@@ -392,7 +393,7 @@ fn vec_f64_input(document_node: &DocumentNode, node_id: NodeId, index: usize, na
if let Some(TaggedValue::VecF64(x)) = &input.as_non_exposed_value() { if let Some(TaggedValue::VecF64(x)) = &input.as_non_exposed_value() {
widgets.extend_from_slice(&[ widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(), Separator::new(SeparatorType::Unrelated).widget_holder(),
text_props text_input
.value(x.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", ")) .value(x.iter().map(|v| v.to_string()).collect::<Vec<_>>().join(", "))
.on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, index)) .on_update(optionally_update_value(move |x: &TextInput| from_string(&x.value), node_id, index))
.widget_holder(), .widget_holder(),
@@ -990,7 +991,7 @@ pub fn vector2_properties(document_node: &DocumentNode, node_id: NodeId, _contex
} }
pub fn boolean_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn boolean_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = bool_widget(document_node, node_id, 0, "Bool", true); let widgets = bool_widget(document_node, node_id, 0, "Bool", CheckboxInput::default(), true);
vec![LayoutGroup::Row { widgets }] vec![LayoutGroup::Row { widgets }]
} }
@@ -1065,7 +1066,7 @@ pub fn noise_pattern_properties(document_node: &DocumentNode, node_id: NodeId, _
// All // All
let clip = LayoutGroup::Row { let clip = LayoutGroup::Row {
widgets: bool_widget(document_node, node_id, 0, "Clip", true), widgets: bool_widget(document_node, node_id, 0, "Clip", CheckboxInput::default(), true),
}; };
let seed = number_widget(document_node, node_id, 1, "Seed", NumberInput::default().min(0.).is_integer(true), true); let seed = number_widget(document_node, node_id, 1, "Seed", NumberInput::default().min(0.).is_integer(true), true);
let scale = number_widget(document_node, node_id, 2, "Scale", NumberInput::default().min(0.).disabled(!coherent_noise_active), true); let scale = number_widget(document_node, node_id, 2, "Scale", NumberInput::default().min(0.).disabled(!coherent_noise_active), true);
@@ -1204,7 +1205,7 @@ pub fn hue_saturation_properties(document_node: &DocumentNode, node_id: NodeId,
pub fn brightness_contrast_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn brightness_contrast_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let brightness = number_widget(document_node, node_id, 1, "Brightness", NumberInput::default().min(-150.).max(150.), true); let brightness = number_widget(document_node, node_id, 1, "Brightness", NumberInput::default().min(-150.).max(150.), true);
let contrast = number_widget(document_node, node_id, 2, "Contrast", NumberInput::default().min(-100.).max(100.), true); let contrast = number_widget(document_node, node_id, 2, "Contrast", NumberInput::default().min(-100.).max(100.), true);
let use_legacy = bool_widget(document_node, node_id, 3, "Use Legacy", true); let use_legacy = bool_widget(document_node, node_id, 3, "Use Legacy", CheckboxInput::default(), true);
vec![ vec![
LayoutGroup::Row { widgets: brightness }, LayoutGroup::Row { widgets: brightness },
@@ -1239,7 +1240,7 @@ pub fn gradient_map_properties(document_node: &DocumentNode, node_id: NodeId, _c
let reverse_index = 2; let reverse_index = 2;
let gradient_row = color_widget(document_node, node_id, gradient_index, "Gradient", ColorButton::default().allow_none(false), true); let gradient_row = color_widget(document_node, node_id, gradient_index, "Gradient", ColorButton::default().allow_none(false), true);
let reverse_row = bool_widget(document_node, node_id, reverse_index, "Reverse", true); let reverse_row = bool_widget(document_node, node_id, reverse_index, "Reverse", CheckboxInput::default(), true);
vec![gradient_row, LayoutGroup::Row { widgets: reverse_row }] vec![gradient_row, LayoutGroup::Row { widgets: reverse_row }]
} }
@@ -1250,18 +1251,20 @@ pub fn assign_colors_properties(document_node: &DocumentNode, node_id: NodeId, _
let gradient_index = 3; let gradient_index = 3;
let reverse_index = 4; let reverse_index = 4;
let randomize_index = 5; let randomize_index = 5;
let repeat_every_index = 6; let seed_index = 6;
let repeat_every_index = 7;
let fill_row = bool_widget(document_node, node_id, fill_index, "Fill", true); let fill_row = bool_widget(document_node, node_id, fill_index, "Fill", CheckboxInput::default(), true);
let stroke_row = bool_widget(document_node, node_id, stroke_index, "Stroke", true); let stroke_row = bool_widget(document_node, node_id, stroke_index, "Stroke", CheckboxInput::default(), true);
let gradient_row = color_widget(document_node, node_id, gradient_index, "Gradient", ColorButton::default().allow_none(false), true); let gradient_row = color_widget(document_node, node_id, gradient_index, "Gradient", ColorButton::default().allow_none(false), true);
let reverse_row = bool_widget(document_node, node_id, reverse_index, "Reverse", true); let reverse_row = bool_widget(document_node, node_id, reverse_index, "Reverse", CheckboxInput::default(), true);
let randomize_row = bool_widget(document_node, node_id, randomize_index, "Randomize", true);
let randomize_enabled = if let Some(&TaggedValue::Bool(randomize_enabled)) = &document_node.inputs[randomize_index].as_value() { let randomize_enabled = if let Some(&TaggedValue::Bool(randomize_enabled)) = &document_node.inputs[randomize_index].as_value() {
randomize_enabled randomize_enabled
} else { } else {
false false
}; };
let randomize_row = bool_widget(document_node, node_id, randomize_index, "Randomize", CheckboxInput::default(), true);
let seed_row = number_widget(document_node, node_id, seed_index, "Seed", NumberInput::default().min(0.).int().disabled(!randomize_enabled), true);
let repeat_every_row = number_widget( let repeat_every_row = number_widget(
document_node, document_node,
node_id, node_id,
@@ -1277,6 +1280,7 @@ pub fn assign_colors_properties(document_node: &DocumentNode, node_id: NodeId, _
gradient_row, gradient_row,
LayoutGroup::Row { widgets: reverse_row }, LayoutGroup::Row { widgets: reverse_row },
LayoutGroup::Row { widgets: randomize_row }, LayoutGroup::Row { widgets: randomize_row },
LayoutGroup::Row { widgets: seed_row },
LayoutGroup::Row { widgets: repeat_every_row }, LayoutGroup::Row { widgets: repeat_every_row },
] ]
} }
@@ -1299,7 +1303,7 @@ pub fn vibrance_properties(document_node: &DocumentNode, node_id: NodeId, _conte
pub fn channel_mixer_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn channel_mixer_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
// Monochrome // Monochrome
let monochrome_index = 1; let monochrome_index = 1;
let monochrome = bool_widget(document_node, node_id, monochrome_index, "Monochrome", true); let monochrome = bool_widget(document_node, node_id, monochrome_index, "Monochrome", CheckboxInput::default(), true);
let is_monochrome = if let Some(&TaggedValue::Bool(monochrome_choice)) = &document_node.inputs[monochrome_index].as_value() { let is_monochrome = if let Some(&TaggedValue::Bool(monochrome_choice)) = &document_node.inputs[monochrome_index].as_value() {
monochrome_choice monochrome_choice
} else { } else {
@@ -1721,7 +1725,7 @@ pub fn rectangle_properties(document_node: &DocumentNode, node_id: NodeId, _cont
} }
// Clamped // Clamped
let clamped = bool_widget(document_node, node_id, clamped_index, "Clamped", true); let clamped = bool_widget(document_node, node_id, clamped_index, "Clamped", CheckboxInput::default(), true);
vec![ vec![
LayoutGroup::Row { widgets: size_x }, LayoutGroup::Row { widgets: size_x },
@@ -1758,7 +1762,7 @@ pub fn spline_properties(document_node: &DocumentNode, node_id: NodeId, _context
} }
pub fn logic_operator_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn logic_operator_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let widgets = bool_widget(document_node, node_id, 0, "Operand B", true); let widgets = bool_widget(document_node, node_id, 0, "Operand B", CheckboxInput::default(), true);
vec![LayoutGroup::Row { widgets }] vec![LayoutGroup::Row { widgets }]
} }
@@ -2195,7 +2199,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
LayoutGroup::Row { widgets }.with_tooltip("A negative text prompt can be used to list things like objects or colors to avoid") LayoutGroup::Row { widgets }.with_tooltip("A negative text prompt can be used to list things like objects or colors to avoid")
}; };
let base_image = { let base_image = {
let widgets = bool_widget(document_node, node_id, base_img_index, "Adapt Input Image", true); let widgets = bool_widget(document_node, node_id, base_img_index, "Adapt Input Image", CheckboxInput::default(), true);
LayoutGroup::Row { widgets }.with_tooltip("Generate an image based upon the bitmap data plugged into this node") LayoutGroup::Row { widgets }.with_tooltip("Generate an image based upon the bitmap data plugged into this node")
}; };
let image_creativity = { let image_creativity = {
@@ -2286,7 +2290,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
// } // }
let improve_faces = { let improve_faces = {
let widgets = bool_widget(document_node, node_id, faces_index, "Improve Faces", true); let widgets = bool_widget(document_node, node_id, faces_index, "Improve Faces", CheckboxInput::default(), true);
LayoutGroup::Row { widgets }.with_tooltip( LayoutGroup::Row { widgets }.with_tooltip(
"Postprocess human (or human-like) faces to look subtly less distorted.\n\ "Postprocess human (or human-like) faces to look subtly less distorted.\n\
\n\ \n\
@@ -2294,7 +2298,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
) )
}; };
let tiling = { let tiling = {
let widgets = bool_widget(document_node, node_id, tiling_index, "Tiling", true); let widgets = bool_widget(document_node, node_id, tiling_index, "Tiling", CheckboxInput::default(), true);
LayoutGroup::Row { widgets }.with_tooltip("Generate the image so its edges loop seamlessly to make repeatable patterns or textures") LayoutGroup::Row { widgets }.with_tooltip("Generate the image so its edges loop seamlessly to make repeatable patterns or textures")
}; };
layout.extend_from_slice(&[improve_faces, tiling]); layout.extend_from_slice(&[improve_faces, tiling]);
@@ -2413,12 +2417,20 @@ pub fn boolean_operation_properties(document_node: &DocumentNode, node_id: NodeI
} }
pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let instance = vector_widget(document_node, node_id, 1, "Instance", true); let instance_index = 1;
let random_scale_min_index = 2;
let random_scale_max_index = 3;
let random_scale_bias_index = 4;
let random_scale_seed_index = 5;
let random_rotation_index = 6;
let random_rotation_seed_index = 7;
let instance = vector_widget(document_node, node_id, instance_index, "Instance", true);
let random_scale_min = number_widget( let random_scale_min = number_widget(
document_node, document_node,
node_id, node_id,
2, random_scale_min_index,
"Random Scale Min", "Random Scale Min",
NumberInput::default().min(0.).mode_range().range_min(Some(0.)).range_max(Some(2.)).unit("x"), NumberInput::default().min(0.).mode_range().range_min(Some(0.)).range_max(Some(2.)).unit("x"),
true, true,
@@ -2426,7 +2438,7 @@ pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId,
let random_scale_max = number_widget( let random_scale_max = number_widget(
document_node, document_node,
node_id, node_id,
3, random_scale_max_index,
"Random Scale Max", "Random Scale Max",
NumberInput::default().min(0.).mode_range().range_min(Some(0.)).range_max(Some(2.)).unit("x"), NumberInput::default().min(0.).mode_range().range_min(Some(0.)).range_max(Some(2.)).unit("x"),
true, true,
@@ -2434,13 +2446,22 @@ pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId,
let random_scale_bias = number_widget( let random_scale_bias = number_widget(
document_node, document_node,
node_id, node_id,
4, random_scale_bias_index,
"Random Scale Bias", "Random Scale Bias",
NumberInput::default().mode_range().range_min(Some(-50.)).range_max(Some(50.)), NumberInput::default().mode_range().range_min(Some(-50.)).range_max(Some(50.)),
true, true,
); );
let random_scale_seed = number_widget(document_node, node_id, random_scale_seed_index, "Random Scale Seed", NumberInput::default().int().min(0.), true);
let random_rotation = number_widget(document_node, node_id, 5, "Random Rotation", NumberInput::default().min(0.).max(360.).mode_range().unit("°"), true); let random_rotation = number_widget(
document_node,
node_id,
random_rotation_index,
"Random Rotation",
NumberInput::default().min(0.).max(360.).mode_range().unit("°"),
true,
);
let random_rotation_seed = number_widget(document_node, node_id, random_rotation_seed_index, "Random Rotation Seed", NumberInput::default().int().min(0.), true);
vec![ vec![
LayoutGroup::Row { widgets: instance }.with_tooltip("Artwork to be copied and placed at each point"), LayoutGroup::Row { widgets: instance }.with_tooltip("Artwork to be copied and placed at each point"),
@@ -2448,7 +2469,9 @@ pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId,
LayoutGroup::Row { widgets: random_scale_max }.with_tooltip("Maximum range of randomized sizes given to each instance"), LayoutGroup::Row { widgets: random_scale_max }.with_tooltip("Maximum range of randomized sizes given to each instance"),
LayoutGroup::Row { widgets: random_scale_bias } LayoutGroup::Row { widgets: random_scale_bias }
.with_tooltip("Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"), .with_tooltip("Bias for the probability distribution of randomized sizes (0 is uniform, negatives favor more of small sizes, positives favor more of large sizes)"),
LayoutGroup::Row { widgets: random_scale_seed }.with_tooltip("Seed to determine unique variations on all the randomized instance sizes"),
LayoutGroup::Row { widgets: random_rotation }.with_tooltip("Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise"), LayoutGroup::Row { widgets: random_rotation }.with_tooltip("Range of randomized angles given to each instance, in degrees ranging from furthest clockwise to counterclockwise"),
LayoutGroup::Row { widgets: random_rotation_seed }.with_tooltip("Seed to determine unique variations on all the randomized instance angles"),
] ]
} }
@@ -2456,7 +2479,7 @@ pub fn sample_points_properties(document_node: &DocumentNode, node_id: NodeId, _
let spacing = number_widget(document_node, node_id, 1, "Spacing", NumberInput::default().min(1.).unit(" px"), true); let spacing = number_widget(document_node, node_id, 1, "Spacing", NumberInput::default().min(1.).unit(" px"), true);
let start_offset = number_widget(document_node, node_id, 2, "Start Offset", NumberInput::default().min(0.).unit(" px"), true); let start_offset = number_widget(document_node, node_id, 2, "Start Offset", NumberInput::default().min(0.).unit(" px"), true);
let stop_offset = number_widget(document_node, node_id, 3, "Stop Offset", NumberInput::default().min(0.).unit(" px"), true); let stop_offset = number_widget(document_node, node_id, 3, "Stop Offset", NumberInput::default().min(0.).unit(" px"), true);
let adaptive_spacing = bool_widget(document_node, node_id, 4, "Adaptive Spacing", true); let adaptive_spacing = bool_widget(document_node, node_id, 4, "Adaptive Spacing", CheckboxInput::default(), true);
vec![ vec![
LayoutGroup::Row { widgets: spacing }.with_tooltip("Distance between each instance (exact if 'Adaptive Spacing' is disabled, approximate if enabled)"), LayoutGroup::Row { widgets: spacing }.with_tooltip("Distance between each instance (exact if 'Adaptive Spacing' is disabled, approximate if enabled)"),
@@ -2467,16 +2490,21 @@ pub fn sample_points_properties(document_node: &DocumentNode, node_id: NodeId, _
} }
pub fn poisson_disk_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn poisson_disk_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let separation_disk_diameter_index = 1;
let seed_index = 2;
let spacing = number_widget( let spacing = number_widget(
document_node, document_node,
node_id, node_id,
1, separation_disk_diameter_index,
"Separation Disk Diameter", "Separation Disk Diameter",
NumberInput::default().min(0.01).mode_range().range_min(Some(1.)).range_max(Some(100.)), NumberInput::default().min(0.01).mode_range().range_min(Some(1.)).range_max(Some(100.)),
true, true,
); );
vec![LayoutGroup::Row { widgets: spacing }] let seed = number_widget(document_node, node_id, seed_index, "Seed", NumberInput::default().int().min(0.), true);
vec![LayoutGroup::Row { widgets: spacing }, LayoutGroup::Row { widgets: seed }]
} }
pub fn morph_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> { pub fn morph_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
@@ -2622,7 +2650,7 @@ pub fn artboard_properties(document_node: &DocumentNode, node_id: NodeId, _conte
let location = vec2_widget(document_node, node_id, 2, "Location", "X", "Y", " px", None, add_blank_assist); let location = vec2_widget(document_node, node_id, 2, "Location", "X", "Y", " px", None, add_blank_assist);
let dimensions = vec2_widget(document_node, node_id, 3, "Dimensions", "W", "H", " px", None, add_blank_assist); let dimensions = vec2_widget(document_node, node_id, 3, "Dimensions", "W", "H", " px", None, add_blank_assist);
let background = color_widget(document_node, node_id, 4, "Background", ColorButton::default().allow_none(false), true); let background = color_widget(document_node, node_id, 4, "Background", ColorButton::default().allow_none(false), true);
let clip = bool_widget(document_node, node_id, 5, "Clip", true); let clip = bool_widget(document_node, node_id, 5, "Clip", CheckboxInput::default(), true);
let clip_row = LayoutGroup::Row { widgets: clip }; let clip_row = LayoutGroup::Row { widgets: clip };
+61 -19
View File
@@ -10,28 +10,40 @@ use glam::{DAffine2, DVec2};
use rand::{Rng, SeedableRng}; use rand::{Rng, SeedableRng};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct AssignColorsNode<Fill, Stroke, Gradient, Reverse, Randomize, RepeatEvery> { pub struct AssignColorsNode<Fill, Stroke, Gradient, Reverse, Randomize, Seed, RepeatEvery> {
fill: Fill, fill: Fill,
stroke: Stroke, stroke: Stroke,
gradient: Gradient, gradient: Gradient,
reverse: Reverse, reverse: Reverse,
randomize: Randomize, randomize: Randomize,
seed: Seed,
repeat_every: RepeatEvery, repeat_every: RepeatEvery,
} }
#[node_macro::node_fn(AssignColorsNode)] #[node_macro::node_fn(AssignColorsNode)]
fn assign_colors_node(group: GraphicGroup, fill: bool, stroke: bool, gradient: GradientStops, reverse: bool, randomize: bool, repeat_every: u32) -> GraphicGroup { fn assign_colors_node(group: GraphicGroup, fill: bool, stroke: bool, gradient: GradientStops, reverse: bool, randomize: bool, seed: u32, repeat_every: u32) -> GraphicGroup {
let mut group = group; let mut group = group;
let vector_data_list: Vec<_> = group.iter_mut().filter_map(|element| element.as_vector_data_mut()).collect(); let vector_data_list: Vec<_> = group.iter_mut().filter_map(|element| element.as_vector_data_mut()).collect();
let list = (vector_data_list.len(), vector_data_list.into_iter()); let list = (vector_data_list.len(), vector_data_list.into_iter());
assign_colors(list, fill, stroke, gradient, reverse, randomize, repeat_every); assign_colors(
list,
AlignColorsOptions {
fill,
stroke,
gradient,
reverse,
randomize,
seed,
repeat_every,
},
);
group group
} }
#[node_macro::node_impl(AssignColorsNode)] #[node_macro::node_impl(AssignColorsNode)]
fn assign_colors_node(vector_data: VectorData, fill: bool, stroke: bool, gradient: GradientStops, reverse: bool, randomize: bool, repeat_every: u32) -> GraphicGroup { fn assign_colors_node(vector_data: VectorData, fill: bool, stroke: bool, gradient: GradientStops, reverse: bool, randomize: bool, seed: u32, repeat_every: u32) -> GraphicGroup {
let mut vector_data_list: Vec<_> = vector_data let mut vector_data_list: Vec<_> = vector_data
.region_bezier_paths() .region_bezier_paths()
.map(|(_, subpath)| { .map(|(_, subpath)| {
@@ -44,7 +56,18 @@ fn assign_colors_node(vector_data: VectorData, fill: bool, stroke: bool, gradien
.collect(); .collect();
let list = (vector_data_list.len(), vector_data_list.iter_mut().map(|element| element.as_vector_data_mut().unwrap())); let list = (vector_data_list.len(), vector_data_list.iter_mut().map(|element| element.as_vector_data_mut().unwrap()));
assign_colors(list, fill, stroke, gradient, reverse, randomize, repeat_every); assign_colors(
list,
AlignColorsOptions {
fill,
stroke,
gradient,
reverse,
randomize,
seed,
repeat_every,
},
);
let mut group = GraphicGroup::new(vector_data_list); let mut group = GraphicGroup::new(vector_data_list);
group.transform = vector_data.transform; group.transform = vector_data.transform;
@@ -53,27 +76,37 @@ fn assign_colors_node(vector_data: VectorData, fill: bool, stroke: bool, gradien
group group
} }
fn assign_colors<'a>((length, vector_data): (usize, impl Iterator<Item = &'a mut VectorData>), fill: bool, stroke: bool, gradient: GradientStops, reverse: bool, randomize: bool, repeat_every: u32) { struct AlignColorsOptions {
let gradient = if reverse { gradient.reversed() } else { gradient }; fill: bool,
stroke: bool,
gradient: GradientStops,
reverse: bool,
randomize: bool,
seed: u32,
repeat_every: u32,
}
let mut rng = rand::rngs::StdRng::seed_from_u64(0); fn assign_colors<'a>((length, vector_data): (usize, impl Iterator<Item = &'a mut VectorData>), options: AlignColorsOptions) {
let gradient = if options.reverse { options.gradient.reversed() } else { options.gradient };
let mut rng = rand::rngs::StdRng::seed_from_u64(options.seed as u64);
for (i, vector_data) in vector_data.enumerate() { for (i, vector_data) in vector_data.enumerate() {
let factor = match randomize { let factor = match options.randomize {
true => rng.gen::<f64>(), true => rng.gen::<f64>(),
false => match repeat_every { false => match options.repeat_every {
0 => i as f64 / (length - 1) as f64, 0 => i as f64 / (length - 1) as f64,
1 => 0., 1 => 0.,
_ => i as f64 % repeat_every as f64 / (repeat_every - 1) as f64, _ => i as f64 % options.repeat_every as f64 / (options.repeat_every - 1) as f64,
}, },
}; };
let color = gradient.evalute(factor); let color = gradient.evalute(factor);
if fill { if options.fill {
vector_data.style.set_fill(Fill::Solid(color)); vector_data.style.set_fill(Fill::Solid(color));
} }
if stroke { if options.stroke {
if let Some(stroke) = vector_data.style.stroke().and_then(|stroke| stroke.with_color(&Some(color))) { if let Some(stroke) = vector_data.style.stroke().and_then(|stroke| stroke.with_color(&Some(color))) {
vector_data.style.set_stroke(stroke); vector_data.style.set_stroke(stroke);
} }
@@ -273,15 +306,18 @@ impl ConcatElement for GraphicGroup {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct CopyToPoints<Points, Instance, RandomScaleMin, RandomScaleMax, RandomScaleBias, RandomRotation> { pub struct CopyToPoints<Points, Instance, RandomScaleMin, RandomScaleMax, RandomScaleBias, RandomScaleSeed, RandomRotation, RandomRotationSeed> {
points: Points, points: Points,
instance: Instance, instance: Instance,
random_scale_min: RandomScaleMin, random_scale_min: RandomScaleMin,
random_scale_max: RandomScaleMax, random_scale_max: RandomScaleMax,
random_scale_bias: RandomScaleBias, random_scale_bias: RandomScaleBias,
random_scale_seed: RandomScaleSeed,
random_rotation: RandomRotation, random_rotation: RandomRotation,
random_rotation_seed: RandomRotationSeed,
} }
#[allow(clippy::too_many_arguments)]
#[node_macro::node_fn(CopyToPoints)] #[node_macro::node_fn(CopyToPoints)]
async fn copy_to_points<I: GraphicElementRendered + Default + ConcatElement + TransformMut + Send>( async fn copy_to_points<I: GraphicElementRendered + Default + ConcatElement + TransformMut + Send>(
footprint: Footprint, footprint: Footprint,
@@ -290,7 +326,9 @@ async fn copy_to_points<I: GraphicElementRendered + Default + ConcatElement + Tr
random_scale_min: f64, random_scale_min: f64,
random_scale_max: f64, random_scale_max: f64,
random_scale_bias: f64, random_scale_bias: f64,
random_scale_seed: u32,
random_rotation: f64, random_rotation: f64,
random_rotation_seed: u32,
) -> I { ) -> I {
let points = self.points.eval(footprint).await; let points = self.points.eval(footprint).await;
let instance = self.instance.eval(footprint).await; let instance = self.instance.eval(footprint).await;
@@ -301,8 +339,8 @@ async fn copy_to_points<I: GraphicElementRendered + Default + ConcatElement + Tr
let instance_bounding_box = instance.bounding_box(DAffine2::IDENTITY).unwrap_or_default(); let instance_bounding_box = instance.bounding_box(DAffine2::IDENTITY).unwrap_or_default();
let instance_center = -0.5 * (instance_bounding_box[0] + instance_bounding_box[1]); let instance_center = -0.5 * (instance_bounding_box[0] + instance_bounding_box[1]);
let mut scale_rng = rand::rngs::StdRng::seed_from_u64(0); let mut scale_rng = rand::rngs::StdRng::seed_from_u64(random_scale_seed as u64);
let mut rotation_rng = rand::rngs::StdRng::seed_from_u64(0); let mut rotation_rng = rand::rngs::StdRng::seed_from_u64(random_rotation_seed as u64);
let do_scale = random_scale_difference.abs() > 1e-6; let do_scale = random_scale_difference.abs() > 1e-6;
let do_rotation = random_rotation.abs() > 1e-6; let do_rotation = random_rotation.abs() > 1e-6;
@@ -425,13 +463,14 @@ async fn sample_points(
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct PoissonDiskPoints<SeparationDiskDiameter> { pub struct PoissonDiskPoints<SeparationDiskDiameter, Seed> {
separation_disk_diameter: SeparationDiskDiameter, separation_disk_diameter: SeparationDiskDiameter,
seed: Seed,
} }
#[node_macro::node_fn(PoissonDiskPoints)] #[node_macro::node_fn(PoissonDiskPoints)]
fn poisson_disk_points(vector_data: VectorData, separation_disk_diameter: f64) -> VectorData { fn poisson_disk_points(vector_data: VectorData, separation_disk_diameter: f64, seed: u32) -> VectorData {
let mut rng = rand::rngs::StdRng::seed_from_u64(0); let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
let mut result = VectorData::empty(); let mut result = VectorData::empty();
for mut subpath in vector_data.stroke_bezier_paths() { for mut subpath in vector_data.stroke_bezier_paths() {
if subpath.manipulator_groups().len() < 3 { if subpath.manipulator_groups().len() < 3 {
@@ -745,7 +784,9 @@ mod test {
random_scale_min: FutureWrapperNode(ClonedNode(1.)), random_scale_min: FutureWrapperNode(ClonedNode(1.)),
random_scale_max: FutureWrapperNode(ClonedNode(1.)), random_scale_max: FutureWrapperNode(ClonedNode(1.)),
random_scale_bias: FutureWrapperNode(ClonedNode(0.)), random_scale_bias: FutureWrapperNode(ClonedNode(0.)),
random_scale_seed: FutureWrapperNode(ClonedNode(0)),
random_rotation: FutureWrapperNode(ClonedNode(0.)), random_rotation: FutureWrapperNode(ClonedNode(0.)),
random_rotation_seed: FutureWrapperNode(ClonedNode(0)),
} }
.eval(Footprint::default()) .eval(Footprint::default())
.await; .await;
@@ -798,6 +839,7 @@ mod test {
fn poisson() { fn poisson() {
let sample_points = PoissonDiskPoints { let sample_points = PoissonDiskPoints {
separation_disk_diameter: ClonedNode(10. * std::f64::consts::SQRT_2), separation_disk_diameter: ClonedNode(10. * std::f64::consts::SQRT_2),
seed: ClonedNode(0),
} }
.eval(VectorData::from_subpath(Subpath::new_ellipse(DVec2::NEG_ONE * 50., DVec2::ONE * 50.))); .eval(VectorData::from_subpath(Subpath::new_ellipse(DVec2::NEG_ONE * 50., DVec2::ONE * 50.)));
assert!( assert!(
@@ -679,8 +679,8 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
register_node!(graphene_core::vector::SetFillNode<_>, input: VectorData, params: [Color]), register_node!(graphene_core::vector::SetFillNode<_>, input: VectorData, params: [Color]),
register_node!(graphene_core::vector::SetFillNode<_>, input: VectorData, params: [Option<Color>]), register_node!(graphene_core::vector::SetFillNode<_>, input: VectorData, params: [Option<Color>]),
register_node!(graphene_core::vector::SetFillNode<_>, input: VectorData, params: [graphene_std::vector::style::Gradient]), register_node!(graphene_core::vector::SetFillNode<_>, input: VectorData, params: [graphene_std::vector::style::Gradient]),
register_node!(graphene_core::vector::AssignColorsNode<_, _, _, _, _, _>, input: GraphicGroup, params: [bool, bool, graphene_std::vector::style::GradientStops, bool, bool, u32]), register_node!(graphene_core::vector::AssignColorsNode<_, _, _, _, _, _, _>, input: GraphicGroup, params: [bool, bool, graphene_std::vector::style::GradientStops, bool, bool, u32, u32]),
register_node!(graphene_core::vector::AssignColorsNode<_, _, _, _, _, _>, input: VectorData, params: [bool, bool, graphene_std::vector::style::GradientStops, bool, bool, u32]), register_node!(graphene_core::vector::AssignColorsNode<_, _, _, _, _, _, _>, input: VectorData, params: [bool, bool, graphene_std::vector::style::GradientStops, bool, bool, u32, u32]),
register_node!(graphene_core::vector::SetStrokeNode<_, _, _, _, _, _, _>, input: VectorData, params: [Option<graphene_core::Color>, f64, Vec<f64>, f64, graphene_core::vector::style::LineCap, graphene_core::vector::style::LineJoin, f64]), register_node!(graphene_core::vector::SetStrokeNode<_, _, _, _, _, _, _>, input: VectorData, params: [Option<graphene_core::Color>, f64, Vec<f64>, f64, graphene_core::vector::style::LineCap, graphene_core::vector::style::LineJoin, f64]),
register_node!(graphene_core::vector::RepeatNode<_, _, _>, input: VectorData, params: [DVec2, f64, u32]), register_node!(graphene_core::vector::RepeatNode<_, _, _>, input: VectorData, params: [DVec2, f64, u32]),
register_node!(graphene_core::vector::BoundingBoxNode, input: VectorData, params: []), register_node!(graphene_core::vector::BoundingBoxNode, input: VectorData, params: []),
@@ -748,10 +748,10 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
)], )],
register_node!(graphene_std::raster::SampleNode<_>, input: Footprint, params: [ImageFrame<Color>]), register_node!(graphene_std::raster::SampleNode<_>, input: Footprint, params: [ImageFrame<Color>]),
register_node!(graphene_std::raster::MandelbrotNode, input: Footprint, params: []), register_node!(graphene_std::raster::MandelbrotNode, input: Footprint, params: []),
async_node!(graphene_core::vector::CopyToPoints<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, Footprint => VectorData, () => f64, () => f64, () => f64, () => f64]), async_node!(graphene_core::vector::CopyToPoints<_, _, _, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, Footprint => VectorData, () => f64, () => f64, () => f64, () => u32, () => f64, () => u32]),
async_node!(graphene_core::vector::CopyToPoints<_, _, _, _, _, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => VectorData, Footprint => GraphicGroup, () => f64, () => f64, () => f64, () => f64]), async_node!(graphene_core::vector::CopyToPoints<_, _, _, _, _, _, _, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => VectorData, Footprint => GraphicGroup, () => f64, () => f64, () => f64, () => u32, () => f64, () => u32]),
async_node!(graphene_core::vector::SamplePoints<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, () => f64, () => f64, () => f64, () => bool, Footprint => Vec<f64>]), async_node!(graphene_core::vector::SamplePoints<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, () => f64, () => f64, () => f64, () => bool, Footprint => Vec<f64>]),
register_node!(graphene_core::vector::PoissonDiskPoints<_>, input: VectorData, params: [f64]), register_node!(graphene_core::vector::PoissonDiskPoints<_, _>, input: VectorData, params: [f64, u32]),
register_node!(graphene_core::vector::LengthsOfSegmentsOfSubpaths, input: VectorData, params: []), register_node!(graphene_core::vector::LengthsOfSegmentsOfSubpaths, input: VectorData, params: []),
register_node!(graphene_core::vector::SplinesFromPointsNode, input: VectorData, params: []), register_node!(graphene_core::vector::SplinesFromPointsNode, input: VectorData, params: []),
async_node!(graphene_core::vector::AreaNode<_>, input: (), output: f64, fn_params: [Footprint => VectorData]), async_node!(graphene_core::vector::AreaNode<_>, input: (), output: f64, fn_params: [Footprint => VectorData]),