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

File diff suppressed because one or more lines are too long

View file

@ -3521,7 +3521,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
category: "Vector: Style",
node_template: NodeTemplate {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_core::vector::AssignColorsNode<_, _, _, _, _, _>"),
implementation: DocumentNodeImplementation::proto("graphene_core::vector::AssignColorsNode<_, _, _, _, _, _, _>"),
inputs: vec![
NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroup::default()), true),
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::U32(0), false),
NodeInput::value(TaggedValue::U32(0), false),
],
..Default::default()
},
@ -3541,6 +3542,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
"Gradient".to_string(),
"Reverse".to_string(),
"Randomize".to_string(),
"Seed".to_string(),
"Repeat Every".to_string(),
],
output_names: vec!["Vector Group".to_string()],
@ -3745,14 +3747,16 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
node_template: NodeTemplate {
document_node: DocumentNode {
// 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![
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(0.), false),
NodeInput::value(TaggedValue::U32(0), false),
NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::U32(0), false),
],
manual_composition: Some(concrete!(Footprint)),
..Default::default()
@ -3764,7 +3768,9 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
"Random Scale Min".to_string(),
"Random Scale Max".to_string(),
"Random Scale Bias".to_string(),
"Random Scale Seed".to_string(),
"Random Rotation".to_string(),
"Random Rotation Seed".to_string(),
],
output_names: vec!["Vector".to_string()],
..Default::default()
@ -3876,8 +3882,12 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(1), 0)],
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(graphene_core::vector::VectorData), 0), NodeInput::network(concrete!(f64), 1)],
implementation: DocumentNodeImplementation::proto("graphene_core::vector::PoissonDiskPoints<_>"),
inputs: vec![
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()
},
DocumentNode {
@ -3896,6 +3906,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
inputs: vec![
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
NodeInput::value(TaggedValue::F64(10.), false),
NodeInput::value(TaggedValue::U32(0), false),
],
..Default::default()
},
@ -3926,7 +3937,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
..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()],
..Default::default()
},

View file

