mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-19 19:08:05 +08:00
Integrate the node graph as a Node Graph Frame layer type (#812)
* Add node graph frame tool * Add a brighten * Use the node graph * Fix topological_sort * Update UI * Add icons for the tool and layer type * Avoid serde & use bitmaps to improve performance * Allow serialising a node graph * Fix missing ..Default::default() * Fix incorrect comments * Cache node graph output image * Suppress no-cycle import warning Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use borrow_stack::FixedSizeStack;
|
||||
use graphene_core::generic::FnNode;
|
||||
use graphene_core::ops::{AddNode, IdNode};
|
||||
use graphene_core::ops::AddNode;
|
||||
use graphene_core::raster::color::Color;
|
||||
use graphene_core::structural::{ConsNode, Then};
|
||||
use graphene_core::{AsRefNode, Node};
|
||||
use graphene_core::Node;
|
||||
use graphene_std::any::DowncastBothNode;
|
||||
use graphene_std::any::{Any, DowncastNode, DynAnyNode, IntoTypeErasedNode, TypeErasedNode};
|
||||
use graphene_std::raster::Image;
|
||||
@@ -13,17 +11,12 @@ use graphene_std::raster::Image;
|
||||
use crate::proto::Type;
|
||||
use crate::proto::{ConstructionArgs, NodeIdentifier, ProtoNode, ProtoNodeInput, Type::Concrete};
|
||||
|
||||
use dyn_any::Upcast;
|
||||
|
||||
type NodeConstructor = fn(ProtoNode, &FixedSizeStack<TypeErasedNode<'static>>);
|
||||
|
||||
//TODO: turn into hasmap
|
||||
static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::ops::IdNode",
|
||||
types: &[Concrete("Any<'_>")],
|
||||
},
|
||||
NodeIdentifier::new("graphene_core::ops::IdNode", &[Concrete(std::borrow::Cow::Borrowed("Any<'_>"))]),
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
@@ -32,24 +25,18 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
})
|
||||
},
|
||||
),
|
||||
(NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Generic]), |proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
let node = pre_node.then(graphene_core::ops::IdNode);
|
||||
node.into_type_erased()
|
||||
})
|
||||
}),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::ops::IdNode",
|
||||
types: &[Type::Generic],
|
||||
},
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
let node = pre_node.then(graphene_core::ops::IdNode);
|
||||
node.into_type_erased()
|
||||
})
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::ops::AddNode",
|
||||
types: &[Concrete("u32"), Concrete("u32")],
|
||||
},
|
||||
NodeIdentifier::new(
|
||||
"graphene_core::ops::AddNode",
|
||||
&[Concrete(std::borrow::Cow::Borrowed("u32")), Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
),
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
@@ -61,10 +48,10 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::ops::AddNode",
|
||||
types: &[Concrete("&u32"), Concrete("&u32")],
|
||||
},
|
||||
NodeIdentifier::new(
|
||||
"graphene_core::ops::AddNode",
|
||||
&[Concrete(std::borrow::Cow::Borrowed("&u32")), Concrete(std::borrow::Cow::Borrowed("&u32"))],
|
||||
),
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
@@ -76,10 +63,10 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::ops::AddNode",
|
||||
types: &[Concrete("&u32"), Concrete("u32")],
|
||||
},
|
||||
NodeIdentifier::new(
|
||||
"graphene_core::ops::AddNode",
|
||||
&[Concrete(std::borrow::Cow::Borrowed("&u32")), Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
),
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
@@ -91,10 +78,10 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::structural::ConsNode",
|
||||
types: &[Concrete("&u32"), Concrete("u32")],
|
||||
},
|
||||
NodeIdentifier::new(
|
||||
"graphene_core::structural::ConsNode",
|
||||
&[Concrete(std::borrow::Cow::Borrowed("&u32")), Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
),
|
||||
|proto_node, stack| {
|
||||
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
|
||||
stack.push_fn(move |nodes| {
|
||||
@@ -118,10 +105,10 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::structural::ConsNode",
|
||||
types: &[Concrete("u32"), Concrete("u32")],
|
||||
},
|
||||
NodeIdentifier::new(
|
||||
"graphene_core::structural::ConsNode",
|
||||
&[Concrete(std::borrow::Cow::Borrowed("u32")), Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
),
|
||||
|proto_node, stack| {
|
||||
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
|
||||
stack.push_fn(move |nodes| {
|
||||
@@ -146,10 +133,10 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
),
|
||||
// TODO: create macro to impl for all types
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::structural::ConsNode",
|
||||
types: &[Concrete("&u32"), Concrete("&u32")],
|
||||
},
|
||||
NodeIdentifier::new(
|
||||
"graphene_core::structural::ConsNode",
|
||||
&[Concrete(std::borrow::Cow::Borrowed("&u32")), Concrete(std::borrow::Cow::Borrowed("&u32"))],
|
||||
),
|
||||
|proto_node, stack| {
|
||||
let node_id = proto_node.input.unwrap_node() as usize;
|
||||
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
|
||||
@@ -168,10 +155,7 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::any::DowncastNode",
|
||||
types: &[Concrete("&u32")],
|
||||
},
|
||||
NodeIdentifier::new("graphene_core::any::DowncastNode", &[Concrete(std::borrow::Cow::Borrowed("&u32"))]),
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
@@ -181,10 +165,7 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::value::ValueNode",
|
||||
types: &[Concrete("Any<'_>")],
|
||||
},
|
||||
NodeIdentifier::new("graphene_core::value::ValueNode", &[Concrete(std::borrow::Cow::Borrowed("Any<'_>"))]),
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|_nodes| {
|
||||
if let ConstructionArgs::Value(value) = proto_node.construction_args {
|
||||
@@ -197,69 +178,48 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
})
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::value::ValueNode",
|
||||
types: &[Type::Generic],
|
||||
},
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|_nodes| {
|
||||
if let ConstructionArgs::Value(value) = proto_node.construction_args {
|
||||
let node = FnNode::new(move |_| value.clone().up_box() as Any<'static>);
|
||||
node.into_type_erased()
|
||||
} else {
|
||||
unreachable!()
|
||||
}
|
||||
})
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::raster::GrayscaleNode",
|
||||
types: &[],
|
||||
},
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let node = DynAnyNode::new(graphene_core::raster::GrayscaleNode);
|
||||
|
||||
if let ProtoNodeInput::Node(pre_id) = proto_node.input {
|
||||
let pre_node = nodes.get(pre_id as usize).unwrap();
|
||||
(pre_node).then(node).into_type_erased()
|
||||
} else {
|
||||
node.into_type_erased()
|
||||
}
|
||||
})
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_std::raster::MapImageNode",
|
||||
types: &[],
|
||||
},
|
||||
|proto_node, stack| {
|
||||
let node_id = proto_node.input.unwrap_node() as usize;
|
||||
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
|
||||
stack.push_fn(move |nodes| {
|
||||
let pre_node = nodes.get(node_id).unwrap();
|
||||
|
||||
let operation_node = nodes.get(operation_node_id[0] as usize).unwrap();
|
||||
let operation_node: DowncastBothNode<_, Color, Color> = DowncastBothNode::new(operation_node);
|
||||
let map_node = DynAnyNode::new(graphene_std::raster::MapImageNode::new(operation_node));
|
||||
|
||||
let node = (pre_node).then(map_node);
|
||||
|
||||
node.into_type_erased()
|
||||
})
|
||||
(NodeIdentifier::new("graphene_core::value::ValueNode", &[Type::Generic]), |proto_node, stack| {
|
||||
stack.push_fn(|_nodes| {
|
||||
if let ConstructionArgs::Value(value) = proto_node.construction_args {
|
||||
let node = FnNode::new(move |_| value.clone().up_box() as Any<'static>);
|
||||
node.into_type_erased()
|
||||
} else {
|
||||
unimplemented!()
|
||||
unreachable!()
|
||||
}
|
||||
},
|
||||
),
|
||||
})
|
||||
}),
|
||||
(NodeIdentifier::new("graphene_core::raster::GrayscaleNode", &[]), |proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let node = DynAnyNode::new(graphene_core::raster::GrayscaleNode);
|
||||
|
||||
if let ProtoNodeInput::Node(pre_id) = proto_node.input {
|
||||
let pre_node = nodes.get(pre_id as usize).unwrap();
|
||||
(pre_node).then(node).into_type_erased()
|
||||
} else {
|
||||
node.into_type_erased()
|
||||
}
|
||||
})
|
||||
}),
|
||||
(NodeIdentifier::new("graphene_std::raster::MapImageNode", &[]), |proto_node, stack| {
|
||||
if let ConstructionArgs::Nodes(operation_node_id) = proto_node.construction_args {
|
||||
stack.push_fn(move |nodes| {
|
||||
let operation_node = nodes.get(operation_node_id[0] as usize).unwrap();
|
||||
let operation_node: DowncastBothNode<_, Color, Color> = DowncastBothNode::new(operation_node);
|
||||
let map_node = DynAnyNode::new(graphene_std::raster::MapImageNode::new(operation_node));
|
||||
|
||||
if let ProtoNodeInput::Node(node_id) = proto_node.input {
|
||||
let pre_node = nodes.get(node_id as usize).unwrap();
|
||||
(pre_node).then(map_node).into_type_erased()
|
||||
} else {
|
||||
map_node.into_type_erased()
|
||||
}
|
||||
})
|
||||
} else {
|
||||
unimplemented!()
|
||||
}
|
||||
}),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_std::raster::ImageNode",
|
||||
types: &[Concrete("&str")],
|
||||
},
|
||||
NodeIdentifier::new("graphene_std::raster::ImageNode", &[Concrete(std::borrow::Cow::Borrowed("&str"))]),
|
||||
|_proto_node, stack| {
|
||||
stack.push_fn(|_nodes| {
|
||||
let image = FnNode::new(|s: &str| graphene_std::raster::image_node::<&str>().eval(s).unwrap());
|
||||
@@ -269,10 +229,7 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_std::raster::ExportImageNode",
|
||||
types: &[Concrete("&str")],
|
||||
},
|
||||
NodeIdentifier::new("graphene_std::raster::ExportImageNode", &[Concrete(std::borrow::Cow::Borrowed("&str"))]),
|
||||
|proto_node, stack| {
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(proto_node.input.unwrap_node() as usize).unwrap();
|
||||
@@ -285,10 +242,10 @@ static NODE_REGISTRY: &[(NodeIdentifier<'static>, NodeConstructor)] = &[
|
||||
},
|
||||
),
|
||||
(
|
||||
NodeIdentifier {
|
||||
name: "graphene_core::structural::ConsNode",
|
||||
types: &[Concrete("Image"), Concrete("&str")],
|
||||
},
|
||||
NodeIdentifier::new(
|
||||
"graphene_core::structural::ConsNode",
|
||||
&[Concrete(std::borrow::Cow::Borrowed("Image")), Concrete(std::borrow::Cow::Borrowed("&str"))],
|
||||
),
|
||||
|proto_node, stack| {
|
||||
let node_id = proto_node.input.unwrap_node() as usize;
|
||||
if let ConstructionArgs::Nodes(cons_node_arg) = proto_node.construction_args {
|
||||
@@ -322,11 +279,6 @@ mod protograph_testing {
|
||||
|
||||
use super::*;
|
||||
|
||||
/// Lookup a node by th suffix of the name (for testing only)
|
||||
fn simple_lookup(suffix: &str) -> &(NodeIdentifier, fn(ProtoNode, &FixedSizeStack<TypeErasedNode<'static>>)) {
|
||||
NODE_REGISTRY.iter().find(|node| node.0.name.ends_with(suffix)).unwrap()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn add_values() {
|
||||
let stack = FixedSizeStack::new(256);
|
||||
@@ -339,14 +291,20 @@ mod protograph_testing {
|
||||
let cons_protonode = ProtoNode {
|
||||
construction_args: ConstructionArgs::Nodes(vec![1]),
|
||||
input: ProtoNodeInput::Node(0),
|
||||
identifier: NodeIdentifier::new("graphene_core::structural::ConsNode", &[Concrete("u32"), Concrete("u32")]),
|
||||
identifier: NodeIdentifier::new(
|
||||
"graphene_core::structural::ConsNode",
|
||||
&[Concrete(std::borrow::Cow::Borrowed("u32")), Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
),
|
||||
};
|
||||
push_node(cons_protonode, &stack);
|
||||
|
||||
let add_protonode = ProtoNode {
|
||||
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||
input: ProtoNodeInput::Node(2),
|
||||
identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[Concrete("u32"), Concrete("u32")]),
|
||||
identifier: NodeIdentifier::new(
|
||||
"graphene_core::ops::AddNode",
|
||||
&[Concrete(std::borrow::Cow::Borrowed("u32")), Concrete(std::borrow::Cow::Borrowed("u32"))],
|
||||
),
|
||||
};
|
||||
push_node(add_protonode, &stack);
|
||||
|
||||
@@ -379,7 +337,7 @@ mod protograph_testing {
|
||||
let image_protonode = ProtoNode {
|
||||
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||
input: ProtoNodeInput::None,
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[Concrete("&str")]),
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[Concrete(std::borrow::Cow::Borrowed("&str"))]),
|
||||
};
|
||||
push_node(image_protonode, &stack);
|
||||
|
||||
@@ -394,7 +352,7 @@ mod protograph_testing {
|
||||
let image_protonode = ProtoNode {
|
||||
construction_args: ConstructionArgs::Nodes(vec![]),
|
||||
input: ProtoNodeInput::None,
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[Concrete("&str")]),
|
||||
identifier: NodeIdentifier::new("graphene_std::raster::ImageNode", &[Concrete(std::borrow::Cow::Borrowed("&str"))]),
|
||||
};
|
||||
push_node(image_protonode, &stack);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user