mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-17 15:28:04 +08:00
Add "Blend" node (#1024)
* Add Blend node * Add more implementations Currently, known buggy implementations: * Color Burn * Saturation Opacity is currently achieved by linear interpolation, this will be changed as soon as all filters are implemented. * Add more implementations Currently, known incorrect implementations: * Color Burn * Saturation Not yet Tested: * Linear Burn * Linear Dodge * Vivid Light * Linear Light * Pin Light * Hard Mix * Subtract * Divide Opacity is currently achieved by linear interpolation, this will be changed as soon as all filters are implemented. * Cleanup * Removed Unused Code * Fixed Clamping Issue * Fixed Inverted Opacity * Moved Opacity Calculation from individual Blend Functions into 'blend_node' function * Fix 'Color Burn' blend mode Currently, known incorrect implementations: * Saturation Not yet Tested: * Linear Burn * Darker Color * Linear Dodge * Lighter Color * Vivid Light * Linear Light * Pin Light * Hard Mix * Subtract * Divide Opacity is currently achieved by linear interpolation, this will be changed as soon as all filters are implemented. * Fix 'Saturation' blend mode Currently, known incorrect implementations: * None :D Not yet Tested: * Linear Burn * Darker Color * Linear Dodge * Lighter Color * Vivid Light * Linear Light * Pin Light * Hard Mix * Subtract * Divide Opacity is currently achieved by linear interpolation, this will be changed as soon as all filters are implemented. * Final Cleanups * Add proper Inputs * cargo fmt * Add test for doubling number * Display implementation for ProtoNetwork * Switch top and bottom * Add input types for blend image node * Fix test --------- Co-authored-by: 0hypercube <0hypercube@gmail.com> Co-authored-by: Dennis Kobert <dennis@kobert.dev>
This commit is contained in:
@@ -7,8 +7,9 @@ use graph_craft::document::value::*;
|
||||
use graph_craft::document::*;
|
||||
use graph_craft::imaginate_input::ImaginateSamplingMethod;
|
||||
|
||||
use graph_craft::concrete;
|
||||
use graph_craft::NodeIdentifier;
|
||||
use graphene_core::raster::{Color, Image, ImageFrame, LuminanceCalculation};
|
||||
use graphene_core::raster::{BlendMode, Color, Image, ImageFrame, LuminanceCalculation};
|
||||
use graphene_core::*;
|
||||
|
||||
use std::collections::VecDeque;
|
||||
@@ -192,6 +193,19 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
properties: |_document_node, _node_id, _context| node_properties::string_properties("Creates an embedded image with the given transform"),
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Blend Node",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeImplementation::proto("graphene_core::raster::BlendNode<_, _, _, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::value("Second", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::value("BlendMode", TaggedValue::BlendMode(BlendMode::Normal), false),
|
||||
DocumentInputType::value("Opacity", TaggedValue::F64(100.), false),
|
||||
],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
properties: node_properties::blend_properties,
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Levels",
|
||||
category: "Image Adjustments",
|
||||
|
||||
@@ -8,7 +8,7 @@ use glam::DVec2;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{DocumentNode, NodeId, NodeInput};
|
||||
use graph_craft::imaginate_input::*;
|
||||
use graphene_core::raster::{Color, LuminanceCalculation};
|
||||
use graphene_core::raster::{BlendMode, Color, LuminanceCalculation};
|
||||
|
||||
use super::document_node_types::NodePropertiesContext;
|
||||
use super::{FrontendGraphDataType, IMAGINATE_NODE};
|
||||
@@ -148,7 +148,27 @@ fn number_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, na
|
||||
widgets
|
||||
}
|
||||
|
||||
// TODO: Generalize this for all dropdowns
|
||||
//TODO Use generalized Version of this as soon as it's available
|
||||
fn blend_mode(document_node: &DocumentNode, node_id: u64, 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::BlendMode(mode),
|
||||
exposed: false,
|
||||
} = &document_node.inputs[index]
|
||||
{
|
||||
let calculation_modes = BlendMode::list();
|
||||
let mut entries = Vec::with_capacity(calculation_modes.len());
|
||||
for method in calculation_modes {
|
||||
entries.push(DropdownEntryData::new(method.to_string()).on_update(update_value(move |_| TaggedValue::BlendMode(method), node_id, index)));
|
||||
}
|
||||
let entries = vec![entries];
|
||||
|
||||
widgets.extend_from_slice(&[WidgetHolder::unrelated_separator(), DropdownInput::new(entries).selected_index(Some(mode as u32)).widget_holder()]);
|
||||
}
|
||||
LayoutGroup::Row { widgets }.with_tooltip("Formula used for blending")
|
||||
}
|
||||
|
||||
// TODO: Generalize this for all dropdowns ( also see blend_mode )
|
||||
fn luminance_calculation(document_node: &DocumentNode, node_id: u64, 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 {
|
||||
@@ -238,6 +258,14 @@ pub fn grayscale_properties(document_node: &DocumentNode, node_id: NodeId, _cont
|
||||
]
|
||||
}
|
||||
|
||||
pub fn blend_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let backdrop = color_widget(document_node, node_id, 1, "Backdrop", ColorInput::default(), true);
|
||||
let blend_mode = blend_mode(document_node, node_id, 2, "Blend Mode", true);
|
||||
let opacity = number_widget(document_node, node_id, 3, "Opacity", NumberInput::default().min(0.).max(100.).unit("%"), true);
|
||||
|
||||
vec![backdrop, blend_mode, LayoutGroup::Row { widgets: opacity }]
|
||||
}
|
||||
|
||||
pub fn luminance_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
let luma_calculation = luminance_calculation(document_node, node_id, 1, "Luma Calculation", true);
|
||||
|
||||
|
||||
@@ -33,11 +33,13 @@ impl NodeGraphExecutor {
|
||||
network.duplicate_outputs(&mut generate_uuid);
|
||||
network.remove_dead_nodes();
|
||||
|
||||
debug!("Execute document network:\n{network:#?}");
|
||||
|
||||
// We assume only one output
|
||||
assert_eq!(network.outputs.len(), 1, "Graph with multiple outputs not yet handled");
|
||||
let c = Compiler {};
|
||||
let proto_network = c.compile_single(network, true)?;
|
||||
|
||||
debug!("Execute proto network:\n{proto_network}");
|
||||
assert_ne!(proto_network.nodes.len(), 0, "No protonodes exist?");
|
||||
if let Err(e) = self.executor.update(proto_network) {
|
||||
error!("Failed to update executor:\n{}", e);
|
||||
|
||||
Reference in New Issue
Block a user