From 95ce26e36ca55acb256b71e3184163740aa85055 Mon Sep 17 00:00:00 2001 From: Dennis Kobert Date: Tue, 8 Sep 2026 15:16:13 +0000 Subject: [PATCH] Drop the stranded ranked wrappers from the node signatures --- node-graph/nodes/gcore/src/animation.rs | 15 +- node-graph/nodes/gcore/src/debug.rs | 1 + node-graph/nodes/math/src/lib.rs | 267 +++++++----- node-graph/nodes/raster/src/adjustments.rs | 384 +++++++----------- node-graph/nodes/raster/src/filter.rs | 4 +- node-graph/nodes/raster/src/std_nodes.rs | 28 +- node-graph/nodes/repeat/src/repeat_nodes.rs | 6 +- .../nodes/transform/src/transform_nodes.rs | 25 +- 8 files changed, 354 insertions(+), 376 deletions(-) diff --git a/node-graph/nodes/gcore/src/animation.rs b/node-graph/nodes/gcore/src/animation.rs index c85ec3548b..4c294c4802 100644 --- a/node-graph/nodes/gcore/src/animation.rs +++ b/node-graph/nodes/gcore/src/animation.rs @@ -36,20 +36,17 @@ fn real_time( /// The time and date component to be produced as a number. component: RealTimeMode, ) -> f64 { - let component = component.into_element(); let real_time = ctx.try_real_time().unwrap_or_default(); // TODO: Implement proper conversion using and existing time implementation - let result = match component { + match component { RealTimeMode::Utc => real_time, RealTimeMode::Year => (real_time / DAY / 365.25).floor() + 1970., // TODO: Factor in a chosen timezone RealTimeMode::Hour => (real_time / 1000. / 3600.).floor() % 24., // TODO: Factor in a chosen timezone RealTimeMode::Minute => (real_time / 1000. / 60.).floor() % 60., // TODO: Factor in a chosen timezone RealTimeMode::Second => (real_time / 1000.).floor() % 60., RealTimeMode::Millisecond => real_time % 1000., - }; - - Item::new_from_element(result) + } } /// Produces the time, in seconds on the timeline, since the beginning of animation playback. @@ -61,7 +58,7 @@ fn animation_time( #[unit("/sec")] rate: f64, ) -> f64 { - Item::new_from_element(ctx.try_animation_time().unwrap_or_default() * *rate.element()) + ctx.try_animation_time().unwrap_or_default() * rate } #[node_macro::node(category("Debug"))] @@ -94,6 +91,7 @@ fn quantize_real_time( Context -> List, Context -> List, Context -> List, + Context -> (), )] value: impl Node, Output = T>, #[default(1)] @@ -102,7 +100,6 @@ fn quantize_real_time( ) -> GPoll { let time = ctx.try_real_time().unwrap_or_default(); let time = time / 1000.; - let quantum = quantum.into_element(); let mut quantized_time = (time * quantum.recip()).round() / quantum.recip(); if !quantized_time.is_finite() { quantized_time = time; @@ -142,6 +139,7 @@ fn quantize_animation_time( Context -> List, Context -> List, Context -> List, + Context -> (), )] value: impl Node, Output = T>, #[default(1)] @@ -149,7 +147,6 @@ fn quantize_animation_time( quantum: f64, ) -> GPoll { let time = ctx.try_animation_time().unwrap_or_default(); - let quantum = quantum.into_element(); let mut quantized_time = (time * quantum.recip()).round() / quantum.recip(); if !quantized_time.is_finite() { quantized_time = time; @@ -161,7 +158,7 @@ fn quantize_animation_time( /// Produces the current position of the user's pointer within the document canvas. #[node_macro::node(category("Animation"))] fn pointer_position(ctx: impl Ctx + ExtractPointerPosition) -> DVec2 { - Item::new_from_element(ctx.try_pointer_position().unwrap_or_default()) + ctx.try_pointer_position().unwrap_or_default() } // TODO: These nodes require more sophisticated algorithms for giving the correct result diff --git a/node-graph/nodes/gcore/src/debug.rs b/node-graph/nodes/gcore/src/debug.rs index 059207181c..88b1802caf 100644 --- a/node-graph/nodes/gcore/src/debug.rs +++ b/node-graph/nodes/gcore/src/debug.rs @@ -1,5 +1,6 @@ use core_types::Ctx; use glam::{DAffine2, DVec2}; +use raster_types::{CPU, Raster}; /// Meant for debugging purposes, not general use. Logs the input value to the console and passes it through unchanged. #[node_macro::node(category("Debug"), name("Log to Console"))] diff --git a/node-graph/nodes/math/src/lib.rs b/node-graph/nodes/math/src/lib.rs index 5cf07a7635..e7e61e0b12 100644 --- a/node-graph/nodes/math/src/lib.rs +++ b/node-graph/nodes/math/src/lib.rs @@ -1,5 +1,6 @@ use core_types::attribute::Attr; use core_types::gpoll::{GraphError, Interrupt}; +use core_types::list::List; use core_types::registry::types::{Fraction, Percentage, PixelSize}; use core_types::transform::Footprint; use core_types::{Color, Ctx, ExtractIndex, InjectIndex, num_traits}; @@ -9,9 +10,12 @@ use math_parser::ast; use math_parser::context::{EvalContext, NothingMap, ValueProvider}; use math_parser::value::{Number, Value}; use rand::{Rng, SeedableRng}; -use std::ops::{Add, Div, Mul, Rem, Sub}; -use vector_types::GradientStops; -use vector_types::markers::{GradientType as GradientTypeAttr, SpreadMethod as SpreadMethodAttr}; +use std::ops::{Add, Mul, Rem, Sub}; +use vector_types::markers::{ + GradientCyclic as GradientCyclicAttr, GradientForm as GradientFormAttr, GradientHueDirection as GradientHueDirectionAttr, GradientInterpolation as GradientInterpolationAttr, + GradientSpace as GradientSpaceAttr, GradientSpread as GradientSpreadAttr, +}; +use vector_types::{Gradient, GradientSettings}; /// The struct that stores the context for the maths parser. /// This is currently just limited to supplying `a` and `b` until we add better node graph support and UI for variadic inputs. @@ -71,12 +75,10 @@ fn math( }; let Value::Number(num) = value; - let result = match num { + match num { Number::Real(val) => T::from(val).unwrap(), Number::Complex(c) => T::from(c.re).unwrap(), - }; - - result + } } /// The addition operation (`+`) calculates the sum of two scalar numbers or vec2s. @@ -229,10 +231,7 @@ fn modulo>>, B: Copy #[default(true)] always_positive: bool, ) -> >::Output { - let (modulus, always_positive) = (modulus, always_positive); - - let result = if always_positive { (numerator % modulus + modulus) % modulus } else { numerator % modulus }; - result + if always_positive { (numerator % modulus + modulus) % modulus } else { numerator % modulus } } pub trait Exponent { @@ -441,10 +440,7 @@ fn sine( /// Whether the given angle should be interpreted as radians instead of degrees. radians: bool, ) -> T { - let radians = radians; - - let result = theta.componentwise(|theta| if radians { theta.sin() } else { theta.to_radians().sin() }); - result + theta.componentwise(|theta| if radians { theta.sin() } else { theta.to_radians().sin() }) } /// The cosine trigonometric function (`cos`) calculates the ratio of the angle's adjacent side length to its hypotenuse length. @@ -459,10 +455,7 @@ fn cosine( /// Whether the given angle should be interpreted as radians instead of degrees. radians: bool, ) -> T { - let radians = radians; - - let result = theta.componentwise(|theta| if radians { theta.cos() } else { theta.to_radians().cos() }); - result + theta.componentwise(|theta| if radians { theta.cos() } else { theta.to_radians().cos() }) } /// The tangent trigonometric function (`tan`) calculates the ratio of the angle's opposite side length to its adjacent side length. @@ -477,10 +470,7 @@ fn tangent( /// Whether the given angle should be interpreted as radians instead of degrees. radians: bool, ) -> T { - let radians = radians; - - let result = theta.componentwise(|theta| if radians { theta.tan() } else { theta.to_radians().tan() }); - result + theta.componentwise(|theta| if radians { theta.tan() } else { theta.to_radians().tan() }) } /// The inverse sine trigonometric function (`asin`) calculates the angle whose sine is the input value. @@ -494,8 +484,7 @@ fn sine_inverse( radians: bool, ) -> T { let angle = value.clamp(T::from(-1.).unwrap(), T::from(1.).unwrap()).asin(); - let result = if radians { angle } else { angle.to_degrees() }; - result + if radians { angle } else { angle.to_degrees() } } /// The inverse cosine trigonometric function (`acos`) calculates the angle whose cosine is the input value. @@ -509,8 +498,7 @@ fn cosine_inverse( radians: bool, ) -> T { let angle = value.clamp(T::from(-1.).unwrap(), T::from(1.).unwrap()).acos(); - let result = if radians { angle } else { angle.to_degrees() }; - result + if radians { angle } else { angle.to_degrees() } } /// The inverse tangent trigonometric function (`atan` or `atan2`, depending on input type) calculates: @@ -579,8 +567,6 @@ fn remap( /// Whether to constrain the result within the output range instead of extrapolating beyond its bounds. clamped: bool, ) -> U { - let (input_min, input_max, output_min, output_max) = (input_min, input_max, output_min, output_max); - let input_range = input_max - input_min; // Handle division by zero @@ -593,7 +579,7 @@ fn remap( let result = output_min + normalized * output_range; - let result = if clamped { + if clamped { // Handle both normal and inverted ranges, since we want to allow the user to use this node to also reverse a range. if output_min <= output_max { result.clamp(output_min, output_max) @@ -602,9 +588,7 @@ fn remap( } } else { result - }; - - result + } } trait Lerp { @@ -649,14 +633,13 @@ fn lerp( let factor = if clamped { factor.clamp(0., 1.) } else { factor }; // Exact endpoint factors pass the endpoint through untouched, since the unused operand would otherwise contaminate the weighted sum (NaN or infinity times 0 is NaN) - let result = if factor == 0. { + if factor == 0. { start } else if factor == 1. { end } else { start.lerp(end, factor) - }; - result + } } /// The random function (`rand`) converts a seed into a random number within the specified range, inclusive of the minimum and exclusive of the maximum. The minimum and maximum values are automatically swapped if they are reversed. @@ -674,9 +657,8 @@ fn random( ) -> f64 { let mut rng = rand::rngs::StdRng::seed_from_u64(seed); let result = rng.random::(); - let (min, max) = (min, max); let (min, max) = if min < max { (min, max) } else { (max, min) }; - (result * (max - min) + min) + result * (max - min) + min } // TODO: Test that these are no longer needed in all circumstances, then remove them and add a migration to convert these into Passthrough nodes. Note: these act more as type annotations than as identity functions. @@ -791,7 +773,7 @@ fn sign( #[implementations(f64, f32, DVec2)] value: T, ) -> T { - let result = value.componentwise(|value| { + value.componentwise(|value| { if value > 0. { 1. } else if value < 0. { @@ -799,8 +781,7 @@ fn sign( } else { 0. } - }); - result + }) } pub trait MinMax { @@ -924,8 +905,6 @@ fn clamp, B: MinMax + Clone>( where >::Output: MinMax>::Output>, { - let (min, max) = (min, max); - let (min, max) = (min.clone().minimum(max.clone()), min.maximum(max)); value.maximum(min).minimum(max) } @@ -941,17 +920,13 @@ fn greatest_common_divisor T { - let other_value = other_value; - - let result = if value == T::zero() { + if value == T::zero() { other_value } else if other_value == T::zero() { value } else { binary_gcd(value, other_value) - }; - - result + } } /// The least common multiple (LCM) calculates the smallest positive integer that is a multiple of both of the two input numbers. @@ -1011,7 +986,7 @@ fn binary_gcd + std::ops: /// Adds together all the numbers in the input list, producing their total. #[node_macro::node(category("Math: Numeric"))] fn sum(_: impl Ctx, values: List) -> f64 { - (values.iter_element_values().sum()) + values.iter_element_values().sum() } /// Averages all the numbers in the input list. An empty list gives 0. @@ -1020,31 +995,31 @@ fn average(_: impl Ctx, values: List) -> f64 { let count = values.len(); let average = if count == 0 { 0. } else { values.iter_element_values().sum::() / count as f64 }; - (average) + average } /// Gives the smallest number in the input list. An empty list gives 0. #[node_macro::node(category("Math: Numeric"))] fn minimum(_: impl Ctx, values: List) -> f64 { - (values.iter_element_values().copied().reduce(f64::min).unwrap_or_default()) + values.iter_element_values().copied().reduce(f64::min).unwrap_or_default() } /// Gives the largest number in the input list. An empty list gives 0. #[node_macro::node(category("Math: Numeric"))] fn maximum(_: impl Ctx, values: List) -> f64 { - (values.iter_element_values().copied().reduce(f64::max).unwrap_or_default()) + values.iter_element_values().copied().reduce(f64::max).unwrap_or_default() } /// Outputs true if at least one value in the input list is true. An empty list gives false. #[node_macro::node(category("Math: Logic"))] fn any(_: impl Ctx, values: List) -> bool { - (values.iter_element_values().any(|&value| value)) + values.iter_element_values().any(|&value| value) } /// Outputs true only if every value in the input list is true. An empty list gives true. #[node_macro::node(category("Math: Logic"))] fn all(_: impl Ctx, values: List) -> bool { - (values.iter_element_values().all(|&value| value)) + values.iter_element_values().all(|&value| value) } /// The less-than operation (`<`) compares two values and returns true if the first value is less than the second, or false if it is not. @@ -1061,10 +1036,7 @@ fn less_than>( /// Uses the less-than-or-equal operation (`<=`) instead of the less-than operation (`<`). or_equal: bool, ) -> bool { - let other_value = other_value; - - let result = if or_equal { value <= other_value } else { value < other_value }; - result + if or_equal { value <= other_value } else { value < other_value } } /// The greater-than operation (`>`) compares two values and returns true if the first value is greater than the second, or false if it is not. @@ -1081,10 +1053,7 @@ fn greater_than>( /// Uses the greater-than-or-equal operation (`>=`) instead of the greater-than operation (`>`). or_equal: bool, ) -> bool { - let other_value = other_value; - - let result = if or_equal { value >= other_value } else { value > other_value }; - result + if or_equal { value >= other_value } else { value > other_value } } /// The equality operation (`==`, `XNOR`) compares two values and returns true if they are equal, or false if they are not. @@ -1098,9 +1067,7 @@ fn equals>( #[implementations(f64, f32, u32, DVec2, bool, String)] other_value: T, ) -> bool { - let value = value; - - (other_value == value) + other_value == value } /// The inequality operation (`!=`, `XOR`) compares two values and returns true if they are not equal, or false if they are. @@ -1114,9 +1081,7 @@ fn not_equals>( #[implementations(f64, f32, u32, DVec2, bool, String)] other_value: T, ) -> bool { - let value = value; - - (other_value != value) + other_value != value } /// The logical OR operation (`||`) returns true if either of the two inputs are true, or false if both are false. @@ -1237,42 +1202,152 @@ fn hex_to_color(ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, hex_code: Str /// 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: (), #[default(Color::BLACK, Color::WHITE)] gradient: Gradient) -> Gradient { gradient } -/// Sets the type (linear or radial) of each gradient in the input list. -#[node_macro::node(category("Color"))] -fn gradient_type(_: impl Ctx, gradient: GradientStops, gradient_type: vector_types::GradientType) -> (GradientStops, Attr) { - (gradient, Attr(gradient_type)) +/// Sets the form (linear or radial) of each gradient in the input list. +#[node_macro::node(category("Gradient"))] +fn gradient_form(_: impl Ctx, gradient: Gradient, gradient_form: vector_types::GradientForm) -> (Gradient, Attr) { + (gradient, Attr(gradient_form)) } -/// Sets how each gradient in the input list extends past its endpoints: Pad, Reflect, or Repeat. -#[node_macro::node(category("Color"))] -fn spread_method(_: impl Ctx, gradient: GradientStops, spread_method: vector_types::GradientSpreadMethod) -> (GradientStops, Attr) { - (gradient, Attr(spread_method)) +/// Sets how each gradient in the input list extends past its endpoints: Pad, Reflect, Repeat, or Clear. +#[node_macro::node(category("Gradient"))] +fn gradient_spread(_: impl Ctx, gradient: Gradient, gradient_spread: vector_types::GradientSpread) -> (Gradient, Attr) { + (gradient, Attr(gradient_spread)) } -/// Gets the color at the specified position along the gradient, given a position from 0 (left) to 1 (right). +/// Sets the color space in which each gradient in the input list interpolates between its stops. +#[node_macro::node(category("Gradient"))] +fn gradient_space(_: impl Ctx, gradient: Gradient, space: vector_types::GradientSpace) -> (Gradient, Attr) { + (gradient, Attr(space)) +} + +/// Sets the path each gradient in the input list interpolates along, deciding whether it jumps, turns corners, or flows smoothly through its stops. +#[node_macro::node(category("Gradient"))] +fn gradient_interpolation(_: impl Ctx, gradient: Gradient, interpolation: vector_types::GradientInterpolation) -> (Gradient, Attr) { + (gradient, Attr(interpolation)) +} + +/// Sets whether each gradient in the input list treats its stops as a cycle, interpolating from the last stop back around to the first. +#[node_macro::node(category("Gradient"))] +fn gradient_cyclic(_: impl Ctx, gradient: Gradient, cyclic: bool) -> (Gradient, Attr) { + (gradient, Attr(cyclic)) +} + +/// Sets which way around the hue wheel each gradient in the input list interpolates, for polar color spaces. +#[node_macro::node(category("Gradient"))] +fn gradient_hue_direction(_: impl Ctx, gradient: Gradient, hue_direction: vector_types::GradientHueDirection) -> (Gradient, Attr) { + (gradient, Attr(hue_direction)) +} + +/// Sets the position of each of a gradient's stops, a factor from 0 to 1 along the gradient. +/// +/// A list shorter than the stop count repeats its last value, a longer list is truncated, and an empty list sets each stop to its default evenly spaced position. +#[node_macro::node(category("Gradient"))] +fn gradient_positions(_: impl Ctx, mut gradient: Gradient, positions: List) -> Gradient { + let positions: Vec = positions.iter_element_values().copied().collect(); + gradient.set_positions(&positions); + gradient +} + +/// Skews how rapidly the color flows across each interval between color stops, bunching up the transition toward one end instead of progressing uniformly. Each value places the halfway color within its corresponding interval, measured as a fraction of the distance (0 to 1) between the adjacent stops. A 0.5 midpoint keeps a uniform transition rate through the interval. +/// +/// Non-cyclic gradients have no interval following the last stop, meaning the midpoint is ignored in that position. +/// +/// A list shorter than the stop count repeats its last value, a longer list is truncated, and an empty list sets each midpoint to its default of 0.5. +#[node_macro::node(category("Gradient"))] +fn gradient_midpoints(_: impl Ctx, mut gradient: Gradient, midpoints: List) -> Gradient { + let midpoints: Vec = midpoints.iter_element_values().copied().collect(); + gradient.set_midpoints(&midpoints); + gradient +} + +/// Reverses the order of each gradient's stops, moving the color at the start of the ramp to the end and vice versa. +#[node_macro::node(category("Gradient"))] +fn gradient_reverse(_: impl Ctx, (gradient, cyclic): (Gradient, Attr)) -> (Gradient, Attr) { + // Master reads the cyclic flag off the item; ours rides the gradient's own lane. + let cyclic = *cyclic; + (gradient.reversed(cyclic), Attr(cyclic)) +} + +/// Shifts every stop along each gradient's ramp, sliding the colors within the gradient without moving the gradient itself. +/// +/// The fraction is measured against the whole ramp. A cyclic gradient spins, wrapping past the end back around to the start so 1 is a full turn that lands where it began. A gradient that isn't cyclic has no loop to spin around, so its stops slide off the end and keep going, leaving the visible ramp to blend between whichever colors still span it. +#[node_macro::node(category("Gradient"))] +fn gradient_shift( + _: impl Ctx, + (mut gradient, cyclic): (Gradient, Attr), + #[range] + #[soft(-1..1)] + fraction: f64, +) -> (Gradient, Attr) { + // Master reads the cyclic flag off the item; ours rides the gradient's own lane. + let cyclic = *cyclic; + gradient.shift_positions(fraction, cyclic); + (gradient, Attr(cyclic)) +} + +/// Stretches or squeezes the spacing of each gradient's stops around a pivot, spreading the colors within the gradient without moving the gradient itself. +/// +/// The factor multiplies every stop's distance from the pivot, so 2 spreads the ramp over twice its span while 0.5 packs it into half. A negative factor mirrors the stops across the pivot, reversing the order of the colors. +/// +/// The pivot is the one point that stays put, measured against the whole ramp from 0 at the start to 1 at the end. +#[node_macro::node(category("Gradient"))] +fn gradient_stretch( + _: impl Ctx, + (mut gradient, cyclic): (Gradient, Attr), + #[default(1.)] + #[unit("x")] + factor: f64, + #[default(0.5)] + #[range] + #[soft(0..1)] + pivot: f64, +) -> (Gradient, Attr) { + // Master reads the cyclic flag off the item; ours rides the gradient's own lane. + let cyclic = *cyclic; + gradient.stretch_positions(factor, pivot, cyclic); + (gradient, Attr(cyclic)) +} + +/// Evaluates the color at the specified position along the gradient, given a position from 0 (left) to 1 (right). Positions beyond that range follow the gradient's `gradient_spread` attribute: Pad (default), Reflect, Repeat, or Clear. Colors between stops interpolate in the gradient's `gradient_space` color space. #[node_macro::node(category("Color"))] -fn sample_gradient(ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, _primary: (), gradient: IList, position: Fraction) -> Result, Interrupt> { +fn evaluate_gradient( + ctx: impl Ctx + ExtractIndex + InjectIndex + Copy, + _primary: (), + #[default(Color::BLACK, Color::WHITE)] gradient: IList, + #[range] + #[soft(0..1)] + position: f64, +) -> Result, Interrupt> { // An unwired gradient serves an empty level: no color if gradient.is_empty() || ctx.index() != 0 { return Err(GraphError::past_end().into()); } - let position = position.clamp(0., 1.); - Ok(gradient.element_ref(0).evaluate(position)) + // Master reads the whole-ramp settings off the item; ours ride the gradient's own lane. + let lane = gradient.lane(0); + let settings = GradientSettings { + spread: lane.attr::(), + cyclic: lane.attr::(), + space: lane.attr::(), + hue_direction: lane.attr::(), + interpolation: lane.attr::(), + }; + + Ok(gradient.element_ref(0).evaluate(position, settings)) } /// Constructs a footprint value which may be set to any transformation of a unit square describing a render area, and a render resolution at least 1x1 integer pixels. #[node_macro::node(category("Value"))] fn footprint_value(_: impl Ctx, _primary: (), transform: DAffine2, #[default(100., 100.)] resolution: PixelSize) -> Footprint { - (Footprint { - transform: transform, + Footprint { + transform, resolution: resolution.max(DVec2::ONE).as_uvec2(), ..Default::default() - }) + } } /// Composes a vec2 from its X and Y components. @@ -1289,7 +1364,7 @@ fn combine_vec2( #[expose] y: f64, ) -> DVec2 { - (DVec2::new(x, y)) + DVec2::new(x, y) } /// The dot product operation (`·`) calculates the degree of similarity of a vec2 pair based on their angles and lengths. @@ -1308,15 +1383,11 @@ fn dot_product( /// Whether to normalize both input vec2s so the calculation ranges in `[-1, 1]` by considering only their degree of directional alignment. normalize: bool, ) -> f64 { - let other_value = other_value; - - let result = if normalize { + if normalize { value.normalize_or_zero().dot(other_value.normalize_or_zero()) } else { value.dot(other_value) - }; - - result + } } /// The cross product operation (`×`) calculates the signed area of the parallelogram formed by a vec2 pair. @@ -1348,15 +1419,12 @@ fn angle_between( /// Whether the resulting angle should be given in radians instead of degrees. radians: bool, ) -> f64 { - let direction_to = direction_to; - if direction_from == DVec2::ZERO || direction_to == DVec2::ZERO { return 0.; } let angle = direction_from.angle_to(direction_to); - let result = if radians { angle } else { angle.to_degrees() }; - result + if radians { angle } else { angle.to_degrees() } } pub trait ToPosition { @@ -1391,8 +1459,7 @@ fn angle_to( let to = position_to.to_position(); let delta = to - from; let angle = delta.y.atan2(delta.x); - let result = if radians { angle } else { angle.to_degrees() }; - result + if radians { angle } else { angle.to_degrees() } } /// The magnitude operator (`‖x‖`) calculates the length of a vec2, which is the distance from the base to the tip of the arrow it represents. @@ -1433,9 +1500,9 @@ mod test { } #[test] - pub fn length_function() { + pub fn magnitude_function() { let vector = DVec2::new(3., 4.); - assert_eq!(length(&(), vector), 5.); + assert_eq!(magnitude(&(), vector), 5.); } #[test] diff --git a/node-graph/nodes/raster/src/adjustments.rs b/node-graph/nodes/raster/src/adjustments.rs index e26b493cda..6d730ab966 100644 --- a/node-graph/nodes/raster/src/adjustments.rs +++ b/node-graph/nodes/raster/src/adjustments.rs @@ -6,8 +6,6 @@ use core::fmt::Debug; use glam::Vec3; use no_std_types::color::{Color, linear_to_srgb, srgb_to_linear}; use no_std_types::context::Ctx; -#[cfg(not(feature = "std"))] -use no_std_types::list::ShaderItem as Item; use no_std_types::registry::types::{AngleF32, PercentageF32, SignedPercentageF32}; use node_macro::BufferStruct; use num_enum::{FromPrimitive, IntoPrimitive}; @@ -55,16 +53,13 @@ fn luminance + Clone + Send + Sync + no_std_types::context::Cac #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, - luminance_calc: Item, -) -> Item { - let mut input = input; - let luminance_calc = luminance_calc.into_element(); - - input.element_mut().adjust(|color| { + mut input: T, + luminance_calc: LuminanceCalculation, +) -> T { + input.adjust(|color| { let luminance = match luminance_calc { LuminanceCalculation::SRGB => color.luminance_rec_709(), LuminanceCalculation::Perceptual => color.luminance_perceptual(), @@ -83,23 +78,19 @@ fn gamma_correction + Clone + Send + Sync + no_std_types::conte #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, + mut input: T, #[default(2.2)] #[range] #[hard(0.0001..)] #[soft(0.01..10)] - gamma: Item, - inverse: Item, -) -> Item { - let mut input = input; - let gamma = gamma.into_element(); - let inverse = inverse.into_element(); - + gamma: f32, + inverse: bool, +) -> T { let exponent = if inverse { 1. / gamma } else { gamma }; - input.element_mut().adjust(|color| color.apply_gamma_exponent(exponent)); + input.adjust(|color| color.apply_gamma_exponent(exponent)); input } @@ -109,16 +100,13 @@ fn extract_channel + Clone + Send + Sync + no_std_types::contex #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, - channel: Item, -) -> Item { - let mut input = input; - let channel = channel.into_element(); - - input.element_mut().adjust(|color| { + mut input: T, + channel: RedGreenBlueAlpha, +) -> T { + input.adjust(|color| { let extracted_value = match channel { RedGreenBlueAlpha::Red => color.r(), RedGreenBlueAlpha::Green => color.g(), @@ -136,13 +124,12 @@ fn make_opaque + Clone + Send + Sync + no_std_types::context::C #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, -) -> Item { - let mut input = input; - input.element_mut().adjust(|color| { + mut input: T, +) -> T { + input.adjust(|color| { if color.a() == 0. { return color.with_alpha(1.); } @@ -159,17 +146,13 @@ fn brightness_contrast_classic + Clone + Send + Sync + no_std_t #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, - brightness: Item, - contrast: Item, -) -> Item { - let mut input = input; - let brightness = brightness.into_element(); - let contrast = contrast.into_element(); - + mut input: T, + brightness: SignedPercentageF32, + contrast: SignedPercentageF32, +) -> T { let brightness = brightness / 255.; let contrast = contrast / 100.; @@ -177,7 +160,7 @@ fn brightness_contrast_classic + Clone + Send + Sync + no_std_t let offset = brightness * contrast + brightness - contrast / 2.; - input.element_mut().adjust(|color| color.map_gamma_rgb(|c| (c + c * contrast + offset).clamp(0., 1.))); + input.adjust(|color| color.map_gamma_rgb(|c| (c + c * contrast + offset).clamp(0., 1.))); input } @@ -194,23 +177,18 @@ fn brightness_contrast + Clone + Send + Sync + no_std_types::co #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, - brightness: Item, - contrast: Item, - use_classic: Item, -) -> Item { - let use_classic = use_classic.into_element(); + mut input: T, + brightness: SignedPercentageF32, + contrast: SignedPercentageF32, + use_classic: bool, +) -> T { if use_classic { return brightness_contrast_classic(_ctx, input, brightness, contrast); } - let mut input = input; - let brightness = brightness.into_element(); - let contrast = contrast.into_element(); - const WINDOW_SIZE: usize = 1024; // Brightness LUT @@ -261,7 +239,7 @@ fn brightness_contrast + Clone + Send + Sync + no_std_types::co }); let lut_max = (combined_lut.len() - 1) as f32; - input.element_mut().adjust(|color| color.map_gamma_rgb(|c| combined_lut[(c * lut_max).round() as usize])); + input.adjust(|color| color.map_gamma_rgb(|c| combined_lut[(c * lut_max).round() as usize])); input } @@ -280,24 +258,17 @@ fn levels + Clone + Send + Sync + no_std_types::context::CacheH #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - image: Item, - #[default(0.)] shadows: Item, - #[default(50.)] midtones: Item, - #[default(100.)] highlights: Item, - #[default(0.)] output_minimums: Item, - #[default(100.)] output_maximums: Item, -) -> Item { - let mut image = image; - let shadows = shadows.into_element(); - let midtones = midtones.into_element(); - let highlights = highlights.into_element(); - let output_minimums = output_minimums.into_element(); - let output_maximums = output_maximums.into_element(); - - image.element_mut().adjust(|color| { + mut image: T, + #[default(0.)] shadows: PercentageF32, + #[default(50.)] midtones: PercentageF32, + #[default(100.)] highlights: PercentageF32, + #[default(0.)] output_minimums: PercentageF32, + #[default(100.)] output_maximums: PercentageF32, +) -> T { + image.adjust(|color| { // Levels math operates in gamma space let [mut r, mut g, mut b, a] = color.to_gamma_srgb_channels(); @@ -366,46 +337,37 @@ fn black_and_white + Clone + Send + Sync + no_std_types::contex #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - image: Item, - #[default(Color::BLACK)] tint: Item, + mut image: T, + #[default(Color::BLACK)] tint: Color, #[default(40.)] #[range] #[soft(-200..300)] - reds: Item, + reds: PercentageF32, #[default(60.)] #[range] #[soft(-200..300)] - yellows: Item, + yellows: PercentageF32, #[default(40.)] #[range] #[soft(-200..300)] - greens: Item, + greens: PercentageF32, #[default(60.)] #[range] #[soft(-200..300)] - cyans: Item, + cyans: PercentageF32, #[default(20.)] #[range] #[soft(-200..300)] - blues: Item, + blues: PercentageF32, #[default(80.)] #[range] #[soft(-200..300)] - magentas: Item, -) -> Item { - let mut image = image; - let tint = tint.into_element(); - let reds = reds.into_element(); - let yellows = yellows.into_element(); - let greens = greens.into_element(); - let cyans = cyans.into_element(); - let blues = blues.into_element(); - let magentas = magentas.into_element(); - - image.element_mut().adjust(|color| { + magentas: PercentageF32, +) -> T { + image.adjust(|color| { // Black & White channel weights are tuned for gamma-space values let [r, g, b, alpha_part] = color.to_gamma_srgb_channels(); @@ -458,20 +420,15 @@ fn hue_saturation + Clone + Send + Sync + no_std_types::context #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, - hue_shift: Item, - saturation_shift: Item, - lightness_shift: Item, -) -> Item { - let mut input = input; - let hue_shift = hue_shift.into_element(); - let saturation_shift = saturation_shift.into_element(); - let lightness_shift = lightness_shift.into_element(); - - input.element_mut().adjust(|color| { + mut input: T, + hue_shift: AngleF32, + saturation_shift: SignedPercentageF32, + lightness_shift: SignedPercentageF32, +) -> T { + input.adjust(|color| { // HSL operates on gamma-space channels let [hue, saturation, lightness, alpha] = color.to_hsla(); @@ -495,13 +452,12 @@ fn invert + Clone + Send + Sync + no_std_types::context::CacheH #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, -) -> Item { - let mut input = input; - input.element_mut().adjust(|color| { + mut input: T, +) -> T { + input.adjust(|color| { // Invert in gamma space relative to alpha let [r, g, b, a] = color.to_gamma_srgb_channels(); Color::from_gamma_srgb_channels(a - r, a - g, a - b, a) @@ -517,20 +473,15 @@ fn threshold + Clone + Send + Sync + no_std_types::context::Cac #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - image: Item, - #[default(50.)] min_luminance: Item, - #[default(100.)] max_luminance: Item, - luminance_calc: Item, -) -> Item { - let mut image = image; - let min_luminance = min_luminance.into_element(); - let max_luminance = max_luminance.into_element(); - let luminance_calc = luminance_calc.into_element(); - - image.element_mut().adjust(|color| { + mut image: T, + #[default(50.)] min_luminance: PercentageF32, + #[default(100.)] max_luminance: PercentageF32, + luminance_calc: LuminanceCalculation, +) -> T { + image.adjust(|color| { let min_luminance = srgb_to_linear(min_luminance / 100.); let max_luminance = srgb_to_linear(max_luminance / 100.); @@ -568,16 +519,13 @@ fn vibrance + Clone + Send + Sync + no_std_types::context::Cach #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - image: Item, - vibrance: Item, -) -> Item { - let mut image = image; - let vibrance = vibrance.into_element(); - - image.element_mut().adjust(|color| { + mut image: T, + vibrance: SignedPercentageF32, +) -> T { + image.adjust(|color| { let r_raw = color.r(); let g_raw = color.g(); let b_raw = color.b(); @@ -773,76 +721,69 @@ fn channel_mixer + Clone + Send + Sync + no_std_types::context: #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - image: Item, + mut image: T, - monochrome: Item, + monochrome: bool, #[default(40.)] #[name("Red")] - monochrome_r: Item, + monochrome_r: f32, #[default(40.)] #[name("Green")] - monochrome_g: Item, + monochrome_g: f32, #[default(20.)] #[name("Blue")] - monochrome_b: Item, + monochrome_b: f32, #[default(0.)] #[name("Constant")] - monochrome_c: Item, + monochrome_c: f32, #[default(100.)] #[name("(Red) Red")] - red_r: Item, + red_r: f32, #[default(0.)] #[name("(Red) Green")] - red_g: Item, + red_g: f32, #[default(0.)] #[name("(Red) Blue")] - red_b: Item, + red_b: f32, #[default(0.)] #[name("(Red) Constant")] - red_c: Item, + red_c: f32, #[default(0.)] #[name("(Green) Red")] - green_r: Item, + green_r: f32, #[default(100.)] #[name("(Green) Green")] - green_g: Item, + green_g: f32, #[default(0.)] #[name("(Green) Blue")] - green_b: Item, + green_b: f32, #[default(0.)] #[name("(Green) Constant")] - green_c: Item, + green_c: f32, #[default(0.)] #[name("(Blue) Red")] - blue_r: Item, + blue_r: f32, #[default(0.)] #[name("(Blue) Green")] - blue_g: Item, + blue_g: f32, #[default(100.)] #[name("(Blue) Blue")] - blue_b: Item, + blue_b: f32, #[default(0.)] #[name("(Blue) Constant")] - blue_c: Item, + blue_c: f32, // Display-only properties (not used within the node) - _output_channel: Item, -) -> Item { - let mut image = image; - let monochrome = monochrome.into_element(); - let (monochrome_r, monochrome_g, monochrome_b, monochrome_c) = (monochrome_r.into_element(), monochrome_g.into_element(), monochrome_b.into_element(), monochrome_c.into_element()); - let (red_r, red_g, red_b, red_c) = (red_r.into_element(), red_g.into_element(), red_b.into_element(), red_c.into_element()); - let (green_r, green_g, green_b, green_c) = (green_r.into_element(), green_g.into_element(), green_b.into_element(), green_c.into_element()); - let (blue_r, blue_g, blue_b, blue_c) = (blue_r.into_element(), blue_g.into_element(), blue_b.into_element(), blue_c.into_element()); - - image.element_mut().adjust(|color| { + _output_channel: RedGreenBlue, +) -> T { + image.adjust(|color| { let [r, g, b, a] = color.to_gamma_srgb_channels(); let (out_r, out_g, out_b) = if monochrome { @@ -912,73 +853,61 @@ fn selective_color + Clone + Send + Sync + no_std_types::contex #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - image: Item, + mut image: T, - mode: Item, + mode: RelativeAbsolute, - #[name("(Reds) Cyan")] r_c: Item, - #[name("(Reds) Magenta")] r_m: Item, - #[name("(Reds) Yellow")] r_y: Item, - #[name("(Reds) Black")] r_k: Item, + #[name("(Reds) Cyan")] r_c: f32, + #[name("(Reds) Magenta")] r_m: f32, + #[name("(Reds) Yellow")] r_y: f32, + #[name("(Reds) Black")] r_k: f32, - #[name("(Yellows) Cyan")] y_c: Item, - #[name("(Yellows) Magenta")] y_m: Item, - #[name("(Yellows) Yellow")] y_y: Item, - #[name("(Yellows) Black")] y_k: Item, + #[name("(Yellows) Cyan")] y_c: f32, + #[name("(Yellows) Magenta")] y_m: f32, + #[name("(Yellows) Yellow")] y_y: f32, + #[name("(Yellows) Black")] y_k: f32, - #[name("(Greens) Cyan")] g_c: Item, - #[name("(Greens) Magenta")] g_m: Item, - #[name("(Greens) Yellow")] g_y: Item, - #[name("(Greens) Black")] g_k: Item, + #[name("(Greens) Cyan")] g_c: f32, + #[name("(Greens) Magenta")] g_m: f32, + #[name("(Greens) Yellow")] g_y: f32, + #[name("(Greens) Black")] g_k: f32, - #[name("(Cyans) Cyan")] c_c: Item, - #[name("(Cyans) Magenta")] c_m: Item, - #[name("(Cyans) Yellow")] c_y: Item, - #[name("(Cyans) Black")] c_k: Item, + #[name("(Cyans) Cyan")] c_c: f32, + #[name("(Cyans) Magenta")] c_m: f32, + #[name("(Cyans) Yellow")] c_y: f32, + #[name("(Cyans) Black")] c_k: f32, - #[name("(Blues) Cyan")] b_c: Item, - #[name("(Blues) Magenta")] b_m: Item, - #[name("(Blues) Yellow")] b_y: Item, - #[name("(Blues) Black")] b_k: Item, + #[name("(Blues) Cyan")] b_c: f32, + #[name("(Blues) Magenta")] b_m: f32, + #[name("(Blues) Yellow")] b_y: f32, + #[name("(Blues) Black")] b_k: f32, - #[name("(Magentas) Cyan")] m_c: Item, - #[name("(Magentas) Magenta")] m_m: Item, - #[name("(Magentas) Yellow")] m_y: Item, - #[name("(Magentas) Black")] m_k: Item, + #[name("(Magentas) Cyan")] m_c: f32, + #[name("(Magentas) Magenta")] m_m: f32, + #[name("(Magentas) Yellow")] m_y: f32, + #[name("(Magentas) Black")] m_k: f32, - #[name("(Whites) Cyan")] w_c: Item, - #[name("(Whites) Magenta")] w_m: Item, - #[name("(Whites) Yellow")] w_y: Item, - #[name("(Whites) Black")] w_k: Item, + #[name("(Whites) Cyan")] w_c: f32, + #[name("(Whites) Magenta")] w_m: f32, + #[name("(Whites) Yellow")] w_y: f32, + #[name("(Whites) Black")] w_k: f32, - #[name("(Neutrals) Cyan")] n_c: Item, - #[name("(Neutrals) Magenta")] n_m: Item, - #[name("(Neutrals) Yellow")] n_y: Item, - #[name("(Neutrals) Black")] n_k: Item, + #[name("(Neutrals) Cyan")] n_c: f32, + #[name("(Neutrals) Magenta")] n_m: f32, + #[name("(Neutrals) Yellow")] n_y: f32, + #[name("(Neutrals) Black")] n_k: f32, - #[name("(Blacks) Cyan")] k_c: Item, - #[name("(Blacks) Magenta")] k_m: Item, - #[name("(Blacks) Yellow")] k_y: Item, - #[name("(Blacks) Black")] k_k: Item, + #[name("(Blacks) Cyan")] k_c: f32, + #[name("(Blacks) Magenta")] k_m: f32, + #[name("(Blacks) Yellow")] k_y: f32, + #[name("(Blacks) Black")] k_k: f32, - _colors: Item, -) -> Item { - let mut image = image; - let mode = mode.into_element(); - let (r_c, r_m, r_y, r_k) = (r_c.into_element(), r_m.into_element(), r_y.into_element(), r_k.into_element()); - let (y_c, y_m, y_y, y_k) = (y_c.into_element(), y_m.into_element(), y_y.into_element(), y_k.into_element()); - let (g_c, g_m, g_y, g_k) = (g_c.into_element(), g_m.into_element(), g_y.into_element(), g_k.into_element()); - let (c_c, c_m, c_y, c_k) = (c_c.into_element(), c_m.into_element(), c_y.into_element(), c_k.into_element()); - let (b_c, b_m, b_y, b_k) = (b_c.into_element(), b_m.into_element(), b_y.into_element(), b_k.into_element()); - let (m_c, m_m, m_y, m_k) = (m_c.into_element(), m_m.into_element(), m_y.into_element(), m_k.into_element()); - let (w_c, w_m, w_y, w_k) = (w_c.into_element(), w_m.into_element(), w_y.into_element(), w_k.into_element()); - let (n_c, n_m, n_y, n_k) = (n_c.into_element(), n_m.into_element(), n_y.into_element(), n_k.into_element()); - let (k_c, k_m, k_y, k_k) = (k_c.into_element(), k_m.into_element(), k_y.into_element(), k_k.into_element()); - - image.element_mut().adjust(|color| { + _colors: SelectiveColorChoice, +) -> T { + image.adjust(|color| { let [r, g, b, a] = color.to_gamma_srgb_channels(); let min = |a: f32, b: f32, c: f32| a.min(b).min(c); @@ -1068,18 +997,16 @@ fn posterize + Clone + Send + Sync + no_std_types::context::Cac #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, + mut input: T, #[default(4)] #[hard(2..)] - levels: Item, -) -> Item { - let mut input = input; - let levels = levels.into_element() as f32; - - input.element_mut().adjust(|color| { + levels: u32, +) -> T { + let levels = levels as f32; + input.adjust(|color| { let number_of_areas = levels.recip(); let size_of_areas = (levels - 1.).recip(); color.map_gamma_rgb(|c| (c / number_of_areas).floor() * size_of_areas) @@ -1099,24 +1026,19 @@ fn exposure + Clone + Send + Sync + no_std_types::context::Cach #[implementations( Raster, Color, - GradientStops, + Gradient, )] #[gpu_image] - input: Item, - exposure: Item, - offset: Item, + mut input: T, + exposure: f32, + offset: f32, #[default(1.)] #[range] #[hard(0.0001..)] #[soft(0.01..10)] - gamma_correction: Item, -) -> Item { - let mut input = input; - let exposure = exposure.into_element(); - let offset = offset.into_element(); - let gamma_correction = gamma_correction.into_element(); - - input.element_mut().adjust(|color| { + gamma_correction: f32, +) -> T { + input.adjust(|color| { let adjusted = color // Exposure .map_rgb(|c: f32| c * 2_f32.powf(exposure)) diff --git a/node-graph/nodes/raster/src/filter.rs b/node-graph/nodes/raster/src/filter.rs index 09a61e2290..34e9069663 100644 --- a/node-graph/nodes/raster/src/filter.rs +++ b/node-graph/nodes/raster/src/filter.rs @@ -94,9 +94,9 @@ fn blur( #[range] #[hard(0..)] #[soft(..100)] - radius: Item, + radius: PixelLength, /// Use a lower-quality box kernel instead of a circular Gaussian kernel. This is faster but produces boxy artifacts. - box_blur: Item, + box_blur: bool, /// Opt to incorrectly apply the filter with color calculations in gamma space for compatibility with the results from other software. gamma: bool, ) -> Raster { diff --git a/node-graph/nodes/raster/src/std_nodes.rs b/node-graph/nodes/raster/src/std_nodes.rs index af44cd5375..fdf188bac7 100644 --- a/node-graph/nodes/raster/src/std_nodes.rs +++ b/node-graph/nodes/raster/src/std_nodes.rs @@ -369,32 +369,32 @@ pub fn image(_: impl Ctx, resource: Resource) -> Raster { pub fn noise_pattern( ctx: impl ExtractFootprint + Ctx, _primary: (), - #[default(true)] clip: Item, - seed: Item, + #[default(true)] clip: bool, + seed: u32, #[widget(ParsedWidgetOverride::Custom = "noise_properties_scale")] #[default(10.)] - scale: Item, - #[widget(ParsedWidgetOverride::Custom = "noise_properties_noise_type")] noise_type: Item, - #[widget(ParsedWidgetOverride::Custom = "noise_properties_domain_warp_type")] domain_warp_type: Item, + scale: f64, + #[widget(ParsedWidgetOverride::Custom = "noise_properties_noise_type")] noise_type: NoiseType, + #[widget(ParsedWidgetOverride::Custom = "noise_properties_domain_warp_type")] domain_warp_type: DomainWarpType, #[widget(ParsedWidgetOverride::Custom = "noise_properties_domain_warp_amplitude")] #[default(100.)] - domain_warp_amplitude: Item, - #[widget(ParsedWidgetOverride::Custom = "noise_properties_fractal_type")] fractal_type: Item, + domain_warp_amplitude: f64, + #[widget(ParsedWidgetOverride::Custom = "noise_properties_fractal_type")] fractal_type: FractalType, #[widget(ParsedWidgetOverride::Custom = "noise_properties_fractal_octaves")] #[default(3)] - fractal_octaves: Item, + fractal_octaves: u32, #[widget(ParsedWidgetOverride::Custom = "noise_properties_fractal_lacunarity")] #[default(2.)] - fractal_lacunarity: Item, + fractal_lacunarity: f64, #[widget(ParsedWidgetOverride::Custom = "noise_properties_fractal_gain")] #[default(0.5)] - fractal_gain: Item, - #[widget(ParsedWidgetOverride::Custom = "noise_properties_fractal_weighted_strength")] fractal_weighted_strength: Item, + fractal_gain: f64, + #[widget(ParsedWidgetOverride::Custom = "noise_properties_fractal_weighted_strength")] fractal_weighted_strength: f64, #[widget(ParsedWidgetOverride::Custom = "noise_properties_ping_pong_strength")] #[default(2.)] - fractal_ping_pong_strength: Item, - #[widget(ParsedWidgetOverride::Custom = "noise_properties_cellular_distance_function")] cellular_distance_function: Item, - #[widget(ParsedWidgetOverride::Custom = "noise_properties_cellular_return_type")] cellular_return_type: Item, + fractal_ping_pong_strength: f64, + #[widget(ParsedWidgetOverride::Custom = "noise_properties_cellular_distance_function")] cellular_distance_function: CellularDistanceFunction, + #[widget(ParsedWidgetOverride::Custom = "noise_properties_cellular_return_type")] cellular_return_type: CellularReturnType, #[widget(ParsedWidgetOverride::Custom = "noise_properties_cellular_jitter")] #[default(1.)] cellular_jitter: f64, diff --git a/node-graph/nodes/repeat/src/repeat_nodes.rs b/node-graph/nodes/repeat/src/repeat_nodes.rs index f16bcc59b1..003dded84e 100644 --- a/node-graph/nodes/repeat/src/repeat_nodes.rs +++ b/node-graph/nodes/repeat/src/repeat_nodes.rs @@ -51,8 +51,8 @@ pub fn repeat_array( content: impl Node, Output = (T, Attr)>, #[default(100., 100.)] // TODO: When using a custom Properties panel layout in document_node_definitions.rs and this default is set, the widget weirdly doesn't show up in the Properties panel. Investigation is needed. - direction: Item, - angle: Item, + direction: PixelSize, + angle: Angle, #[default(5)] #[hard(1..)] count: u32, @@ -95,7 +95,7 @@ fn repeat_radial( start_angle: Angle, #[unit(" px")] #[default(5)] - radius: Item, + radius: f64, #[default(5)] #[hard(1..)] count: u32, diff --git a/node-graph/nodes/transform/src/transform_nodes.rs b/node-graph/nodes/transform/src/transform_nodes.rs index b5190c292a..534598ddf5 100644 --- a/node-graph/nodes/transform/src/transform_nodes.rs +++ b/node-graph/nodes/transform/src/transform_nodes.rs @@ -56,7 +56,7 @@ fn transform_value( let transformed = ctx.modify_footprint(|footprint| footprint.apply_transform(&matrix)); let mut transform_target = content.eval(&transformed.ctx())?; - item.left_apply_transform(&matrix); + transform_target.left_apply_transform(&matrix); Ok(transform_target) } @@ -96,7 +96,7 @@ fn replace_transform(_: impl Ctx + InjectFootprint, (element, _content_transf // TODO: Figure out how this node should behave once #2982 is implemented. /// Obtains the transform of the first lane of the input, if present. #[node_macro::node(category("Math: Transform"), path(core_types::vector))] -fn extract_transform(_: impl Ctx, #[implementations(Graphic, Vector, Raster, Raster, Color, Gradient)] content: IList) -> DAffine2 { +fn extract_transform(_: impl Ctx, #[implementations(Graphic, Vector, Raster, Raster, Color, Gradient, String, Artboard)] content: IList) -> DAffine2 { match content.len() { 0 => DAffine2::default(), _ => content.lane(0).attr::(), @@ -106,23 +106,19 @@ fn extract_transform(_: impl Ctx, /// Produces the inverse of the input transform, which is the transform that undoes the effect of the original transform. #[node_macro::node(category("Math: Transform"))] fn invert_transform(_: impl Ctx, transform: DAffine2) -> DAffine2 { - let (transform, attributes) = transform.into_parts(); - - let result = transform.inverse(); - - Item::from_parts(result, attributes) + transform.inverse() } /// Extracts the translation component from the input transform. #[node_macro::node(category("Math: Transform"))] fn decompose_translation(_: impl Ctx, transform: DAffine2) -> DVec2 { - Item::new_from_element(transform.into_element().translation) + transform.translation } /// Extracts the rotation component (in degrees) from the input transform. #[node_macro::node(category("Math: Transform"))] fn decompose_rotation(_: impl Ctx, transform: DAffine2) -> f64 { - Item::new_from_element(transform.into_element().decompose_rotation().to_degrees()) + transform.decompose_rotation().to_degrees() } /// Extracts the scale component from the input transform. @@ -130,19 +126,14 @@ fn decompose_rotation(_: impl Ctx, transform: DAffine2) -> f64 { /// **Pure** returns the isolated scale factors with rotation and skew stripped away (can be negative for flipped axes). #[node_macro::node(category("Math: Transform"))] fn decompose_scale(_: impl Ctx, transform: DAffine2, scale_type: ScaleType) -> DVec2 { - let transform = transform.into_element(); - let scale_type = scale_type.into_element(); - - let result = match scale_type { + match scale_type { ScaleType::Magnitude => transform.scale_magnitudes(), ScaleType::Pure => transform.decompose_scale(), - }; - - Item::new_from_element(result) + } } /// Extracts the skew angle (in degrees) from the input transform. #[node_macro::node(category("Math: Transform"))] fn decompose_skew(_: impl Ctx, transform: DAffine2) -> f64 { - Item::new_from_element(transform.into_element().decompose_skew().atan().to_degrees()) + transform.decompose_skew().atan().to_degrees() }