@ -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> {
let horizontal_gap = (output_position.x - input_position.x).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
// if ((verticalOut && vertical_in) || (!verticalOut && !vertical_in && vertical_gap === 0)) {
// return [

View file

@ -122,7 +122,7 @@ fn text_area_widget(document_node: &DocumentNode, node_id: NodeId, index: usize,
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 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() {
widgets.extend_from_slice(&[
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_commit(commit_value)
.widget_holder(),
@ -372,7 +373,7 @@ fn vec2_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name
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 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() {
widgets.extend_from_slice(&[
Separator::new(SeparatorType::Unrelated).widget_holder(),
text_props
text_input
.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))
.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> {
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 }]
}
@ -1065,7 +1066,7 @@ pub fn noise_pattern_properties(document_node: &DocumentNode, node_id: NodeId, _
// All
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 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> {
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 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![
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 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 }]
}
@ -1250,18 +1251,20 @@ pub fn assign_colors_properties(document_node: &DocumentNode, node_id: NodeId, _
let gradient_index = 3;
let reverse_index = 4;
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 stroke_row = bool_widget(document_node, node_id, stroke_index, "Stroke", 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", CheckboxInput::default(), 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 randomize_row = bool_widget(document_node, node_id, randomize_index, "Randomize", true);
let reverse_row = bool_widget(document_node, node_id, reverse_index, "Reverse", CheckboxInput::default(), true);
let randomize_enabled = if let Some(&TaggedValue::Bool(randomize_enabled)) = &document_node.inputs[randomize_index].as_value() {
randomize_enabled
} else {
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(
document_node,
node_id,
@ -1277,6 +1280,7 @@ pub fn assign_colors_properties(document_node: &DocumentNode, node_id: NodeId, _
gradient_row,
LayoutGroup::Row { widgets: reverse_row },
LayoutGroup::Row { widgets: randomize_row },
LayoutGroup::Row { widgets: seed_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> {
// Monochrome
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() {
monochrome_choice
} else {
@ -1721,7 +1725,7 @@ pub fn rectangle_properties(document_node: &DocumentNode, node_id: NodeId, _cont
}
// 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![
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> {
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 }]
}
@ -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")
};
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")
};
let image_creativity = {
@ -2286,7 +2290,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
// }
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(
"Postprocess human (or human-like) faces to look subtly less distorted.\n\
\n\
@ -2294,7 +2298,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte
)
};
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")
};
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> {
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(
document_node,
node_id,
2,
random_scale_min_index,
"Random Scale Min",
NumberInput::default().min(0.).mode_range().range_min(Some(0.)).range_max(Some(2.)).unit("x"),
true,
@ -2426,7 +2438,7 @@ pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId,
let random_scale_max = number_widget(
document_node,
node_id,
3,
random_scale_max_index,
"Random Scale Max",
NumberInput::default().min(0.).mode_range().range_min(Some(0.)).range_max(Some(2.)).unit("x"),
true,
@ -2434,13 +2446,22 @@ pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId,
let random_scale_bias = number_widget(
document_node,
node_id,
4,
random_scale_bias_index,
"Random Scale Bias",
NumberInput::default().mode_range().range_min(Some(-50.)).range_max(Some(50.)),
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![
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_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)"),
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_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 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 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![
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> {
let separation_disk_diameter_index = 1;
let seed_index = 2;
let spacing = number_widget(
document_node,
node_id,
1,
separation_disk_diameter_index,
"Separation Disk Diameter",
NumberInput::default().min(0.01).mode_range().range_min(Some(1.)).range_max(Some(100.)),
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> {
@ -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 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 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 };

View file

@ -10,28 +10,40 @@ use glam::{DAffine2, DVec2};
use rand::{Rng, SeedableRng};
#[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,
stroke: Stroke,
gradient: Gradient,
reverse: Reverse,
randomize: Randomize,
seed: Seed,
repeat_every: RepeatEvery,
}
#[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 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());
assign_colors(list, fill, stroke, gradient, reverse, randomize, repeat_every);
assign_colors(
list,
AlignColorsOptions {
fill,
stroke,
gradient,
reverse,
randomize,
seed,
repeat_every,
},
);
group
}
#[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
.region_bezier_paths()
.map(|(_, subpath)| {
@ -44,7 +56,18 @@ fn assign_colors_node(vector_data: VectorData, fill: bool, stroke: bool, gradien
.collect();
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);
group.transform = vector_data.transform;
@ -53,27 +76,37 @@ fn assign_colors_node(vector_data: VectorData, fill: bool, stroke: bool, gradien
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) {
let gradient = if reverse { gradient.reversed() } else { gradient };
struct AlignColorsOptions {
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() {
let factor = match randomize {
let factor = match options.randomize {
true => rng.gen::<f64>(),
false => match repeat_every {
false => match options.repeat_every {
0 => i as f64 / (length - 1) as f64,
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);
if fill {
if options.fill {
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))) {
vector_data.style.set_stroke(stroke);
}
@ -273,15 +306,18 @@ impl ConcatElement for GraphicGroup {
}
#[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,
instance: Instance,
random_scale_min: RandomScaleMin,
random_scale_max: RandomScaleMax,
random_scale_bias: RandomScaleBias,
random_scale_seed: RandomScaleSeed,
random_rotation: RandomRotation,
random_rotation_seed: RandomRotationSeed,
}
#[allow(clippy::too_many_arguments)]
#[node_macro::node_fn(CopyToPoints)]
async fn copy_to_points<I: GraphicElementRendered + Default + ConcatElement + TransformMut + Send>(
footprint: Footprint,
@ -290,7 +326,9 @@ async fn copy_to_points<I: GraphicElementRendered + Default + ConcatElement + Tr
random_scale_min: f64,
random_scale_max: f64,
random_scale_bias: f64,
random_scale_seed: u32,
random_rotation: f64,
random_rotation_seed: u32,
) -> I {
let points = self.points.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_center = -0.5 * (instance_bounding_box[0] + instance_bounding_box[1]);
let mut scale_rng = rand::rngs::StdRng::seed_from_u64(0);
let mut rotation_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(random_rotation_seed as u64);
let do_scale = random_scale_difference.abs() > 1e-6;
let do_rotation = random_rotation.abs() > 1e-6;
@ -425,13 +463,14 @@ async fn sample_points(
}
#[derive(Debug, Clone, Copy)]
pub struct PoissonDiskPoints<SeparationDiskDiameter> {
pub struct PoissonDiskPoints<SeparationDiskDiameter, Seed> {
separation_disk_diameter: SeparationDiskDiameter,
seed: Seed,
}
#[node_macro::node_fn(PoissonDiskPoints)]
fn poisson_disk_points(vector_data: VectorData, separation_disk_diameter: f64) -> VectorData {
let mut rng = rand::rngs::StdRng::seed_from_u64(0);
fn poisson_disk_points(vector_data: VectorData, separation_disk_diameter: f64, seed: u32) -> VectorData {
let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
let mut result = VectorData::empty();
for mut subpath in vector_data.stroke_bezier_paths() {
if subpath.manipulator_groups().len() < 3 {
@ -745,7 +784,9 @@ mod test {
random_scale_min: FutureWrapperNode(ClonedNode(1.)),
random_scale_max: FutureWrapperNode(ClonedNode(1.)),
random_scale_bias: FutureWrapperNode(ClonedNode(0.)),
random_scale_seed: FutureWrapperNode(ClonedNode(0)),
random_rotation: FutureWrapperNode(ClonedNode(0.)),
random_rotation_seed: FutureWrapperNode(ClonedNode(0)),
}
.eval(Footprint::default())
.await;
@ -798,6 +839,7 @@ mod test {
fn poisson() {
let sample_points = PoissonDiskPoints {
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.)));
assert!(

View file

@ -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: [Option<Color>]),
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: VectorData, 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, 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::RepeatNode<_, _, _>, input: VectorData, params: [DVec2, f64, u32]),
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::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: GraphicGroup, fn_params: [Footprint => VectorData, Footprint => GraphicGroup, () => 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, () => u32, () => f64, () => u32]),
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::SplinesFromPointsNode, input: VectorData, params: []),
async_node!(graphene_core::vector::AreaNode<_>, input: (), output: f64, fn_params: [Footprint => VectorData]),