mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
New node: Assign Colors (#1938)
* New node: Assign Colors * Simplify the Procedural String Lights demo artwork * Add "Group" node to the node catalog * Better comment styling in profiling action
This commit is contained in:
@@ -55,6 +55,22 @@ impl core::hash::Hash for GraphicGroup {
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicGroup {
|
||||
pub const EMPTY: Self = Self {
|
||||
elements: Vec::new(),
|
||||
transform: DAffine2::IDENTITY,
|
||||
alpha_blending: AlphaBlending::new(),
|
||||
};
|
||||
|
||||
pub fn new(elements: Vec<GraphicElement>) -> Self {
|
||||
Self {
|
||||
elements,
|
||||
transform: DAffine2::IDENTITY,
|
||||
alpha_blending: AlphaBlending::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The possible forms of graphical content held in a Vec by the `elements` field of [`GraphicElement`].
|
||||
/// Can be another recursively nested [`GraphicGroup`], a [`VectorData`] shape, an [`ImageFrame`], or an [`Artboard`].
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||
@@ -74,6 +90,50 @@ impl Default for GraphicElement {
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicElement {
|
||||
pub fn as_group(&self) -> Option<&GraphicGroup> {
|
||||
match self {
|
||||
GraphicElement::GraphicGroup(group) => Some(group),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_group_mut(&mut self) -> Option<&mut GraphicGroup> {
|
||||
match self {
|
||||
GraphicElement::GraphicGroup(group) => Some(group),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vector_data(&self) -> Option<&VectorData> {
|
||||
match self {
|
||||
GraphicElement::VectorData(data) => Some(data),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_vector_data_mut(&mut self) -> Option<&mut VectorData> {
|
||||
match self {
|
||||
GraphicElement::VectorData(data) => Some(data),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raster(&self) -> Option<&Raster> {
|
||||
match self {
|
||||
GraphicElement::Raster(raster) => Some(raster),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_raster_mut(&mut self) -> Option<&mut Raster> {
|
||||
match self {
|
||||
GraphicElement::Raster(raster) => Some(raster),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Hash, PartialEq, DynAny)]
|
||||
pub enum Raster {
|
||||
/// A bitmap image with a finite position and extent, equivalent to the SVG <image> tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image
|
||||
@@ -301,11 +361,3 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GraphicGroup {
|
||||
pub const EMPTY: Self = Self {
|
||||
elements: Vec::new(),
|
||||
transform: DAffine2::IDENTITY,
|
||||
alpha_blending: AlphaBlending::new(),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -60,6 +60,10 @@ impl GradientStops {
|
||||
|
||||
Color::BLACK
|
||||
}
|
||||
|
||||
pub fn reversed(&self) -> Self {
|
||||
Self(self.0.iter().rev().map(|(position, color)| (1. - position, *color)).collect())
|
||||
}
|
||||
}
|
||||
|
||||
/// A gradient fill.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::misc::CentroidType;
|
||||
use super::style::{Fill, Stroke};
|
||||
use super::style::{Fill, GradientStops, Stroke};
|
||||
use super::{PointId, SegmentId, StrokeId, VectorData};
|
||||
use crate::renderer::GraphicElementRendered;
|
||||
use crate::transform::{Footprint, Transform, TransformMut};
|
||||
@@ -9,6 +9,78 @@ use bezier_rs::{Cap, Join, Subpath, SubpathTValue, TValue};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use rand::{Rng, SeedableRng};
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct AssignColorsNode<Fill, Stroke, Gradient, Reverse, Randomize, RepeatEvery> {
|
||||
fill: Fill,
|
||||
stroke: Stroke,
|
||||
gradient: Gradient,
|
||||
reverse: Reverse,
|
||||
randomize: Randomize,
|
||||
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 {
|
||||
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);
|
||||
|
||||
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 {
|
||||
let mut vector_data_list: Vec<_> = vector_data
|
||||
.region_bezier_paths()
|
||||
.map(|(_, subpath)| {
|
||||
let mut vector = VectorData::from_subpath(subpath);
|
||||
|
||||
vector.style = vector_data.style.clone();
|
||||
|
||||
crate::GraphicElement::VectorData(Box::new(vector))
|
||||
})
|
||||
.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);
|
||||
|
||||
let mut group = GraphicGroup::new(vector_data_list);
|
||||
group.transform = vector_data.transform;
|
||||
group.alpha_blending = vector_data.alpha_blending;
|
||||
|
||||
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 };
|
||||
|
||||
let mut rng = rand::rngs::StdRng::seed_from_u64(0);
|
||||
|
||||
for (i, vector_data) in vector_data.enumerate() {
|
||||
let factor = match randomize {
|
||||
true => rng.gen::<f64>(),
|
||||
false => match repeat_every {
|
||||
0 => i as f64 / (length - 1) as f64,
|
||||
1 => 0.,
|
||||
_ => i as f64 % repeat_every as f64 / (repeat_every - 1) as f64,
|
||||
},
|
||||
};
|
||||
|
||||
let color = gradient.evalute(factor);
|
||||
|
||||
if fill {
|
||||
vector_data.style.set_fill(Fill::Solid(color));
|
||||
}
|
||||
if stroke {
|
||||
if let Some(stroke) = vector_data.style.stroke().and_then(|stroke| stroke.with_color(&Some(color))) {
|
||||
vector_data.style.set_stroke(stroke);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct SetFillNode<Fill> {
|
||||
fill: Fill,
|
||||
|
||||
Reference in New Issue
Block a user