mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-10-02 10:08:12 +08:00
WIP
This commit is contained in:
Generated
+2
-5
@@ -2842,12 +2842,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indoc"
|
name = "indoc"
|
||||||
version = "2.0.7"
|
version = "2.0.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
|
checksum = "f4c7245a08504955605670dbf141fceab975f15ca21570696aebe9d2e71576bd"
|
||||||
dependencies = [
|
|
||||||
"rustversion",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "inotify"
|
name = "inotify"
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use core_types::blending::BlendMode;
|
|||||||
use core_types::bounds::{BoundingBox, RenderBoundingBox};
|
use core_types::bounds::{BoundingBox, RenderBoundingBox};
|
||||||
use core_types::list::{ATTR_FILL, ATTR_STROKE, Item, List, ListDyn};
|
use core_types::list::{ATTR_FILL, ATTR_STROKE, Item, List, ListDyn};
|
||||||
use core_types::registry::types::{Angle, Length, Multiplier, Percentage, PixelLength, Progression, SeedValue};
|
use core_types::registry::types::{Angle, Length, Multiplier, Percentage, PixelLength, Progression, SeedValue};
|
||||||
use core_types::transform::{Footprint, Transform};
|
use core_types::transform::{ApplyTransform, Footprint, Transform};
|
||||||
use core_types::uuid::NodeId;
|
use core_types::uuid::NodeId;
|
||||||
use core_types::{
|
use core_types::{
|
||||||
ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, CloneVarArgs, Color, Context, Ctx, ExtractAll,
|
ATTR_BLEND_MODE, ATTR_CLIPPING_MASK, ATTR_EDITOR_LAYER_PATH, ATTR_EDITOR_MERGED_LAYERS, ATTR_OPACITY, ATTR_OPACITY_FILL, ATTR_TRANSFORM, CloneVarArgs, Color, Context, Ctx, ExtractAll,
|
||||||
@@ -38,6 +38,9 @@ trait VectorListIterMut {
|
|||||||
fn for_each_vector_mut(&mut self, f: impl FnMut(&mut Vector, DAffine2));
|
fn for_each_vector_mut(&mut self, f: impl FnMut(&mut Vector, DAffine2));
|
||||||
|
|
||||||
fn vector_count(&self) -> usize;
|
fn vector_count(&self) -> usize;
|
||||||
|
|
||||||
|
/// Iterates over a mutable reference to each vector item's transform, used by the transform-assignment nodes.
|
||||||
|
fn vector_transforms_iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut DAffine2>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VectorListIterMut for List<Graphic> {
|
impl VectorListIterMut for List<Graphic> {
|
||||||
@@ -54,6 +57,13 @@ impl VectorListIterMut for List<Graphic> {
|
|||||||
fn vector_count(&self) -> usize {
|
fn vector_count(&self) -> usize {
|
||||||
self.iter_element_values().filter_map(|element| element.as_vector()).map(|list| list.len()).sum()
|
self.iter_element_values().filter_map(|element| element.as_vector()).map(|list| list.len()).sum()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn vector_transforms_iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut DAffine2> {
|
||||||
|
// Grab only the direct children
|
||||||
|
self.iter_element_values_mut()
|
||||||
|
.filter_map(|graphic| graphic.as_vector_mut())
|
||||||
|
.flat_map(|vector_list| vector_list.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VectorListIterMut for List<Vector> {
|
impl VectorListIterMut for List<Vector> {
|
||||||
@@ -67,6 +77,10 @@ impl VectorListIterMut for List<Vector> {
|
|||||||
fn vector_count(&self) -> usize {
|
fn vector_count(&self) -> usize {
|
||||||
self.len()
|
self.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn vector_transforms_iter_mut(&mut self) -> impl DoubleEndedIterator<Item = &mut DAffine2> {
|
||||||
|
self.iter_attribute_values_mut_or_default::<DAffine2>(ATTR_TRANSFORM)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uniquely sets the fill and/or stroke style of every vector element to individual colors sampled along a chosen gradient.
|
/// Uniquely sets the fill and/or stroke style of every vector element to individual colors sampled along a chosen gradient.
|
||||||
@@ -134,6 +148,239 @@ where
|
|||||||
content
|
content
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[node_macro::node(category("Instancing"), path(core_types::vector))]
|
||||||
|
async fn assign_rotations<T: VectorListIterMut + 'n + Send>(
|
||||||
|
_: impl Ctx,
|
||||||
|
#[implementations(List<Graphic>, List<Vector>)] mut content: T,
|
||||||
|
#[range((0., 360.))]
|
||||||
|
#[default(360.)]
|
||||||
|
angle: Angle,
|
||||||
|
/// Whether to reverse the order.
|
||||||
|
reverse: bool,
|
||||||
|
/// Whether to randomize the rotation selection for each element.
|
||||||
|
#[default(true)]
|
||||||
|
randomize: bool,
|
||||||
|
/// The seed used for randomization.
|
||||||
|
seed: SeedValue,
|
||||||
|
#[range((-50., 50.))] bias: f64,
|
||||||
|
/// The number of elements to span across before repeating. A 0 value will span the entire range once.
|
||||||
|
repeat_every: u32,
|
||||||
|
) -> T {
|
||||||
|
let count = content.vector_count() as u32;
|
||||||
|
|
||||||
|
let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
|
||||||
|
|
||||||
|
let apply = |(index, transform): (usize, &mut DAffine2)| {
|
||||||
|
let factor = match randomize {
|
||||||
|
true => {
|
||||||
|
if bias.abs() < 1e-6 {
|
||||||
|
rng.random::<f64>()
|
||||||
|
} else {
|
||||||
|
(1. - rng.random::<f64>() * (1. - 2_f64.powf(bias))).log2() / bias
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false => match repeat_every {
|
||||||
|
0 => index as f64 / (count - 1).max(1) as f64,
|
||||||
|
1 => 0.,
|
||||||
|
_ => index as f64 % repeat_every as f64 / (repeat_every - 1) as f64,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let rotation_transform = DAffine2::from_angle(factor * angle.to_radians());
|
||||||
|
transform.left_apply_transform(&rotation_transform);
|
||||||
|
};
|
||||||
|
|
||||||
|
if reverse {
|
||||||
|
content.vector_transforms_iter_mut().rev().enumerate().for_each(apply);
|
||||||
|
} else {
|
||||||
|
content.vector_transforms_iter_mut().enumerate().for_each(apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
|
#[node_macro::node(category("Instancing"), path(core_types::vector))]
|
||||||
|
async fn assign_translations<T: VectorListIterMut + 'n + Send>(
|
||||||
|
_: impl Ctx,
|
||||||
|
#[implementations(List<Graphic>, List<Vector>)] mut content: T,
|
||||||
|
x_min: f64,
|
||||||
|
x_max: f64,
|
||||||
|
y_min: f64,
|
||||||
|
y_max: f64,
|
||||||
|
/// Whether to reverse the order.
|
||||||
|
reverse: bool,
|
||||||
|
/// Whether to randomize the translation selection for each element.
|
||||||
|
#[default(true)]
|
||||||
|
randomize: bool,
|
||||||
|
/// The seed used for randomization.
|
||||||
|
seed: SeedValue,
|
||||||
|
#[range((-50., 50.))] x_bias: f64,
|
||||||
|
#[range((-50., 50.))] y_bias: f64,
|
||||||
|
/// The number of elements to span across before repeating. A 0 value will span the entire range once.
|
||||||
|
repeat_every: u32,
|
||||||
|
) -> T {
|
||||||
|
let count = content.vector_count() as u32;
|
||||||
|
|
||||||
|
let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
|
||||||
|
|
||||||
|
let apply = |(index, transform): (usize, &mut DAffine2)| {
|
||||||
|
let (factor_x, factor_y) = match randomize {
|
||||||
|
true => {
|
||||||
|
let factor_x = if x_bias.abs() < 1e-6 {
|
||||||
|
rng.random::<f64>()
|
||||||
|
} else {
|
||||||
|
(1. - rng.random::<f64>() * (1. - 2_f64.powf(x_bias))).log2() / x_bias
|
||||||
|
};
|
||||||
|
let factor_y = if y_bias.abs() < 1e-6 {
|
||||||
|
rng.random::<f64>()
|
||||||
|
} else {
|
||||||
|
(1. - rng.random::<f64>() * (1. - 2_f64.powf(y_bias))).log2() / y_bias
|
||||||
|
};
|
||||||
|
(factor_x, factor_y)
|
||||||
|
}
|
||||||
|
false => match repeat_every {
|
||||||
|
0 => {
|
||||||
|
let factor = index as f64 / (count - 1).max(1) as f64;
|
||||||
|
(factor, factor)
|
||||||
|
}
|
||||||
|
1 => (0., 0.),
|
||||||
|
_ => {
|
||||||
|
let factor = index as f64 % repeat_every as f64 / (repeat_every - 1) as f64;
|
||||||
|
(factor, factor)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let translation = DVec2::new(x_min + (x_max - x_min) * factor_x, y_min + (y_max - y_min) * factor_y);
|
||||||
|
let translation_transform = DAffine2::from_translation(translation);
|
||||||
|
transform.left_apply_transform(&translation_transform);
|
||||||
|
};
|
||||||
|
|
||||||
|
if reverse {
|
||||||
|
content.vector_transforms_iter_mut().rev().enumerate().for_each(apply);
|
||||||
|
} else {
|
||||||
|
content.vector_transforms_iter_mut().enumerate().for_each(apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: decide if we want to keep both circular and non-circular versions
|
||||||
|
#[node_macro::node(category("Instancing"), path(core_types::vector))]
|
||||||
|
async fn assign_translations_circular<T: VectorListIterMut + 'n + Send>(
|
||||||
|
_: impl Ctx,
|
||||||
|
#[implementations(List<Graphic>, List<Vector>)] mut content: T,
|
||||||
|
radius_min: f64,
|
||||||
|
radius_max: f64,
|
||||||
|
#[default(-180.)] angle_min: Angle,
|
||||||
|
#[default(180.)] angle_max: Angle,
|
||||||
|
/// Whether to reverse the order.
|
||||||
|
reverse: bool,
|
||||||
|
/// Whether to randomize the translation selection for each element.
|
||||||
|
#[default(true)]
|
||||||
|
randomize: bool,
|
||||||
|
/// The seed used for randomization.
|
||||||
|
seed: SeedValue,
|
||||||
|
#[range((-50., 50.))] radius_bias: f64,
|
||||||
|
#[range((-50., 50.))] angle_bias: f64,
|
||||||
|
/// The number of elements to span across before repeating. A 0 value will span the entire range once.
|
||||||
|
repeat_every: u32,
|
||||||
|
) -> T {
|
||||||
|
let count = content.vector_count() as u32;
|
||||||
|
|
||||||
|
let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
|
||||||
|
|
||||||
|
let apply = |(index, transform): (usize, &mut DAffine2)| {
|
||||||
|
let (factor_angle, factor_radius) = match randomize {
|
||||||
|
true => {
|
||||||
|
let factor_angle = if angle_bias.abs() < 1e-6 {
|
||||||
|
rng.random::<f64>()
|
||||||
|
} else {
|
||||||
|
(1. - rng.random::<f64>() * (1. - 2_f64.powf(angle_bias))).log2() / angle_bias
|
||||||
|
};
|
||||||
|
let factor_radius = if radius_bias.abs() < 1e-6 {
|
||||||
|
rng.random::<f64>()
|
||||||
|
} else {
|
||||||
|
(1. - rng.random::<f64>() * (1. - 2_f64.powf(radius_bias))).log2() / radius_bias
|
||||||
|
};
|
||||||
|
(factor_angle, factor_radius)
|
||||||
|
}
|
||||||
|
false => match repeat_every {
|
||||||
|
0 => {
|
||||||
|
let factor = index as f64 / (count - 1).max(1) as f64;
|
||||||
|
(factor, factor)
|
||||||
|
}
|
||||||
|
1 => (0., 0.),
|
||||||
|
_ => {
|
||||||
|
let factor = index as f64 % repeat_every as f64 / (repeat_every - 1) as f64;
|
||||||
|
(factor, factor)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let angle = factor_angle * (angle_max.to_radians() - angle_min.to_radians()) + angle_min.to_radians();
|
||||||
|
let radius = radius_min + (radius_max - radius_min) * factor_radius.sqrt();
|
||||||
|
let translation = DVec2::new(angle.cos() * radius, angle.sin() * radius);
|
||||||
|
let translation_transform = DAffine2::from_translation(translation);
|
||||||
|
transform.left_apply_transform(&translation_transform);
|
||||||
|
};
|
||||||
|
|
||||||
|
if reverse {
|
||||||
|
content.vector_transforms_iter_mut().rev().enumerate().for_each(apply);
|
||||||
|
} else {
|
||||||
|
content.vector_transforms_iter_mut().enumerate().for_each(apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
|
#[node_macro::node(category("Instancing"), path(core_types::vector))]
|
||||||
|
async fn assign_scales<T: VectorListIterMut + 'n + Send>(
|
||||||
|
_: impl Ctx,
|
||||||
|
#[implementations(List<Graphic>, List<Vector>)] mut content: T,
|
||||||
|
#[default(0.5)] min_scale: f64,
|
||||||
|
#[default(2.)] max_scale: f64,
|
||||||
|
/// Whether to reverse the order.
|
||||||
|
reverse: bool,
|
||||||
|
/// Whether to randomize the scale selection for each element.
|
||||||
|
#[default(true)]
|
||||||
|
randomize: bool,
|
||||||
|
/// The seed used for randomization.
|
||||||
|
seed: SeedValue,
|
||||||
|
#[range((-50., 50.))] bias: f64,
|
||||||
|
/// The number of elements to span across before repeating. A 0 value will span the entire range once.
|
||||||
|
repeat_every: u32,
|
||||||
|
) -> T {
|
||||||
|
let count = content.vector_count() as u32;
|
||||||
|
|
||||||
|
let mut rng = rand::rngs::StdRng::seed_from_u64(seed as u64);
|
||||||
|
|
||||||
|
let apply = |(index, transform): (usize, &mut DAffine2)| {
|
||||||
|
let factor = match randomize {
|
||||||
|
true => {
|
||||||
|
if bias.abs() < 1e-6 {
|
||||||
|
rng.random::<f64>()
|
||||||
|
} else {
|
||||||
|
(1. - rng.random::<f64>() * (1. - 2_f64.powf(bias))).log2() / bias
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false => match repeat_every {
|
||||||
|
0 => index as f64 / (count - 1).max(1) as f64,
|
||||||
|
1 => 0.,
|
||||||
|
_ => index as f64 % repeat_every as f64 / (repeat_every - 1) as f64,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
let scale_value = min_scale + (max_scale - min_scale) * factor;
|
||||||
|
let scale_transform = DAffine2::from_scale(DVec2::splat(scale_value));
|
||||||
|
transform.apply_transform(&scale_transform);
|
||||||
|
};
|
||||||
|
|
||||||
|
if reverse {
|
||||||
|
content.vector_transforms_iter_mut().rev().enumerate().for_each(apply);
|
||||||
|
} else {
|
||||||
|
content.vector_transforms_iter_mut().enumerate().for_each(apply);
|
||||||
|
}
|
||||||
|
|
||||||
|
content
|
||||||
|
}
|
||||||
|
|
||||||
/// Applies a fill style to the vector content, giving an appearance to the area within the interior of the geometry.
|
/// Applies a fill style to the vector content, giving an appearance to the area within the interior of the geometry.
|
||||||
#[node_macro::node(category("Vector: Style"), path(graphene_core::vector), properties("fill_properties"))]
|
#[node_macro::node(category("Vector: Style"), path(graphene_core::vector), properties("fill_properties"))]
|
||||||
async fn fill<F: Into<Fill> + 'n + Send, V: VectorListIterMut + 'n + Send>(
|
async fn fill<F: Into<Fill> + 'n + Send, V: VectorListIterMut + 'n + Send>(
|
||||||
|
|||||||
Reference in New Issue
Block a user