mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Add automatic type conversion and the node graph preprocessor (#2478)
* Prototype document network level into node insertion * Implement Convert trait / node for places we can't use Into * Add isize/usize and i128/u128 implementations for Convert trait * Factor out substitutions into preprocessor crate * Simplify layer node further * Code review * Mark preprocessed networks as generated * Revert changes to layer node definition * Skip generated flag for serialization * Don't expand for tests * Code review --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
@@ -15,7 +15,7 @@ use graphene_std::GraphicElement;
|
||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, IntoTypeErasedNode};
|
||||
use graphene_std::application_io::{ImageTexture, SurfaceFrame};
|
||||
use graphene_std::wasm_application_io::*;
|
||||
use node_registry_macros::{async_node, into_node};
|
||||
use node_registry_macros::{async_node, convert_node, into_node};
|
||||
use once_cell::sync::Lazy;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
@@ -23,10 +23,7 @@ use wgpu_executor::{WgpuExecutor, WgpuSurface, WindowHandle};
|
||||
|
||||
// TODO: turn into hashmap
|
||||
fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>> {
|
||||
let node_types: Vec<(ProtoNodeIdentifier, NodeConstructor, NodeIOTypes)> = vec![
|
||||
into_node!(from: f64, to: f64),
|
||||
into_node!(from: u32, to: f64),
|
||||
into_node!(from: u8, to: u32),
|
||||
let mut node_types: Vec<(ProtoNodeIdentifier, NodeConstructor, NodeIOTypes)> = vec![
|
||||
into_node!(from: VectorDataTable, to: VectorDataTable),
|
||||
into_node!(from: VectorDataTable, to: GraphicElement),
|
||||
into_node!(from: VectorDataTable, to: GraphicGroupTable),
|
||||
@@ -35,6 +32,7 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
into_node!(from: RasterDataTable<CPU>, to: RasterDataTable<CPU>),
|
||||
// into_node!(from: RasterDataTable<CPU>, to: RasterDataTable<SRGBA8>),
|
||||
into_node!(from: RasterDataTable<CPU>, to: GraphicElement),
|
||||
into_node!(from: RasterDataTable<GPU>, to: GraphicElement),
|
||||
into_node!(from: RasterDataTable<CPU>, to: GraphicGroupTable),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => RasterDataTable<CPU>]),
|
||||
async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]),
|
||||
@@ -137,6 +135,26 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
},
|
||||
),
|
||||
];
|
||||
node_types.extend(
|
||||
[
|
||||
convert_node!(from: f32, to: numbers),
|
||||
convert_node!(from: f64, to: numbers),
|
||||
convert_node!(from: i8, to: numbers),
|
||||
convert_node!(from: u8, to: numbers),
|
||||
convert_node!(from: u16, to: numbers),
|
||||
convert_node!(from: i16, to: numbers),
|
||||
convert_node!(from: i32, to: numbers),
|
||||
convert_node!(from: u32, to: numbers),
|
||||
convert_node!(from: i64, to: numbers),
|
||||
convert_node!(from: u64, to: numbers),
|
||||
convert_node!(from: i128, to: numbers),
|
||||
convert_node!(from: u128, to: numbers),
|
||||
convert_node!(from: isize, to: numbers),
|
||||
convert_node!(from: usize, to: numbers),
|
||||
]
|
||||
.into_iter()
|
||||
.flatten(),
|
||||
);
|
||||
|
||||
let mut map: HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>> = HashMap::new();
|
||||
|
||||
@@ -151,12 +169,14 @@ fn node_registry() -> HashMap<ProtoNodeIdentifier, HashMap<NodeIOTypes, NodeCons
|
||||
// This occurs for the ChannelMixerNode presumably because of the long name.
|
||||
// This might be caused by the stringify! macro
|
||||
let mut new_name = id.name.replace('\n', " ");
|
||||
// Remove struct generics for all nodes except for the IntoNode
|
||||
if !new_name.contains("IntoNode") {
|
||||
|
||||
// Remove struct generics for all nodes except for the IntoNode and ConvertNode
|
||||
if !(new_name.contains("IntoNode") || new_name.contains("ConvertNode")) {
|
||||
if let Some((path, _generics)) = new_name.split_once("<") {
|
||||
new_name = path.to_string();
|
||||
}
|
||||
}
|
||||
|
||||
let nid = ProtoNodeIdentifier { name: Cow::Owned(new_name) };
|
||||
map.entry(nid).or_default().insert(types.clone(), c);
|
||||
}
|
||||
@@ -203,9 +223,8 @@ mod node_registry_macros {
|
||||
(from: $from:ty, to: $to:ty) => {
|
||||
(
|
||||
ProtoNodeIdentifier::new(concat!["graphene_core::ops::IntoNode<", stringify!($to), ">"]),
|
||||
|mut args| {
|
||||
|_| {
|
||||
Box::pin(async move {
|
||||
args.reverse();
|
||||
let node = graphene_core::ops::IntoNode::<$to>::new();
|
||||
let any: DynAnyNode<$from, _, _> = graphene_std::any::DynAnyNode::new(node);
|
||||
Box::new(any) as TypeErasedBox
|
||||
@@ -220,7 +239,47 @@ mod node_registry_macros {
|
||||
)
|
||||
};
|
||||
}
|
||||
macro_rules! convert_node {
|
||||
(from: $from:ty, to: numbers) => {{
|
||||
let x: Vec<(ProtoNodeIdentifier, NodeConstructor, NodeIOTypes)> = vec![
|
||||
convert_node!(from: $from, to: f32),
|
||||
convert_node!(from: $from, to: f64),
|
||||
convert_node!(from: $from, to: i8),
|
||||
convert_node!(from: $from, to: u8),
|
||||
convert_node!(from: $from, to: u16),
|
||||
convert_node!(from: $from, to: i16),
|
||||
convert_node!(from: $from, to: i32),
|
||||
convert_node!(from: $from, to: u32),
|
||||
convert_node!(from: $from, to: i64),
|
||||
convert_node!(from: $from, to: u64),
|
||||
convert_node!(from: $from, to: i128),
|
||||
convert_node!(from: $from, to: u128),
|
||||
convert_node!(from: $from, to: isize),
|
||||
convert_node!(from: $from, to: usize),
|
||||
];
|
||||
x
|
||||
}};
|
||||
(from: $from:ty, to: $to:ty) => {
|
||||
(
|
||||
ProtoNodeIdentifier::new(concat!["graphene_core::ops::ConvertNode<", stringify!($to), ">"]),
|
||||
|_| {
|
||||
Box::pin(async move {
|
||||
let node = graphene_core::ops::ConvertNode::<$to>::new();
|
||||
let any: DynAnyNode<$from, _, _> = graphene_std::any::DynAnyNode::new(node);
|
||||
Box::new(any) as TypeErasedBox
|
||||
})
|
||||
},
|
||||
{
|
||||
let node = graphene_core::ops::ConvertNode::<$to>::new();
|
||||
let mut node_io = NodeIO::<'_, $from>::to_async_node_io(&node, vec![]);
|
||||
node_io.call_argument = future!(<$from as StaticType>::Static);
|
||||
node_io
|
||||
},
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) use async_node;
|
||||
pub(crate) use convert_node;
|
||||
pub(crate) use into_node;
|
||||
}
|
||||
|
||||
@@ -78,5 +78,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork, editor_api: Arc<WasmEdito
|
||||
exports: vec![NodeInput::node(NodeId(1), 0)],
|
||||
nodes: nodes.into_iter().enumerate().map(|(id, node)| (NodeId(id as u64), node)).collect(),
|
||||
scope_injections: [("editor-api".to_string(), (NodeId(2), concrete!(&WasmEditorApi)))].into_iter().collect(),
|
||||
// TODO(TrueDoctor): check if it makes sense to set `generated` to `true`
|
||||
generated: false,
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user