mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-20 03:18:06 +08:00
Add multi-output nodes with struct returns destructured by #[node_macro::destructure]
A #[node_macro::node] function returning a struct tagged with
field is a named output connector (title-cased from the field name,
renamed with #[name("...")], described by its doc comment). By default
the node has a hidden primary output carrying the whole struct with the
fields as secondary outputs; marking at most one field #[primary] makes
that field the primary output instead.
The macro generates one hidden extractor proto node per field plus a
registration keyed by the struct's TypeId. The Graphene preprocessor
recognizes nodes returning a registered struct and substitutes them, in
the transient runtime copy of the network only, with a generated network
exporting each field through its extractor. The destructuring machinery
therefore never appears when drilling into a node, in copied clipboard
content, or in saved documents. When a Memoize implementation is
registered for the struct type, the struct is computed once and shared
across all outputs rather than re-evaluated per output.
The editor derives output counts, names, and types for such nodes from
the registry. The old hand-authored "Split Vec2" and "Split Channels"
wrapper-network definitions are replaced by multi-output split_vec2 and
split_channels proto nodes, with document migrations that keep existing
wires valid since the output indices are unchanged.
The "Position on Path" and "Tangent on Path" nodes are combined into a
single multi-output "Evaluate Path" node whose primary output is the
position and whose secondary output is the tangent angle. A migration
converts old instances, forwarding the shared inputs and remapping the
tangent nodes' downstream connections to the new tangent output index.
The now-redundant "Extract XY" node is removed (its role is subsumed by
Split Vec2's destructuring), and "Extract Channel" becomes a plain helper
used by Split Channels rather than a standalone node.
This commit is contained in:
@@ -105,22 +105,10 @@ fn gamma_correction<T: Adjust<Color>>(
|
||||
input
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Raster: Channels"), shader_node(PerPixelAdjust))]
|
||||
fn extract_channel<T: Adjust<Color>>(
|
||||
_: impl Ctx,
|
||||
#[implementations(
|
||||
Raster<CPU>,
|
||||
Color,
|
||||
Gradient,
|
||||
)]
|
||||
#[gpu_image]
|
||||
input: Item<T>,
|
||||
channel: Item<RedGreenBlueAlpha>,
|
||||
) -> Item<T> {
|
||||
let mut input = input;
|
||||
let channel = channel.into_element();
|
||||
|
||||
input.element_mut().adjust(|color| {
|
||||
/// Extracts one color channel as a grayscale image. Used internally by the `split_channels` node.
|
||||
#[cfg(feature = "std")]
|
||||
fn extract_channel<T: Adjust<Color>>(mut input: T, channel: RedGreenBlueAlpha) -> T {
|
||||
input.adjust(|color| {
|
||||
let extracted_value = match channel {
|
||||
RedGreenBlueAlpha::Red => color.r(),
|
||||
RedGreenBlueAlpha::Green => color.g(),
|
||||
@@ -132,6 +120,37 @@ fn extract_channel<T: Adjust<Color>>(
|
||||
input
|
||||
}
|
||||
|
||||
/// The red, green, blue, and alpha channels of an image, split into separate node outputs.
|
||||
#[cfg(feature = "std")]
|
||||
#[node_macro::destructure]
|
||||
#[derive(Debug, Clone, dyn_any::DynAny)]
|
||||
pub struct ImageChannels {
|
||||
/// The red channel of the image, as a grayscale image.
|
||||
pub red: Raster<CPU>,
|
||||
/// The green channel of the image, as a grayscale image.
|
||||
pub green: Raster<CPU>,
|
||||
/// The blue channel of the image, as a grayscale image.
|
||||
pub blue: Raster<CPU>,
|
||||
/// The alpha channel of the image, as a grayscale image.
|
||||
pub alpha: Raster<CPU>,
|
||||
}
|
||||
|
||||
/// Separates an image into its red, green, blue, and alpha channels, each provided as a grayscale image.
|
||||
#[cfg(feature = "std")]
|
||||
#[node_macro::node(name("Split Channels"), category("Raster: Channels"))]
|
||||
fn split_channels(_: impl Ctx, image: Item<Raster<CPU>>) -> Item<ImageChannels> {
|
||||
let (image, attributes) = image.into_parts();
|
||||
|
||||
let channels = ImageChannels {
|
||||
red: extract_channel(image.clone(), RedGreenBlueAlpha::Red),
|
||||
green: extract_channel(image.clone(), RedGreenBlueAlpha::Green),
|
||||
blue: extract_channel(image.clone(), RedGreenBlueAlpha::Blue),
|
||||
alpha: extract_channel(image, RedGreenBlueAlpha::Alpha),
|
||||
};
|
||||
|
||||
Item::from_parts(channels, attributes)
|
||||
}
|
||||
|
||||
#[node_macro::node(category("Raster: Channels"), shader_node(PerPixelAdjust))]
|
||||
fn make_opaque<T: Adjust<Color>>(
|
||||
_: impl Ctx,
|
||||
|
||||
Reference in New Issue
Block a user