mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 14:18:04 +08:00
Make the node graph use Table<GradientStops> instead of GradientStops (#3837)
* Switch from GradientStops to Table<GradientStops> in all nodes * Remove TaggedValue::ColorNotInTable * Fix bug Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> * Add migrations * Fix default gradient on empty table * Update demo artwork --------- Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
This commit is contained in:
2
demo-artwork/changing-seasons.graphite
generated
2
demo-artwork/changing-seasons.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/isometric-fountain.graphite
generated
2
demo-artwork/isometric-fountain.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/marbled-mandelbrot.graphite
generated
2
demo-artwork/marbled-mandelbrot.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/painted-dreams.graphite
generated
2
demo-artwork/painted-dreams.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/parametric-dunescape.graphite
generated
2
demo-artwork/parametric-dunescape.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/procedural-string-lights.graphite
generated
2
demo-artwork/procedural-string-lights.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/red-dress.graphite
generated
2
demo-artwork/red-dress.graphite
generated
File diff suppressed because one or more lines are too long
2
demo-artwork/valley-of-spires.graphite
generated
2
demo-artwork/valley-of-spires.graphite
generated
File diff suppressed because one or more lines are too long
@@ -214,19 +214,19 @@ pub(crate) fn property_from_type(
|
||||
Some(x) if x == TypeId::of::<String>() => text_widget(default_info).into(),
|
||||
Some(x) if x == TypeId::of::<DVec2>() => vec2_widget(default_info, "X", "Y", "", None, false),
|
||||
Some(x) if x == TypeId::of::<DAffine2>() => transform_widget(default_info, &mut extra_widgets),
|
||||
Some(x) if x == TypeId::of::<Color>() => color_widget(default_info, ColorInput::default()),
|
||||
Some(x) if x == TypeId::of::<Option<Color>>() => color_widget(default_info, ColorInput::default()),
|
||||
// ==========================
|
||||
// PRIMITIVE COLLECTION TYPES
|
||||
// ==========================
|
||||
Some(x) if x == TypeId::of::<Vec<f64>>() => array_of_number_widget(default_info, TextInput::default()).into(),
|
||||
Some(x) if x == TypeId::of::<Vec<DVec2>>() => array_of_vec2_widget(default_info, TextInput::default()).into(),
|
||||
// ===========
|
||||
// TABLE TYPES
|
||||
// ===========
|
||||
Some(x) if x == TypeId::of::<Table<Color>>() => color_widget(default_info, ColorInput::default().allow_none(true)),
|
||||
Some(x) if x == TypeId::of::<Table<GradientStops>>() => color_widget(default_info, ColorInput::default().allow_none(false)),
|
||||
// ============
|
||||
// STRUCT TYPES
|
||||
// ============
|
||||
Some(x) if x == TypeId::of::<Table<Color>>() => color_widget(default_info, ColorInput::default().allow_none(true)),
|
||||
Some(x) if x == TypeId::of::<Table<GradientStops>>() => color_widget(default_info, ColorInput::default().allow_none(false)),
|
||||
Some(x) if x == TypeId::of::<GradientStops>() => color_widget(default_info, ColorInput::default().allow_none(false)),
|
||||
Some(x) if x == TypeId::of::<Font>() => font_widget(default_info),
|
||||
Some(x) if x == TypeId::of::<Curve>() => curve_widget(default_info),
|
||||
Some(x) if x == TypeId::of::<Footprint>() => footprint_widget(default_info, &mut extra_widgets),
|
||||
@@ -1145,14 +1145,6 @@ pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button:
|
||||
|
||||
// Add the color input
|
||||
match &**tagged_value {
|
||||
TaggedValue::ColorNotInTable(color) => widgets.push(
|
||||
color_button
|
||||
.value(FillChoice::Solid(*color))
|
||||
.allow_none(false)
|
||||
.on_update(update_value(|input: &ColorInput| TaggedValue::ColorNotInTable(input.value.as_solid().unwrap()), node_id, index))
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
),
|
||||
TaggedValue::Color(color_table) => widgets.push(
|
||||
color_button
|
||||
.value(match color_table.iter().next() {
|
||||
@@ -1171,7 +1163,7 @@ pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button:
|
||||
color_button
|
||||
.value(match gradient_table.iter().next() {
|
||||
Some(row) => FillChoice::Gradient(row.element.clone()),
|
||||
None => FillChoice::None,
|
||||
None => FillChoice::Gradient(GradientStops::default()),
|
||||
})
|
||||
.on_update(update_value(
|
||||
|input: &ColorInput| TaggedValue::GradientTable(input.value.as_gradient().iter().map(|&gradient| TableRow::new_from_element(gradient.clone())).collect()),
|
||||
@@ -1181,18 +1173,7 @@ pub fn color_widget(parameter_widgets_info: ParameterWidgetsInfo, color_button:
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
),
|
||||
TaggedValue::GradientStops(gradient_stops) => widgets.push(
|
||||
color_button
|
||||
.value(FillChoice::Gradient(gradient_stops.clone()))
|
||||
.on_update(update_value(
|
||||
|input: &ColorInput| TaggedValue::GradientStops(input.value.as_gradient().cloned().unwrap_or_default()),
|
||||
node_id,
|
||||
index,
|
||||
))
|
||||
.on_commit(commit_value)
|
||||
.widget_instance(),
|
||||
),
|
||||
x => warn!("Colour {x:?}"),
|
||||
x => warn!("Color {x:?}"),
|
||||
}
|
||||
|
||||
LayoutGroup::Row { widgets }
|
||||
|
||||
@@ -35,7 +35,7 @@ impl FrontendGraphDataType {
|
||||
TaggedValue::Raster(_) => Self::Raster,
|
||||
TaggedValue::Vector(_) => Self::Vector,
|
||||
TaggedValue::Color(_) => Self::Color,
|
||||
TaggedValue::Gradient(_) | TaggedValue::GradientStops(_) | TaggedValue::GradientTable(_) => Self::Gradient,
|
||||
TaggedValue::Gradient(_) | TaggedValue::GradientTable(_) => Self::Gradient,
|
||||
TaggedValue::String(_) | TaggedValue::VecString(_) => Self::Typography,
|
||||
_ => Self::General,
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ impl TypeSource {
|
||||
TaggedValue::Raster(_) => FrontendGraphDataType::Raster,
|
||||
TaggedValue::Vector(_) => FrontendGraphDataType::Vector,
|
||||
TaggedValue::Color(_) => FrontendGraphDataType::Color,
|
||||
TaggedValue::Gradient(_) | TaggedValue::GradientStops(_) | TaggedValue::GradientTable(_) => FrontendGraphDataType::Gradient,
|
||||
TaggedValue::Gradient(_) | TaggedValue::GradientTable(_) => FrontendGraphDataType::Gradient,
|
||||
TaggedValue::String(_) => FrontendGraphDataType::Typography,
|
||||
_ => FrontendGraphDataType::General,
|
||||
},
|
||||
|
||||
@@ -282,13 +282,15 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
|
||||
node: graphene_std::math_nodes::footprint_value::IDENTIFIER,
|
||||
aliases: &["graphene_math_nodes::FootprintValueNode", "graphene_core::ops::FootprintValueNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::math_nodes::gradient_table_value::IDENTIFIER,
|
||||
aliases: &["graphene_math_nodes::GradientTableValueNode", "graphene_core::ops::GradientTableValueNode"],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::math_nodes::gradient_value::IDENTIFIER,
|
||||
aliases: &["graphene_math_nodes::GradientValueNode", "graphene_core::ops::GradientValueNode"],
|
||||
aliases: &[
|
||||
"graphene_math_nodes::GradientValueNode",
|
||||
"graphene_core::ops::GradientValueNode",
|
||||
"graphene_math_nodes::GradientTableValueNode",
|
||||
"graphene_core::ops::GradientTableValueNode",
|
||||
"math_nodes::GradientTableValueNode",
|
||||
],
|
||||
},
|
||||
NodeReplacement {
|
||||
node: graphene_std::math_nodes::greater_than::IDENTIFIER,
|
||||
|
||||
@@ -26,6 +26,7 @@ use std::hash::Hash;
|
||||
use std::marker::PhantomData;
|
||||
use std::str::FromStr;
|
||||
pub use std::sync::Arc;
|
||||
use text_nodes::vector_types::GradientStop;
|
||||
|
||||
pub struct TaggedValueTypeError;
|
||||
|
||||
@@ -182,7 +183,6 @@ tagged_value! {
|
||||
U64(u64),
|
||||
Bool(bool),
|
||||
String(String),
|
||||
ColorNotInTable(Color),
|
||||
// ========================
|
||||
// LISTS OF PRIMITIVE TYPES
|
||||
// ========================
|
||||
@@ -209,8 +209,10 @@ tagged_value! {
|
||||
#[serde(alias = "ArtboardGroup")]
|
||||
Artboard(Table<Artboard>),
|
||||
#[serde(deserialize_with = "core_types::misc::migrate_color")] // TODO: Eventually remove this migration document upgrade code
|
||||
#[serde(alias = "ColorTable", alias = "OptionalColor")]
|
||||
#[serde(alias = "ColorTable", alias = "OptionalColor", alias = "ColorNotInTable")]
|
||||
Color(Table<Color>),
|
||||
#[serde(deserialize_with = "graphic_types::vector_types::gradient::migrate_gradient_stops")] // TODO: Eventually remove this migration document upgrade code
|
||||
#[serde(alias = "GradientPositions", alias = "GradientStops")]
|
||||
GradientTable(Table<GradientStops>),
|
||||
// ============
|
||||
// STRUCT TYPES
|
||||
@@ -222,8 +224,6 @@ tagged_value! {
|
||||
DAffine2(DAffine2),
|
||||
Stroke(graphic_types::vector_types::vector::style::Stroke),
|
||||
Gradient(graphic_types::vector_types::vector::style::Gradient),
|
||||
#[serde(alias = "GradientPositions")] // TODO: Eventually remove this alias document upgrade code
|
||||
GradientStops(GradientStops),
|
||||
Font(text_nodes::Font),
|
||||
BrushStrokes(Vec<BrushStroke>),
|
||||
BrushCache(BrushCache),
|
||||
@@ -333,6 +333,35 @@ impl TaggedValue {
|
||||
None
|
||||
}
|
||||
|
||||
fn to_gradient(input: &str) -> Option<GradientStops> {
|
||||
// String syntax: (e.g. "000000ff, ff0000ff")
|
||||
let stops = input.split(',').filter_map(|s| to_color(s.trim())).collect::<Vec<_>>();
|
||||
if stops.len() == 1 {
|
||||
Some(GradientStops::new(vec![
|
||||
GradientStop {
|
||||
position: 0.,
|
||||
midpoint: 0.5,
|
||||
color: stops[0],
|
||||
},
|
||||
GradientStop {
|
||||
position: 1.,
|
||||
midpoint: 0.5,
|
||||
color: stops[0],
|
||||
},
|
||||
]))
|
||||
} else if stops.len() >= 2 {
|
||||
let step = 1. / (stops.len() - 1) as f64;
|
||||
Some(GradientStops::new(stops.into_iter().enumerate().map(|(i, color)| GradientStop {
|
||||
position: i as f64 * step,
|
||||
midpoint: 0.5,
|
||||
color,
|
||||
})))
|
||||
} else {
|
||||
log::error!("Invalid default value gradient string: {input}");
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn to_reference_point(input: &str) -> Option<ReferencePoint> {
|
||||
let mut choices = input.split("::");
|
||||
let (first, second) = (choices.next()?.trim(), choices.next()?.trim());
|
||||
@@ -375,9 +404,8 @@ impl TaggedValue {
|
||||
() if ty == TypeId::of::<u32>() => FromStr::from_str(string).map(TaggedValue::U32).ok()?,
|
||||
() if ty == TypeId::of::<DVec2>() => to_dvec2(string).map(TaggedValue::DVec2)?,
|
||||
() if ty == TypeId::of::<bool>() => FromStr::from_str(string).map(TaggedValue::Bool).ok()?,
|
||||
() if ty == TypeId::of::<Color>() => to_color(string).map(TaggedValue::ColorNotInTable)?,
|
||||
() if ty == TypeId::of::<Option<Color>>() => TaggedValue::ColorNotInTable(to_color(string)?),
|
||||
() if ty == TypeId::of::<Table<Color>>() => to_color(string).map(|color| TaggedValue::Color(Table::new_from_element(color)))?,
|
||||
() if ty == TypeId::of::<Table<GradientStops>>() => to_gradient(string).map(|color| TaggedValue::GradientTable(Table::new_from_element(color)))?,
|
||||
() if ty == TypeId::of::<Fill>() => to_color(string).map(|color| TaggedValue::Fill(Fill::solid(color)))?,
|
||||
() if ty == TypeId::of::<ReferencePoint>() => to_reference_point(string).map(TaggedValue::ReferencePoint)?,
|
||||
_ => return None,
|
||||
@@ -537,8 +565,3 @@ mod fake_hash {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_construct_color() {
|
||||
assert_eq!(TaggedValue::from_type(&concrete!(Color)).unwrap(), TaggedValue::ColorNotInTable(Color::default()));
|
||||
}
|
||||
|
||||
@@ -94,7 +94,6 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::StrokeAlign]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Stroke]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::style::Gradient]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => GradientStops]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Vec<graphene_std::uuid::NodeId>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Box<graphene_std::vector::VectorModification>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_std::vector::misc::CentroidType]),
|
||||
@@ -157,7 +156,6 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Table<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Image<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Table<GradientStops>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => GradientStops]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Vec<DVec2>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Vec<NodeId>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Vec<f64>]),
|
||||
@@ -183,7 +181,6 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Table<Raster<GPU>>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Option<f64>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Color]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Option<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => [f64; 4]]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Graphic]),
|
||||
|
||||
@@ -12,11 +12,8 @@ use core_types::uuid::{NodeId, generate_uuid};
|
||||
use dyn_any::DynAny;
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphic_types::Vector;
|
||||
use graphic_types::raster_types::BitmapMut;
|
||||
use graphic_types::raster_types::Image;
|
||||
use graphic_types::raster_types::{CPU, GPU, Raster};
|
||||
use graphic_types::vector_types::gradient::GradientStops;
|
||||
use graphic_types::vector_types::gradient::GradientType;
|
||||
use graphic_types::raster_types::{BitmapMut, CPU, GPU, Image, Raster};
|
||||
use graphic_types::vector_types::gradient::{GradientStops, GradientType};
|
||||
use graphic_types::vector_types::subpath::Subpath;
|
||||
use graphic_types::vector_types::vector::click_target::{ClickTarget, FreePoint};
|
||||
use graphic_types::vector_types::vector::style::{Fill, PaintOrder, RenderMode, Stroke, StrokeAlign};
|
||||
|
||||
@@ -447,6 +447,24 @@ impl Gradient {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Eventually remove this migration document upgrade code
|
||||
pub fn migrate_gradient_stops<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<core_types::table::Table<GradientStops>, D::Error> {
|
||||
use core_types::table::Table;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(serde::Deserialize)]
|
||||
#[serde(untagged)]
|
||||
enum GradientStopsFormat {
|
||||
GradientStops(GradientStops),
|
||||
GradientTable(Table<GradientStops>),
|
||||
}
|
||||
|
||||
Ok(match GradientStopsFormat::deserialize(deserializer)? {
|
||||
GradientStopsFormat::GradientStops(stops) => Table::new_from_element(stops),
|
||||
GradientStopsFormat::GradientTable(table) => table,
|
||||
})
|
||||
}
|
||||
|
||||
impl core_types::bounds::BoundingBox for GradientStops {
|
||||
fn bounding_box(&self, _transform: DAffine2, _include_stroke: bool) -> core_types::bounds::RenderBoundingBox {
|
||||
core_types::bounds::RenderBoundingBox::Infinite
|
||||
|
||||
@@ -1455,11 +1455,9 @@ mod tests {
|
||||
() -> Table<Raster<CPU>>,
|
||||
() -> Table<Color>,
|
||||
() -> Table<GradientStops>,
|
||||
() -> GradientStops,
|
||||
Footprint -> Table<Raster<CPU>>,
|
||||
Footprint -> Table<Color>,
|
||||
Footprint -> Table<GradientStops>,
|
||||
Footprint -> GradientStops,
|
||||
)]
|
||||
image: impl Node<F, Output = T>,
|
||||
) -> T {
|
||||
|
||||
@@ -3,7 +3,8 @@ use core_types::transform::Footprint;
|
||||
use core_types::uuid::NodeId;
|
||||
use core_types::{CloneVarArgs, Color, Context, Ctx, ExtractAll, ExtractAnimationTime, ExtractPointerPosition, ExtractRealTime, OwnedContextImpl};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphic_types::{Artboard, Graphic, Vector, vector_types::GradientStops};
|
||||
use graphic_types::vector_types::GradientStops;
|
||||
use graphic_types::{Artboard, Graphic, Vector};
|
||||
use raster_types::{CPU, GPU, Raster};
|
||||
|
||||
const DAY: f64 = 1000. * 3600. * 24.;
|
||||
@@ -84,7 +85,6 @@ async fn quantize_real_time<T>(
|
||||
Context -> Table<Color>,
|
||||
Context -> Table<Artboard>,
|
||||
Context -> Table<GradientStops>,
|
||||
Context -> GradientStops,
|
||||
Context -> (),
|
||||
)]
|
||||
value: impl Node<'n, Context<'static>, Output = T>,
|
||||
@@ -128,7 +128,6 @@ async fn quantize_animation_time<T>(
|
||||
Context -> Table<Color>,
|
||||
Context -> Table<Artboard>,
|
||||
Context -> Table<GradientStops>,
|
||||
Context -> GradientStops,
|
||||
Context -> (),
|
||||
)]
|
||||
value: impl Node<'n, Context<'static>, Output = T>,
|
||||
|
||||
@@ -5,7 +5,8 @@ use core_types::transform::Footprint;
|
||||
use core_types::uuid::NodeId;
|
||||
use core_types::{Color, OwnedContextImpl};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphic_types::{Artboard, Graphic, Vector, vector_types::GradientStops};
|
||||
use graphic_types::vector_types::GradientStops;
|
||||
use graphic_types::{Artboard, Graphic, Vector};
|
||||
use raster_types::{CPU, GPU, Raster};
|
||||
|
||||
/// Filters out what should be unused components of the context based on the specified requirements.
|
||||
@@ -37,7 +38,6 @@ async fn context_modification<T>(
|
||||
Context -> Table<Color>,
|
||||
Context -> Table<Artboard>,
|
||||
Context -> Table<GradientStops>,
|
||||
Context -> GradientStops,
|
||||
)]
|
||||
value: impl Node<Context<'static>, Output = T>,
|
||||
/// The parts of the context to keep when evaluating the input value. All other parts are nullified.
|
||||
|
||||
@@ -3,7 +3,8 @@ use core_types::registry::types::TextArea;
|
||||
use core_types::table::Table;
|
||||
use core_types::{Context, Ctx};
|
||||
use glam::{DAffine2, DVec2};
|
||||
use graphic_types::{Artboard, Graphic, Vector, vector_types::GradientStops};
|
||||
use graphic_types::vector_types::GradientStops;
|
||||
use graphic_types::{Artboard, Graphic, Vector};
|
||||
use raster_types::{CPU, GPU, Raster};
|
||||
|
||||
/// Type-asserts a value to be a string.
|
||||
@@ -152,7 +153,7 @@ async fn switch<T, C: Send + 'n + Clone>(
|
||||
Context -> Table<Raster<CPU>>,
|
||||
Context -> Table<Raster<GPU>>,
|
||||
Context -> Table<Color>,
|
||||
Context -> GradientStops,
|
||||
Context -> Table<GradientStops>,
|
||||
)]
|
||||
if_true: impl Node<C, Output = T>,
|
||||
#[expose]
|
||||
@@ -171,7 +172,7 @@ async fn switch<T, C: Send + 'n + Clone>(
|
||||
Context -> Table<Raster<CPU>>,
|
||||
Context -> Table<Raster<GPU>>,
|
||||
Context -> Table<Color>,
|
||||
Context -> GradientStops,
|
||||
Context -> Table<GradientStops>,
|
||||
)]
|
||||
if_false: impl Node<C, Output = T>,
|
||||
) -> T {
|
||||
|
||||
@@ -318,22 +318,47 @@ pub async fn flatten_gradient<T: IntoGraphicTable + 'n + Send + Clone>(_: impl C
|
||||
|
||||
/// Constructs a gradient from a table of colors, where the colors are evenly distributed as gradient stops across the range from 0 to 1.
|
||||
#[node_macro::node(category("Color"))]
|
||||
fn colors_to_gradient<T: IntoGraphicTable + 'n + Send + Clone>(_: impl Ctx, #[implementations(Table<Graphic>, Table<Color>)] colors: T) -> GradientStops {
|
||||
fn colors_to_gradient<T: IntoGraphicTable + 'n + Send + Clone>(_: impl Ctx, #[implementations(Table<Graphic>, Table<Color>)] colors: T) -> Table<GradientStops> {
|
||||
let colors = colors.into_flattened_table::<Color>();
|
||||
let total_colors = colors.len();
|
||||
|
||||
if total_colors == 0 {
|
||||
return GradientStops::new(vec![GradientStop {
|
||||
position: 0.,
|
||||
midpoint: 0.5,
|
||||
color: Color::BLACK,
|
||||
}]);
|
||||
return Table::new_from_element(GradientStops::new(vec![
|
||||
GradientStop {
|
||||
position: 0.,
|
||||
midpoint: 0.5,
|
||||
color: Color::BLACK,
|
||||
},
|
||||
GradientStop {
|
||||
position: 1.,
|
||||
midpoint: 0.5,
|
||||
color: Color::BLACK,
|
||||
},
|
||||
]));
|
||||
}
|
||||
|
||||
if let (Some(color), None) = {
|
||||
let mut colors_iter = colors.iter();
|
||||
(colors_iter.next(), colors_iter.next())
|
||||
} {
|
||||
return Table::new_from_element(GradientStops::new(vec![
|
||||
GradientStop {
|
||||
position: 0.,
|
||||
midpoint: 0.5,
|
||||
color: *color.element,
|
||||
},
|
||||
GradientStop {
|
||||
position: 1.,
|
||||
midpoint: 0.5,
|
||||
color: *color.element,
|
||||
},
|
||||
]));
|
||||
}
|
||||
|
||||
let colors = colors.into_iter().enumerate().map(|(index, row)| GradientStop {
|
||||
position: index as f64 / (total_colors - 1).max(1) as f64,
|
||||
position: index as f64 / (total_colors - 1) as f64,
|
||||
midpoint: 0.5,
|
||||
color: row.element,
|
||||
});
|
||||
GradientStops::new(colors)
|
||||
Table::new_from_element(GradientStops::new(colors))
|
||||
}
|
||||
|
||||
@@ -767,21 +767,17 @@ fn color_value(_: impl Ctx, _primary: (), #[default(Color::BLACK)] color: Table<
|
||||
|
||||
/// Constructs a gradient value which may be set to any sequence of color stops to represent the transition between colors.
|
||||
#[node_macro::node(category("Value"))]
|
||||
fn gradient_value(_: impl Ctx, _primary: (), gradient: GradientStops) -> GradientStops {
|
||||
fn gradient_value(_: impl Ctx, _primary: (), gradient: Table<GradientStops>) -> Table<GradientStops> {
|
||||
gradient
|
||||
}
|
||||
|
||||
/// Constructs a gradient value which may be set to any sequence of color stops to represent the transition between colors.
|
||||
#[node_macro::node(category("Value"))]
|
||||
fn gradient_table_value(_: impl Ctx, _primary: (), gradient: GradientStops) -> Table<GradientStops> {
|
||||
Table::new_from_element(gradient)
|
||||
}
|
||||
|
||||
/// Gets the color at the specified position along the gradient, given a position from 0 (left) to 1 (right).
|
||||
#[node_macro::node(category("Color"))]
|
||||
fn sample_gradient(_: impl Ctx, _primary: (), gradient: GradientStops, position: Fraction) -> Table<Color> {
|
||||
fn sample_gradient(_: impl Ctx, _primary: (), gradient: Table<GradientStops>, position: Fraction) -> Table<Color> {
|
||||
let Some(row) = gradient.get(0) else { return Table::new() };
|
||||
|
||||
let position = position.clamp(0., 1.);
|
||||
let color = gradient.evaluate(position);
|
||||
let color = row.element.evaluate(position);
|
||||
Table::new_from_element(color)
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ fn luminance<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
@@ -80,7 +79,6 @@ fn gamma_correction<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
@@ -102,7 +100,6 @@ fn extract_channel<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
@@ -127,7 +124,6 @@ fn make_opaque<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
@@ -154,7 +150,6 @@ fn brightness_contrast_classic<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
@@ -186,7 +181,6 @@ fn brightness_contrast<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
@@ -268,7 +262,6 @@ fn levels<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
@@ -337,7 +330,6 @@ fn black_and_white<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
@@ -411,7 +403,6 @@ fn hue_saturation<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
@@ -447,7 +438,6 @@ fn invert<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
@@ -471,7 +461,6 @@ fn threshold<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
@@ -518,7 +507,6 @@ fn vibrance<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
@@ -684,7 +672,6 @@ fn channel_mixer<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
@@ -815,7 +802,6 @@ fn selective_color<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
@@ -962,7 +948,6 @@ fn posterize<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
@@ -997,7 +982,6 @@ fn exposure<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut input: T,
|
||||
|
||||
@@ -136,7 +136,6 @@ fn blend<T: Blend<Color> + Send>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
over: T,
|
||||
@@ -145,7 +144,6 @@ fn blend<T: Blend<Color> + Send>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
under: T,
|
||||
@@ -162,7 +160,6 @@ fn color_overlay<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
#[gpu_image]
|
||||
mut image: T,
|
||||
|
||||
@@ -16,16 +16,17 @@ async fn gradient_map<T: Adjust<Color>>(
|
||||
Table<Raster<CPU>>,
|
||||
Table<Color>,
|
||||
Table<GradientStops>,
|
||||
GradientStops,
|
||||
)]
|
||||
mut image: T,
|
||||
gradient: GradientStops,
|
||||
gradient: Table<GradientStops>,
|
||||
reverse: bool,
|
||||
) -> T {
|
||||
let Some(row) = gradient.get(0) else { return image };
|
||||
|
||||
image.adjust(|color| {
|
||||
let intensity = color.luminance_srgb();
|
||||
let intensity = if reverse { 1. - intensity } else { intensity };
|
||||
gradient.evaluate(intensity as f64).to_linear_srgb()
|
||||
row.element.evaluate(intensity as f64).to_linear_srgb()
|
||||
});
|
||||
|
||||
image
|
||||
|
||||
@@ -60,7 +60,7 @@ async fn assign_colors<T>(
|
||||
stroke: bool,
|
||||
/// The range of colors to select from.
|
||||
#[widget(ParsedWidgetOverride::Custom = "assign_colors_gradient")]
|
||||
gradient: GradientStops,
|
||||
gradient: Table<GradientStops>,
|
||||
/// Whether to reverse the gradient.
|
||||
reverse: bool,
|
||||
/// Whether to randomize the color selection for each element from throughout the gradient.
|
||||
@@ -76,8 +76,10 @@ async fn assign_colors<T>(
|
||||
where
|
||||
T: VectorTableIterMut + 'n + Send,
|
||||
{
|
||||
let Some(row) = gradient.into_iter().next() else { return content };
|
||||
|
||||
let length = content.vector_iter_mut().count();
|
||||
let gradient = if reverse { gradient.reversed() } else { gradient };
|
||||
let gradient = if reverse { row.element.reversed() } else { row.element };
|
||||
|
||||
let mut rng = rand::rngs::StdRng::seed_from_u64(seed.into());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user