Implement blur as a document node (#987)
* Implement blur as a document node * Reuse node node registry * Add comment explaining the use of once cell * Fix rebase error
This commit is contained in:
parent
898b0bb582
commit
0531df18d5
|
|
@ -2,8 +2,8 @@ use super::{node_properties, FrontendGraphDataType, FrontendNodeType};
|
|||
use crate::messages::layout::utility_types::layout_widget::LayoutGroup;
|
||||
|
||||
use graph_craft::concrete;
|
||||
use graph_craft::document::value::*;
|
||||
use graph_craft::document::*;
|
||||
use graph_craft::document::{value::*, DocumentNodeImplementation};
|
||||
use graph_craft::imaginate_input::ImaginateSamplingMethod;
|
||||
use graph_craft::proto::{NodeIdentifier, Type};
|
||||
use graphene_core::raster::Image;
|
||||
|
|
@ -40,21 +40,85 @@ pub struct NodePropertiesContext<'a> {
|
|||
pub nested_path: &'a [NodeId],
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum NodeImplementation {
|
||||
ProtoNode(NodeIdentifier),
|
||||
DocumentNode(NodeNetwork),
|
||||
}
|
||||
|
||||
impl NodeImplementation {
|
||||
pub const fn proto(name: &'static str, types: &'static [Type]) -> Self {
|
||||
Self::ProtoNode(NodeIdentifier::new(name, types))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct DocumentNodeType {
|
||||
pub name: &'static str,
|
||||
pub category: &'static str,
|
||||
pub identifier: NodeIdentifier,
|
||||
pub identifier: NodeImplementation,
|
||||
pub inputs: &'static [DocumentInputType],
|
||||
pub outputs: &'static [FrontendGraphDataType],
|
||||
pub properties: fn(&DocumentNode, NodeId, &mut NodePropertiesContext) -> Vec<LayoutGroup>,
|
||||
}
|
||||
|
||||
fn document_node_types() -> Vec<DocumentNodeType> {
|
||||
let mut vec: Vec<_> = STATIC_NODES.to_vec();
|
||||
|
||||
const INPUTS: &[DocumentInputType] = &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Radius", TaggedValue::U32(3), false),
|
||||
DocumentInputType::new("Sigma", TaggedValue::F64(1.), false),
|
||||
];
|
||||
|
||||
let blur = DocumentNodeType {
|
||||
name: "Gaussian Blur",
|
||||
category: "Image Filters",
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![0, 1, 1],
|
||||
output: 1,
|
||||
nodes: vec![
|
||||
(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: "CacheNode".to_string(),
|
||||
inputs: vec![NodeInput::Network],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::memo::CacheNode", &[concrete!("Image")])),
|
||||
metadata: Default::default(),
|
||||
},
|
||||
),
|
||||
(
|
||||
1,
|
||||
DocumentNode {
|
||||
name: "BlurNode".to_string(),
|
||||
inputs: vec![NodeInput::Node(0), NodeInput::Network, NodeInput::Network],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::BlurNode", &[])),
|
||||
metadata: Default::default(),
|
||||
},
|
||||
),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: INPUTS,
|
||||
outputs: &[FrontendGraphDataType::Raster],
|
||||
properties: node_properties::blur_image_properties,
|
||||
};
|
||||
vec.push(blur);
|
||||
vec
|
||||
}
|
||||
|
||||
// We use the once cell for lazy initialization to avoid the overhead of reconstructing the node list every time.
|
||||
// TODO: make document nodes not require a `'static` lifetime to avoid having to split the construction into const and non-const parts.
|
||||
static DOCUMENT_NODE_TYPES: once_cell::sync::Lazy<Vec<DocumentNodeType>> = once_cell::sync::Lazy::new(document_node_types);
|
||||
|
||||
// TODO: Dynamic node library
|
||||
static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
||||
static STATIC_NODES: &[DocumentNodeType] = &[
|
||||
DocumentNodeType {
|
||||
name: "Identity",
|
||||
category: "General",
|
||||
identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
inputs: &[DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
|
|
@ -66,7 +130,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Image",
|
||||
category: "Ignore",
|
||||
identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
inputs: &[DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), false)],
|
||||
outputs: &[FrontendGraphDataType::Raster],
|
||||
properties: |_document_node, _node_id, _context| node_properties::string_properties("A bitmap image embedded in this node"),
|
||||
|
|
@ -74,7 +138,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Input",
|
||||
category: "Ignore",
|
||||
identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
inputs: &[DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::Raster,
|
||||
|
|
@ -86,7 +150,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Output",
|
||||
category: "Ignore",
|
||||
identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
inputs: &[DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::Raster,
|
||||
|
|
@ -98,7 +162,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Grayscale",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::GrayscaleNode", &[]),
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::GrayscaleNode", &[]),
|
||||
inputs: &[DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true)],
|
||||
outputs: &[FrontendGraphDataType::Raster],
|
||||
properties: node_properties::no_properties,
|
||||
|
|
@ -107,7 +171,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "GpuImage",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::executor::MapGpuSingleImageNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType {
|
||||
|
|
@ -123,7 +187,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "QuantizeImage",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::quantization::GenerateQuantizationNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::quantization::GenerateQuantizationNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType {
|
||||
name: "Image",
|
||||
|
|
@ -144,22 +208,10 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
outputs: &[FrontendGraphDataType::Raster],
|
||||
properties: node_properties::quantize_properties,
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Gaussian Blur",
|
||||
category: "Image Filters",
|
||||
identifier: NodeIdentifier::new("graphene_core::raster::BlurNode", &[]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Radius", TaggedValue::U32(3), false),
|
||||
DocumentInputType::new("Sigma", TaggedValue::F64(1.), false),
|
||||
],
|
||||
outputs: &[FrontendGraphDataType::Raster],
|
||||
properties: node_properties::blur_image_properties,
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Cache",
|
||||
category: "Structural",
|
||||
identifier: NodeIdentifier::new("graphene_std::memo::CacheNode", &[concrete!("Image")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::memo::CacheNode", &[concrete!("Image")]),
|
||||
inputs: &[DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true)],
|
||||
outputs: &[FrontendGraphDataType::Raster],
|
||||
properties: node_properties::no_properties,
|
||||
|
|
@ -167,7 +219,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Invert RGB",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::InvertRGBNode", &[]),
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::InvertRGBNode", &[]),
|
||||
inputs: &[DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true)],
|
||||
outputs: &[FrontendGraphDataType::Raster],
|
||||
properties: node_properties::no_properties,
|
||||
|
|
@ -175,7 +227,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Hue/Saturation",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::HueSaturationNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::HueSaturationNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Hue Shift", TaggedValue::F64(0.), false),
|
||||
|
|
@ -188,7 +240,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Brightness/Contrast",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::BrightnessContrastNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::BrightnessContrastNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Brightness", TaggedValue::F64(0.), false),
|
||||
|
|
@ -200,7 +252,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Gamma",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::GammaNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::GammaNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Gamma", TaggedValue::F64(1.), false),
|
||||
|
|
@ -211,7 +263,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Opacity",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::OpacityNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::OpacityNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Factor", TaggedValue::F64(1.), false),
|
||||
|
|
@ -222,7 +274,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Posterize",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::PosterizeNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::PosterizeNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Value", TaggedValue::F64(5.), false),
|
||||
|
|
@ -233,7 +285,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Exposure",
|
||||
category: "Image Adjustments",
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::ExposureNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::ExposureNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Value", TaggedValue::F64(0.), false),
|
||||
|
|
@ -245,7 +297,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Add",
|
||||
category: "Math",
|
||||
identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_core::ops::AddNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Input", TaggedValue::F64(0.), true),
|
||||
DocumentInputType::new("Addend", TaggedValue::F64(0.), true),
|
||||
|
|
@ -256,7 +308,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
/*DocumentNodeType {
|
||||
name: "Unit Circle Generator",
|
||||
category: "Vector",
|
||||
identifier: NodeIdentifier::new("graphene_std::vector::generator_nodes::UnitCircleGenerator", &[]),
|
||||
identifier: NodeImplementation::proto("graphene_std::vector::generator_nodes::UnitCircleGenerator", &[]),
|
||||
inputs: &[DocumentInputType::none()],
|
||||
outputs: &[FrontendGraphDataType::Subpath],
|
||||
properties: node_properties::no_properties,
|
||||
|
|
@ -264,7 +316,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Unit Square Generator",
|
||||
category: "Vector",
|
||||
identifier: NodeIdentifier::new("graphene_std::vector::generator_nodes::UnitSquareGenerator", &[]),
|
||||
identifier: NodeImplementation::proto("graphene_std::vector::generator_nodes::UnitSquareGenerator", &[]),
|
||||
inputs: &[DocumentInputType::none()],
|
||||
outputs: &[FrontendGraphDataType::Subpath],
|
||||
properties: node_properties::no_properties,
|
||||
|
|
@ -272,7 +324,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Path Generator",
|
||||
category: "Vector",
|
||||
identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode", &[concrete!("Any<'_>")]),
|
||||
inputs: &[DocumentInputType {
|
||||
name: "Path Data",
|
||||
data_type: FrontendGraphDataType::Subpath,
|
||||
|
|
@ -284,7 +336,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Transform Subpath",
|
||||
category: "Vector",
|
||||
identifier: NodeIdentifier::new("graphene_std::vector::generator_nodes::TransformSubpathNode", &[]),
|
||||
identifier: NodeImplementation::proto("graphene_std::vector::generator_nodes::TransformSubpathNode", &[]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Subpath", TaggedValue::Subpath(Subpath::empty()), true),
|
||||
DocumentInputType::new("Translation", TaggedValue::DVec2(DVec2::ZERO), false),
|
||||
|
|
@ -298,7 +350,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
DocumentNodeType {
|
||||
name: "Blit Subpath",
|
||||
category: "Vector",
|
||||
identifier: NodeIdentifier::new("graphene_std::vector::generator_nodes::BlitSubpath", &[]),
|
||||
identifier: NodeImplementation::proto("graphene_std::vector::generator_nodes::BlitSubpath", &[]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Subpath", TaggedValue::Subpath(Subpath::empty()), true),
|
||||
|
|
@ -311,7 +363,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
|
|||
pub const IMAGINATE_NODE: DocumentNodeType = DocumentNodeType {
|
||||
name: "Imaginate",
|
||||
category: "Image Synthesis",
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::ImaginateNode", &[concrete!("&TypeErasedNode")]),
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::ImaginateNode", &[concrete!("&TypeErasedNode")]),
|
||||
inputs: &[
|
||||
DocumentInputType::new("Input Image", TaggedValue::Image(Image::empty()), true),
|
||||
DocumentInputType::new("Seed", TaggedValue::F64(0.), false),
|
||||
|
|
@ -353,24 +405,30 @@ pub fn collect_node_types() -> Vec<FrontendNodeType> {
|
|||
impl DocumentNodeType {
|
||||
/// Generate a [`DocumentNodeImplementation`] from this node type, using a nested network.
|
||||
pub fn generate_implementation(&self) -> DocumentNodeImplementation {
|
||||
let number_of_inputs = self.inputs.len();
|
||||
let network = NodeNetwork {
|
||||
inputs: (0..number_of_inputs).map(|_| 0).collect(),
|
||||
output: 0,
|
||||
nodes: [(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: format!("{}_impl", self.name),
|
||||
// TODO: Allow inserting nodes that contain other nodes.
|
||||
implementation: DocumentNodeImplementation::Unresolved(self.identifier.clone()),
|
||||
inputs: (0..number_of_inputs).map(|_| NodeInput::Network).collect(),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
let num_inputs = self.inputs.len();
|
||||
|
||||
let inner_network = match &self.identifier {
|
||||
NodeImplementation::ProtoNode(ident) => {
|
||||
NodeNetwork {
|
||||
inputs: (0..num_inputs).map(|_| 0).collect(),
|
||||
output: 0,
|
||||
nodes: [(
|
||||
0,
|
||||
DocumentNode {
|
||||
name: format!("{}_impl", self.name),
|
||||
// TODO: Allow inserting nodes that contain other nodes.
|
||||
implementation: DocumentNodeImplementation::Unresolved(ident.clone()),
|
||||
inputs: (0..num_inputs).map(|_| NodeInput::Network).collect(),
|
||||
metadata: DocumentNodeMetadata::default(),
|
||||
},
|
||||
)]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
NodeImplementation::DocumentNode(network) => network.clone(),
|
||||
};
|
||||
DocumentNodeImplementation::Network(network)
|
||||
DocumentNodeImplementation::Network(inner_network)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use crate::consts::DRAG_THRESHOLD;
|
|||
use crate::messages::frontend::utility_types::MouseCursorIcon;
|
||||
use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeysGroup, MouseMotion};
|
||||
use crate::messages::layout::utility_types::layout_widget::PropertyHolder;
|
||||
use crate::messages::portfolio::document::node_graph::IMAGINATE_NODE;
|
||||
use crate::messages::portfolio::document::node_graph::{NodeImplementation, IMAGINATE_NODE};
|
||||
use crate::messages::prelude::*;
|
||||
use crate::messages::tool::common_functionality::resize::Resize;
|
||||
use crate::messages::tool::utility_types::{EventToMessageMap, Fsm, ToolActionHandlerData, ToolMetadata, ToolTransition, ToolType};
|
||||
|
|
|
|||
Loading…
Reference in New Issue