From 3019cc7253b89f287b824f5a731ef7fde4ea9699 Mon Sep 17 00:00:00 2001 From: Karthik Prakash <116057817+skoriop@users.noreply.github.com> Date: Thu, 18 Apr 2024 04:14:14 +0530 Subject: [PATCH] Add alpha to Extract Channel node and remove Extract Alpha node (#1731) * add `TaggedValue::RedGreenBlueAlpha` * add alpha to `ExtractChannelNode` * remove `ExtractAlphaNode` from `Split Channels` * remove `ExtractAlphaNode` --- .../node_graph/document_node_types.rs | 22 ++++------ .../document/node_graph/node_properties.rs | 32 ++++++++++++++- node-graph/gcore/src/raster/adjustments.rs | 41 ++++++++++++------- node-graph/graph-craft/src/document/value.rs | 5 +++ .../interpreted-executor/src/node_registry.rs | 3 +- 5 files changed, 70 insertions(+), 33 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs index 93dcd47c..4a8ffc62 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_types.rs @@ -14,7 +14,7 @@ use graph_craft::imaginate_input::ImaginateSamplingMethod; use graph_craft::ProtoNodeIdentifier; use graphene_core::raster::brush_cache::BrushCache; use graphene_core::raster::{ - BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, Image, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RelativeAbsolute, + BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, Image, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute, SelectiveColorChoice, }; use graphene_core::text::Font; @@ -867,20 +867,12 @@ fn static_nodes() -> Vec { implementation: DocumentNodeImplementation::proto("graphene_core::raster::ExtractChannelNode<_>"), inputs: vec![ DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), - DocumentInputType::value("From", TaggedValue::RedGreenBlue(RedGreenBlue::Red), false), + DocumentInputType::value("From", TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false), ], outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], properties: node_properties::extract_channel_properties, ..Default::default() }, - DocumentNodeDefinition { - name: "Extract Alpha", - category: "Image Adjustments", - implementation: DocumentNodeImplementation::proto("graphene_core::raster::ExtractAlphaNode<>"), - inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)], - outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)], - ..Default::default() - }, DocumentNodeDefinition { name: "Extract Opaque", category: "Image Adjustments", @@ -912,26 +904,26 @@ fn static_nodes() -> Vec { }, DocumentNode { name: "RedNode".to_string(), - inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::Red), false)], + inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false)], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractChannelNode<_>")), ..Default::default() }, DocumentNode { name: "GreenNode".to_string(), - inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::Green), false)], + inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Green), false)], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractChannelNode<_>")), ..Default::default() }, DocumentNode { name: "BlueNode".to_string(), - inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::Blue), false)], + inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Blue), false)], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractChannelNode<_>")), ..Default::default() }, DocumentNode { name: "AlphaNode".to_string(), - inputs: vec![NodeInput::node(NodeId(0), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractAlphaNode<>")), + inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Alpha), false)], + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::ExtractChannelNode<>")), ..Default::default() }, ] diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index fdcdf3a4..2ed0f174 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -10,7 +10,8 @@ use graph_craft::document::{DocumentNode, NodeId, NodeInput}; use graph_craft::imaginate_input::{ImaginateSamplingMethod, ImaginateServerStatus, ImaginateStatus}; use graphene_core::memo::IORecord; use graphene_core::raster::{ - BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RelativeAbsolute, SelectiveColorChoice, + BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute, + SelectiveColorChoice, }; use graphene_core::text::Font; use graphene_core::vector::style::{FillType, GradientType, LineCap, LineJoin}; @@ -400,6 +401,33 @@ fn color_channel(document_node: &DocumentNode, node_id: NodeId, index: usize, na LayoutGroup::Row { widgets }.with_tooltip("Color Channel") } +fn rgba_channel(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { + let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); + if let &NodeInput::Value { + tagged_value: TaggedValue::RedGreenBlueAlpha(mode), + exposed: false, + } = &document_node.inputs[index] + { + let calculation_modes = [RedGreenBlueAlpha::Red, RedGreenBlueAlpha::Green, RedGreenBlueAlpha::Blue, RedGreenBlueAlpha::Alpha]; + let mut entries = Vec::with_capacity(calculation_modes.len()); + for method in calculation_modes { + entries.push( + MenuListEntry::new(format!("{method:?}")) + .label(method.to_string()) + .on_update(update_value(move |_| TaggedValue::RedGreenBlueAlpha(method), node_id, index)) + .on_commit(commit_value), + ); + } + let entries = vec![entries]; + + widgets.extend_from_slice(&[ + Separator::new(SeparatorType::Unrelated).widget_holder(), + DropdownInput::new(entries).selected_index(Some(mode as u32)).widget_holder(), + ]); + } + LayoutGroup::Row { widgets }.with_tooltip("Color Channel") +} + // TODO Generalize this instead of using a separate function per dropdown menu enum fn noise_type(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> LayoutGroup { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::General, blank_assist); @@ -971,7 +999,7 @@ pub fn insert_channel_properties(document_node: &DocumentNode, node_id: NodeId, } pub fn extract_channel_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { - let color_channel = color_channel(document_node, node_id, 1, "From", true); + let color_channel = rgba_channel(document_node, node_id, 1, "From", true); vec![color_channel] } diff --git a/node-graph/gcore/src/raster/adjustments.rs b/node-graph/gcore/src/raster/adjustments.rs index c4ed020c..d63d4ad6 100644 --- a/node-graph/gcore/src/raster/adjustments.rs +++ b/node-graph/gcore/src/raster/adjustments.rs @@ -256,22 +256,14 @@ pub struct ExtractChannelNode { } #[node_macro::node_fn(ExtractChannelNode)] -fn extract_channel_node(color: Color, channel: RedGreenBlue) -> Color { +fn extract_channel_node(color: Color, channel: RedGreenBlueAlpha) -> Color { let extracted_value = match channel { - RedGreenBlue::Red => color.r(), - RedGreenBlue::Green => color.g(), - RedGreenBlue::Blue => color.b(), + RedGreenBlueAlpha::Red => color.r(), + RedGreenBlueAlpha::Green => color.g(), + RedGreenBlueAlpha::Blue => color.b(), + RedGreenBlueAlpha::Alpha => color.a(), }; - color.map_rgb(|_| extracted_value) -} - -#[derive(Debug, Clone, Copy, Default)] -pub struct ExtractAlphaNode; - -#[node_macro::node_fn(ExtractAlphaNode)] -fn extract_alpha_node(color: Color) -> Color { - let alpha = color.a(); - Color::from_rgbaf32(alpha, alpha, alpha, 1.).unwrap() + color.map_rgba(|_| extracted_value) } #[derive(Debug, Clone, Copy, Default)] @@ -606,6 +598,27 @@ impl core::fmt::Display for RedGreenBlue { } } +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(feature = "std", derive(specta::Type))] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] +pub enum RedGreenBlueAlpha { + Red, + Green, + Blue, + Alpha, +} + +impl core::fmt::Display for RedGreenBlueAlpha { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + match self { + RedGreenBlueAlpha::Red => write!(f, "Red"), + RedGreenBlueAlpha::Green => write!(f, "Green"), + RedGreenBlueAlpha::Blue => write!(f, "Blue"), + RedGreenBlueAlpha::Alpha => write!(f, "Alpha"), + } + } +} + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "std", derive(specta::Type))] #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, DynAny)] diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index 3133ccc6..c9c1aa29 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -46,6 +46,7 @@ pub enum TaggedValue { VecF64(Vec), VecDVec2(Vec), RedGreenBlue(graphene_core::raster::RedGreenBlue), + RedGreenBlueAlpha(graphene_core::raster::RedGreenBlueAlpha), NoiseType(graphene_core::raster::NoiseType), FractalType(graphene_core::raster::FractalType), CellularDistanceFunction(graphene_core::raster::CellularDistanceFunction), @@ -114,6 +115,7 @@ impl Hash for TaggedValue { Self::VecF64(x) => x.iter().for_each(|val| val.to_bits().hash(state)), Self::VecDVec2(x) => x.iter().for_each(|val| val.to_array().iter().for_each(|x| x.to_bits().hash(state))), Self::RedGreenBlue(x) => x.hash(state), + Self::RedGreenBlueAlpha(x) => x.hash(state), Self::NoiseType(x) => x.hash(state), Self::FractalType(x) => x.hash(state), Self::CellularDistanceFunction(x) => x.hash(state), @@ -189,6 +191,7 @@ impl<'a> TaggedValue { TaggedValue::VecF64(x) => Box::new(x), TaggedValue::VecDVec2(x) => Box::new(x), TaggedValue::RedGreenBlue(x) => Box::new(x), + TaggedValue::RedGreenBlueAlpha(x) => Box::new(x), TaggedValue::NoiseType(x) => Box::new(x), TaggedValue::FractalType(x) => Box::new(x), TaggedValue::CellularDistanceFunction(x) => Box::new(x), @@ -266,6 +269,7 @@ impl<'a> TaggedValue { TaggedValue::VecF64(_) => concrete!(Vec), TaggedValue::VecDVec2(_) => concrete!(Vec), TaggedValue::RedGreenBlue(_) => concrete!(graphene_core::raster::RedGreenBlue), + TaggedValue::RedGreenBlueAlpha(_) => concrete!(graphene_core::raster::RedGreenBlueAlpha), TaggedValue::NoiseType(_) => concrete!(graphene_core::raster::NoiseType), TaggedValue::FractalType(_) => concrete!(graphene_core::raster::FractalType), TaggedValue::CellularDistanceFunction(_) => concrete!(graphene_core::raster::CellularDistanceFunction), @@ -330,6 +334,7 @@ impl<'a> TaggedValue { x if x == TypeId::of::>() => Ok(TaggedValue::VecF64(*downcast(input).unwrap())), x if x == TypeId::of::>() => Ok(TaggedValue::VecDVec2(*downcast(input).unwrap())), x if x == TypeId::of::() => Ok(TaggedValue::RedGreenBlue(*downcast(input).unwrap())), + x if x == TypeId::of::() => Ok(TaggedValue::RedGreenBlueAlpha(*downcast(input).unwrap())), x if x == TypeId::of::() => Ok(TaggedValue::NoiseType(*downcast(input).unwrap())), x if x == TypeId::of::() => Ok(TaggedValue::FractalType(*downcast(input).unwrap())), x if x == TypeId::of::() => Ok(TaggedValue::CellularDistanceFunction(*downcast(input).unwrap())), diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index fccdcf83..f71ab461 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -451,8 +451,7 @@ fn node_registry() -> HashMap, input: ImageFrame, output: ImageFrame, params: [ImageFrame, Vec, BrushCache]), // Filters raster_node!(graphene_core::raster::LuminanceNode<_>, params: [LuminanceCalculation]), - raster_node!(graphene_core::raster::ExtractChannelNode<_>, params: [RedGreenBlue]), - raster_node!(graphene_core::raster::ExtractAlphaNode<>, params: []), + raster_node!(graphene_core::raster::ExtractChannelNode<_>, params: [RedGreenBlueAlpha]), raster_node!(graphene_core::raster::ExtractOpaqueNode<>, params: []), raster_node!(graphene_core::raster::LevelsNode<_, _, _, _, _>, params: [f64, f64, f64, f64, f64]), register_node!(graphene_std::image_segmentation::ImageSegmentationNode<_>, input: ImageFrame, params: [ImageFrame]),