mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-31 02:07:21 +00:00
Remove unsafe code and clean up the code base in general (#1263)
* Remove unsafe code * Make node graph test syncronous * Add miri step to ci * Remove unsafe from node graph evaluation * Replace operation pseudo_hash with hash based on discriminant * Fix test * Move memo module to core and make it safe * Fix formatting * Remove unused stuff from gstd * Use safe casting for creating key variants * Fix memo node types * Fix ref node * "fix" ub * Use correct input types for ExtractImageFrame * Fix types for async nodes * Fix missing implementation * Manually override output type for async nodes * Fix types for EditorApi * Fix output type for WasmSurfaceHandle * Remove unused miri.yml * Fix incorrect type for cache node
This commit is contained in:
parent
259dcdc628
commit
4e1bfddcd8
43 changed files with 520 additions and 1252 deletions
|
@ -13,18 +13,17 @@ quantization = ["graphene-std/quantization"]
|
|||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
graphene-core = { path = "../gcore", features = ["async", "std" ] }
|
||||
graphene-core = { path = "../gcore", features = ["async", "std"] }
|
||||
graphene-std = { path = "../gstd" }
|
||||
graph-craft = { path = "../graph-craft" }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = ["log-bad-types", "glam"] }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = [
|
||||
"log-bad-types",
|
||||
"glam",
|
||||
] }
|
||||
num-traits = "0.2"
|
||||
borrow_stack = { path = "../borrow_stack" }
|
||||
dyn-clone = "1.0"
|
||||
log = "0.4"
|
||||
serde = { version = "1", features = ["derive"], optional = true }
|
||||
glam = { version = "0.22" }
|
||||
once_cell = "1.17.0"
|
||||
futures = "0.3.28"
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { version = "1.12", features = ["rt", "macros"] }
|
||||
|
|
|
@ -3,12 +3,12 @@ use std::error::Error;
|
|||
use std::sync::{Arc, RwLock};
|
||||
|
||||
use dyn_any::StaticType;
|
||||
use graph_craft::document::value::UpcastNode;
|
||||
use graph_craft::document::value::{TaggedValue, UpcastNode};
|
||||
use graph_craft::document::NodeId;
|
||||
use graph_craft::executor::Executor;
|
||||
use graph_craft::proto::{ConstructionArgs, LocalFuture, ProtoNetwork, ProtoNode, TypingContext};
|
||||
use graph_craft::Type;
|
||||
use graphene_std::any::{Any, TypeErasedPinned, TypeErasedPinnedRef};
|
||||
use graphene_std::any::{TypeErasedPinned, TypeErasedPinnedRef};
|
||||
|
||||
use crate::node_registry;
|
||||
|
||||
|
@ -73,9 +73,9 @@ impl DynamicExecutor {
|
|||
}
|
||||
}
|
||||
|
||||
impl Executor for DynamicExecutor {
|
||||
fn execute<'a>(&'a self, input: Any<'a>) -> LocalFuture<Result<Any<'a>, Box<dyn Error>>> {
|
||||
Box::pin(async move { self.tree.eval_any(self.output, input).await.ok_or_else(|| "Failed to execute".into()) })
|
||||
impl<'a, I: StaticType + 'a> Executor<I, TaggedValue> for &'a DynamicExecutor {
|
||||
fn execute(&self, input: I) -> LocalFuture<Result<TaggedValue, Box<dyn Error>>> {
|
||||
Box::pin(async move { self.tree.eval_tagged_value(self.output, input).await.map_err(|e| e.into()) })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -167,18 +167,17 @@ impl BorrowTree {
|
|||
self.nodes.get(&id).cloned()
|
||||
}
|
||||
|
||||
pub async fn eval<'i, I: StaticType + 'i + Send + Sync, O: StaticType + Send + Sync + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
|
||||
pub async fn eval<'i, I: StaticType + 'i, O: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Option<O> {
|
||||
let node = self.nodes.get(&id).cloned()?;
|
||||
let reader = node.read().unwrap();
|
||||
let output = reader.node.eval(Box::new(input));
|
||||
dyn_any::downcast::<O>(output.await).ok().map(|o| *o)
|
||||
}
|
||||
pub async fn eval_any<'i>(&'i self, id: NodeId, input: Any<'i>) -> Option<Any<'i>> {
|
||||
let node = self.nodes.get(&id)?;
|
||||
// TODO: Comments by @TrueDoctor before this was merged:
|
||||
// TODO: Oof I dislike the evaluation being an unsafe operation but I guess its fine because it only is a lifetime extension
|
||||
// TODO: We should ideally let miri run on a test that evaluates the nodegraph multiple times to check if this contains any subtle UB but this looks fine for now
|
||||
Some(unsafe { (*((&*node.read().unwrap()) as *const NodeContainer)).node.eval(input).await })
|
||||
pub async fn eval_tagged_value<'i, I: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Result<TaggedValue, String> {
|
||||
let node = self.nodes.get(&id).cloned().ok_or_else(|| "Output node not found in executor")?;
|
||||
let reader = node.read().unwrap();
|
||||
let output = reader.node.eval(Box::new(input));
|
||||
TaggedValue::try_from_any(output.await)
|
||||
}
|
||||
|
||||
pub fn free_node(&mut self, id: NodeId) {
|
||||
|
@ -226,12 +225,15 @@ mod test {
|
|||
|
||||
use super::*;
|
||||
|
||||
#[tokio::test]
|
||||
async fn push_node() {
|
||||
#[test]
|
||||
fn push_node_sync() {
|
||||
let mut tree = BorrowTree::default();
|
||||
let val_1_protonode = ProtoNode::value(ConstructionArgs::Value(TaggedValue::U32(2u32)), vec![]);
|
||||
tree.push_node(0, val_1_protonode, &TypingContext::default()).await.unwrap();
|
||||
let context = TypingContext::default();
|
||||
let future = tree.push_node(0, val_1_protonode, &context); //.await.unwrap();
|
||||
futures::executor::block_on(future).unwrap();
|
||||
let _node = tree.get(0).unwrap();
|
||||
assert_eq!(tree.eval(0, ()).await, Some(2u32));
|
||||
let result = futures::executor::block_on(tree.eval(0, ()));
|
||||
assert_eq!(result, Some(2u32));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,45 +7,14 @@ pub mod node_registry;
|
|||
#[cfg(test)]
|
||||
mod tests {
|
||||
use dyn_any::IntoDynAny;
|
||||
use graph_craft::document::value::TaggedValue;
|
||||
use graphene_core::*;
|
||||
use std::borrow::Cow;
|
||||
|
||||
/*
|
||||
use futures::executor::block_on;
|
||||
|
||||
#[test]
|
||||
fn borrow_stack() {
|
||||
let stack = borrow_stack::FixedSizeStack::new(256);
|
||||
unsafe {
|
||||
let dynanynode: DynAnyNode<ValueNode<u32>, (), _, _> = DynAnyNode::new(ValueNode(2_u32));
|
||||
stack.push(dynanynode.into_box());
|
||||
}
|
||||
stack.push_fn(|nodes| {
|
||||
let pre_node = nodes.get(0).unwrap();
|
||||
let downcast: DowncastNode<&TypeErasedNode, &u32> = DowncastNode::new(pre_node);
|
||||
let dynanynode: DynAnyNode<ConsNode<_, Any<'_>>, u32, _, _> = DynAnyNode::new(ConsNode(downcast, PhantomData));
|
||||
dynanynode.into_box()
|
||||
});
|
||||
stack.push_fn(|_| {
|
||||
let dynanynode: DynAnyNode<_, (u32, &u32), _, _> = DynAnyNode::new(AddNode);
|
||||
dynanynode.into_box()
|
||||
});
|
||||
stack.push_fn(|nodes| {
|
||||
let compose_node = nodes[1].after(&nodes[2]);
|
||||
TypeErasedNode(Box::pin(compose_node))
|
||||
});
|
||||
|
||||
let result = unsafe { &stack.get()[0] }.eval_ref(().into_dyn());
|
||||
assert_eq!(*downcast::<&u32>(result).unwrap(), &2_u32);
|
||||
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
||||
assert_eq!(*downcast::<(u32, &u32)>(result).unwrap(), (4_u32, &2_u32));
|
||||
let result = unsafe { &stack.get()[1] }.eval_ref(4_u32.into_dyn());
|
||||
let add = unsafe { &stack.get()[2] }.eval_ref(result);
|
||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||
let add = unsafe { &stack.get()[3] }.eval_ref(4_u32.into_dyn());
|
||||
assert_eq!(*downcast::<u32>(add).unwrap(), 6_u32);
|
||||
}*/
|
||||
|
||||
#[tokio::test]
|
||||
async fn execute_add() {
|
||||
fn execute_add() {
|
||||
use graph_craft::document::*;
|
||||
|
||||
use graph_craft::*;
|
||||
|
@ -109,15 +78,14 @@ mod tests {
|
|||
let compiler = Compiler {};
|
||||
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
||||
|
||||
let exec = DynamicExecutor::new(protograph).await.unwrap_or_else(|e| panic!("Failed to create executor: {}", e));
|
||||
let exec = block_on(DynamicExecutor::new(protograph)).unwrap_or_else(|e| panic!("Failed to create executor: {}", e));
|
||||
|
||||
let result = exec.execute(32_u32.into_dyn()).await.unwrap();
|
||||
let val = *dyn_any::downcast::<u32>(result).unwrap();
|
||||
assert_eq!(val, 33_u32);
|
||||
let result = block_on((&exec).execute(32_u32)).unwrap();
|
||||
assert_eq!(result, TaggedValue::U32(33));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn double_number() {
|
||||
#[test]
|
||||
fn double_number() {
|
||||
use graph_craft::document::*;
|
||||
|
||||
use graph_craft::*;
|
||||
|
@ -158,6 +126,6 @@ mod tests {
|
|||
let compiler = Compiler {};
|
||||
let protograph = compiler.compile_single(network, true).expect("Graph should be generated");
|
||||
|
||||
let _exec = DynamicExecutor::new(protograph).await.map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err();
|
||||
let _exec = block_on(DynamicExecutor::new(protograph)).map(|e| panic!("The network should not type check: {:#?}", e)).unwrap_err();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use graph_craft::document::DocumentNode;
|
||||
use graph_craft::proto::{NodeConstructor, TypeErasedPinned};
|
||||
use graphene_core::ops::IdNode;
|
||||
use graphene_core::quantization::QuantizationChannels;
|
||||
|
@ -10,13 +9,11 @@ use graphene_core::vector::brush_stroke::BrushStroke;
|
|||
use graphene_core::vector::VectorData;
|
||||
use graphene_core::wasm_application_io::WasmSurfaceHandle;
|
||||
use graphene_core::wasm_application_io::*;
|
||||
use graphene_core::{concrete, generic, value_fn};
|
||||
use graphene_core::{concrete, generic};
|
||||
use graphene_core::{fn_type, raster::*};
|
||||
use graphene_core::{Cow, NodeIdentifier, Type, TypeDescriptor};
|
||||
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyInRefNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode, TypeErasedPinnedRef};
|
||||
use graphene_std::brush::*;
|
||||
use graphene_std::memo::{CacheNode, LetNode};
|
||||
use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, FutureWrapperNode, IntoTypeErasedNode};
|
||||
use graphene_std::raster::BlendImageTupleNode;
|
||||
use graphene_std::raster::*;
|
||||
|
||||
|
@ -27,8 +24,8 @@ use std::collections::HashMap;
|
|||
use std::sync::Arc;
|
||||
|
||||
macro_rules! construct_node {
|
||||
($args: ident, $path:ty, [$($type:tt),*]) => { async move {
|
||||
let mut args: Vec<TypeErasedPinnedRef<'static>> = $args.clone();
|
||||
($args: ident, $path:ty, [$($type:ty),*]) => { async move {
|
||||
let mut args = $args.clone();
|
||||
args.reverse();
|
||||
let node = <$path>::new($(
|
||||
{
|
||||
|
@ -60,7 +57,7 @@ macro_rules! register_node {
|
|||
let node = <$path>::new($(
|
||||
graphene_std::any::PanicNode::<(), $type>::new()
|
||||
),*);
|
||||
let params = vec![$(value_fn!($type)),*];
|
||||
let params = vec![$(fn_type!((), $type)),*];
|
||||
let mut node_io = <$path as NodeIO<'_, $input>>::to_node_io(&node, params);
|
||||
node_io.input = concrete!(<$input as StaticType>::Static);
|
||||
node_io
|
||||
|
@ -69,6 +66,38 @@ macro_rules! register_node {
|
|||
]
|
||||
};
|
||||
}
|
||||
macro_rules! async_node {
|
||||
// TODO: we currently need to annotate the type here because the compiler would otherwise (correctly)
|
||||
// assign a Pin<Box<dyn Fututure<Output=T>>> type to the node, which is not what we want for now.
|
||||
($path:ty, input: $input:ty, output: $output:ty, params: [ $($type:ty),*]) => {
|
||||
vec![
|
||||
(
|
||||
NodeIdentifier::new(stringify!($path)),
|
||||
|mut args| {
|
||||
Box::pin(async move {
|
||||
args.reverse();
|
||||
let node = <$path>::new($(graphene_std::any::input_node::<$type>(args.pop().expect("Not enough arguments provided to construct node"))),*);
|
||||
let any: DynAnyNode<$input, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
{
|
||||
let node = <$path>::new($(
|
||||
graphene_std::any::PanicNode::<(), core::pin::Pin<Box<dyn core::future::Future<Output = $type>>>>::new()
|
||||
),*);
|
||||
// TODO: Propagate the future type through the node graph
|
||||
//let params = vec![$(Type::Fn(Box::new(concrete!(())), Box::new(Type::Future(Box::new(concrete!($type)))))),*];
|
||||
let params = vec![$(Type::Fn(Box::new(concrete!(())), Box::new(concrete!($type)))),*];
|
||||
let mut node_io = NodeIO::<'_, $input>::to_node_io(&node, params);
|
||||
node_io.input = concrete!(<$input as StaticType>::Static);
|
||||
node_io.input = concrete!(<$input as StaticType>::Static);
|
||||
node_io.output = concrete!(<$output as StaticType>::Static);
|
||||
node_io
|
||||
},
|
||||
)
|
||||
]
|
||||
};
|
||||
}
|
||||
macro_rules! raster_node {
|
||||
($path:ty, params: [$($type:ty),*]) => {{
|
||||
// this function could also be inlined but serves as a workaround for
|
||||
|
@ -92,7 +121,7 @@ macro_rules! raster_node {
|
|||
})
|
||||
},
|
||||
{
|
||||
let params = vec![$(value_fn!($type)),*];
|
||||
let params = vec![$(fn_type!($type)),*];
|
||||
NodeIOTypes::new(concrete!(Color), concrete!(Color), params)
|
||||
},
|
||||
),
|
||||
|
@ -108,7 +137,7 @@ macro_rules! raster_node {
|
|||
})
|
||||
},
|
||||
{
|
||||
let params = vec![$(value_fn!($type)),*];
|
||||
let params = vec![$(fn_type!($type)),*];
|
||||
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), params)
|
||||
},
|
||||
),
|
||||
|
@ -124,7 +153,7 @@ macro_rules! raster_node {
|
|||
})
|
||||
},
|
||||
{
|
||||
let params = vec![$(value_fn!($type)),*];
|
||||
let params = vec![$(fn_type!($type)),*];
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), params)
|
||||
},
|
||||
)
|
||||
|
@ -208,38 +237,32 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>)],
|
||||
vec![fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>)],
|
||||
),
|
||||
)],
|
||||
register_node!(graphene_std::raster::EmptyImageNode<_, _>, input: DAffine2, params: [Color]),
|
||||
register_node!(graphene_std::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
|
||||
register_node!(graphene_std::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
|
||||
register_node!(graphene_core::wasm_application_io::CreateSurfaceNode, input: &graphene_core::EditorApi, params: []),
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_core::wasm_application_io::DrawImageFrameNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let surface: DowncastBothNode<(), Arc<WasmSurfaceHandle>> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_core::wasm_application_io::DrawImageFrameNode::new(surface);
|
||||
let any: DynAnyNode<ImageFrame<SRGBA8>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<SRGBA8>), concrete!(WasmSurfaceHandleFrame), vec![value_fn!(Arc<WasmSurfaceHandle>)]),
|
||||
)],
|
||||
register_node!(graphene_core::memo::MonitorNode<_>, input: ImageFrame<Color>, params: []),
|
||||
register_node!(graphene_core::memo::MonitorNode<_>, input: graphene_core::GraphicGroup, params: []),
|
||||
register_node!(graphene_core::wasm_application_io::CreateSurfaceNode, input: graphene_core::EditorApi, params: []),
|
||||
async_node!(
|
||||
graphene_core::wasm_application_io::DrawImageFrameNode<_>,
|
||||
input: ImageFrame<SRGBA8>,
|
||||
output: WasmSurfaceHandleFrame,
|
||||
params: [Arc<WasmSurfaceHandle>]
|
||||
),
|
||||
#[cfg(feature = "gpu")]
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_std::executor::MapGpuSingleImageNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let document_node: DowncastBothNode<(), DocumentNode> = DowncastBothNode::new(args[0]);
|
||||
let document_node: DowncastBothNode<(), graph_craft::document::DocumentNode> = DowncastBothNode::new(args[0]);
|
||||
//let document_node = ClonedNode::new(document_node.eval(()));
|
||||
let node = graphene_std::executor::MapGpuNode::new(document_node);
|
||||
let any: DynAnyNode<ImageFrame<Color>, _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(DocumentNode)]),
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(graph_craft::document::DocumentNode)]),
|
||||
)],
|
||||
#[cfg(feature = "gpu")]
|
||||
vec![(
|
||||
|
@ -258,7 +281,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
NodeIOTypes::new(
|
||||
concrete!(ImageFrame<Color>),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f32)],
|
||||
vec![fn_type!(ImageFrame<Color>), fn_type!(BlendMode), fn_type!(f32)],
|
||||
),
|
||||
)],
|
||||
vec![(
|
||||
|
@ -327,28 +350,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>), value_fn!(ImageFrame<Color>), value_fn!(Vec<BrushStroke>)],
|
||||
),
|
||||
)],
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_std::brush::ReduceNode<_, _>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let acc: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let image = acc.eval(()).await;
|
||||
let blend_node = graphene_core::raster::BlendNode::new(ClonedNode::new(BlendMode::Normal), ClonedNode::new(1.0));
|
||||
let _ = &blend_node as &dyn for<'i> Node<'i, (Color, Color), Output = Color>;
|
||||
let node = ReduceNode::new(ClonedNode::new(image), ValueNode::new(BlendImageTupleNode::new(ValueNode::new(blend_node))));
|
||||
//let _ = &node as &dyn for<'i> Node<'i, core::slice::Iter<ImageFrame<Color>>, Output = ImageFrame<Color>>;
|
||||
let node = FutureWrapperNode::new(node);
|
||||
let any: DynAnyNode<Box<dyn Iterator<Item = ImageFrame<Color>> + Sync + Send>, _, _> = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(Box<dyn Iterator<Item = &ImageFrame<Color>> + Sync + Send>),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>)],
|
||||
vec![fn_type!(ImageFrame<Color>), fn_type!(ImageFrame<Color>), fn_type!(Vec<BrushStroke>)],
|
||||
),
|
||||
)],
|
||||
// Filters
|
||||
|
@ -374,7 +376,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
NodeIOTypes::new(
|
||||
concrete!(ImageFrame<Color>),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![value_fn!(ImageFrame<Color>), value_fn!(BlendMode), value_fn!(f64)],
|
||||
vec![fn_type!(ImageFrame<Color>), fn_type!(BlendMode), fn_type!(f64)],
|
||||
),
|
||||
)],
|
||||
raster_node!(graphene_core::raster::GrayscaleNode<_, _, _, _, _, _, _>, params: [Color, f64, f64, f64, f64, f64, f64]),
|
||||
|
@ -417,265 +419,59 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
}
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![value_fn!(f64), value_fn!(f64), value_fn!(bool)]),
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(f64), fn_type!(f64), fn_type!(bool)]),
|
||||
)],
|
||||
raster_node!(graphene_core::raster::OpacityNode<_>, params: [f64]),
|
||||
raster_node!(graphene_core::raster::PosterizeNode<_>, params: [f64]),
|
||||
raster_node!(graphene_core::raster::ExposureNode<_, _, _>, params: [f64, f64, f64]),
|
||||
vec![
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
||||
|_| {
|
||||
Box::pin(async move {
|
||||
let node: LetNode<ImageFrame<Color>> = graphene_std::memo::LetNode::new();
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Option<ImageFrame<Color>>), concrete!(&ImageFrame<Color>), vec![]),
|
||||
register_node!(graphene_core::memo::LetNode<_>, input: Option<ImageFrame<Color>>, params: []),
|
||||
register_node!(graphene_core::memo::LetNode<_>, input: Option<graphene_core::EditorApi>, params: []),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
output: ImageFrame<Color>,
|
||||
params: [ImageFrame<Color>]
|
||||
),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: graphene_core::EditorApi, output: VectorData, params: [VectorData]),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
output: graphene_core::GraphicGroup,
|
||||
params: [graphene_core::GraphicGroup]
|
||||
),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
output: graphene_core::Artboard,
|
||||
params: [graphene_core::Artboard]
|
||||
),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
input: graphene_core::EditorApi,
|
||||
output: WasmSurfaceHandleFrame,
|
||||
params: [WasmSurfaceHandleFrame]
|
||||
),
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_core::memo::RefNode<_, _>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let node: DowncastBothNode<Option<graphene_core::EditorApi>, graphene_core::EditorApi> = graphene_std::any::DowncastBothNode::new(args[0]);
|
||||
let node = <graphene_core::memo::RefNode<_, _>>::new(node);
|
||||
let any: DynAnyNode<(), _, _> = graphene_std::any::DynAnyNode::new(graphene_core::value::ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
concrete!(graphene_core::EditorApi),
|
||||
vec![fn_type!(Option<graphene_core::EditorApi>, graphene_core::EditorApi)],
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::LetNode<_>"),
|
||||
|_| {
|
||||
Box::pin(async move {
|
||||
let node: LetNode<graphene_core::EditorApi> = graphene_std::memo::LetNode::new();
|
||||
let any = graphene_std::any::DynAnyRefNode::new(node);
|
||||
any.into_type_erased()
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Option<graphene_core::EditorApi>), concrete!(&graphene_core::EditorApi), vec![]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned<'_>
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), VectorData> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(VectorData), vec![value_fn!(VectorData)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), graphene_core::GraphicGroup> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(graphene_core::GraphicGroup), vec![value_fn!(graphene_core::GraphicGroup)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), graphene_core::Artboard> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(graphene_core::Artboard), vec![value_fn!(graphene_core::Artboard)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::EndLetNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), WasmSurfaceHandleFrame> = DowncastBothNode::new(args[0]);
|
||||
let node = graphene_std::memo::EndLetNode::new(input);
|
||||
let any: DynAnyInRefNode<graphene_core::EditorApi, _, _> = graphene_std::any::DynAnyInRefNode::new(node);
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(generic!(T), concrete!(WasmSurfaceHandleFrame), vec![value_fn!(WasmSurfaceHandleFrame)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::RefNode<_, _>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let map_fn: DowncastBothNode<Option<graphene_core::EditorApi>, &graphene_core::EditorApi> = DowncastBothNode::new(args[0]);
|
||||
//let map_fn = map_fn.then(EvalSyncNode::new());
|
||||
let node = graphene_std::memo::RefNode::new(map_fn);
|
||||
let any = graphene_std::any::DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(()),
|
||||
concrete!(&graphene_core::EditorApi),
|
||||
vec![fn_type!(Option<graphene_core::EditorApi>, &graphene_core::EditorApi)],
|
||||
),
|
||||
),
|
||||
/*
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::raster::ImaginateNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let cached = graphene_std::any::input_node::<Option<std::sync::Arc<Image<Color>>>>(args[15]);
|
||||
let cached = cached.then(EvalSyncNode::new());
|
||||
let node = graphene_std::raster::ImaginateNode::new(cached);
|
||||
let node = FutureWrapperNode::new(node);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(
|
||||
concrete!(ImageFrame<Color>),
|
||||
concrete!(ImageFrame<Color>),
|
||||
vec![
|
||||
value_fn!(f64),
|
||||
value_fn!(Option<DVec2>),
|
||||
value_fn!(f64),
|
||||
value_fn!(ImaginateSamplingMethod),
|
||||
value_fn!(f64),
|
||||
value_fn!(String),
|
||||
value_fn!(String),
|
||||
value_fn!(bool),
|
||||
value_fn!(f64),
|
||||
value_fn!(Option<Vec<u64>>),
|
||||
value_fn!(bool),
|
||||
value_fn!(f64),
|
||||
value_fn!(ImaginateMaskStartingFill),
|
||||
value_fn!(bool),
|
||||
value_fn!(bool),
|
||||
value_fn!(Option<std::sync::Arc<Image<Color>>>),
|
||||
value_fn!(f64),
|
||||
value_fn!(ImaginateStatus),
|
||||
],
|
||||
),
|
||||
),
|
||||
*/
|
||||
/*
|
||||
(
|
||||
NodeIdentifier::new("graphene_core::raster::BlurNode"),
|
||||
|args| {
|
||||
let radius = DowncastBothNode::<(), u32>::new(args[0]);
|
||||
let sigma = DowncastBothNode::<(), f64>::new(args[1]);
|
||||
let image = DowncastBothRefNode::<Image<Color>, Image<Color>>::new(args[2]);
|
||||
let image = image.then(EvalSyncNode::new());
|
||||
let empty_image: ValueNode<Image<Color>> = ValueNode::new(Image::empty());
|
||||
let empty: TypeNode<_, (), Image<Color>> = TypeNode::new(empty_image.then(CloneNode::new()));
|
||||
use graphene_core::Node;
|
||||
let radius = ClonedNode::new(radius.eval(()));
|
||||
let sigma = ClonedNode::new(sigma.eval(()));
|
||||
|
||||
//let image = &image as &dyn for<'a> Node<'a, (), Output = &'a Image>;
|
||||
// dirty hack: we abuse that the cache node will ignore the input if it is evaluated a second time
|
||||
let image = empty.then(image).then(ImageRefNode::new());
|
||||
|
||||
let window = WindowNode::new(radius, image.clone());
|
||||
let map_gaussian = MapSndNode::new(ValueNode::new(DistanceNode.then(GaussianNode::new(sigma))));
|
||||
let map_distances = MapNode::new(ValueNode::new(map_gaussian));
|
||||
let gaussian_iter = window.then(map_distances);
|
||||
let avg = gaussian_iter.then(WeightedAvgNode::new());
|
||||
let avg: TypeNode<_, u32, Color> = TypeNode::new(avg);
|
||||
let blur_iter = MapNode::new(ValueNode::new(avg));
|
||||
let pixel_iter = image.clone().then(ImageIndexIterNode::new());
|
||||
let blur = pixel_iter.then(blur_iter);
|
||||
let collect = CollectNode {};
|
||||
let vec = blur.then(collect);
|
||||
let new_image = MapImageSliceNode::new(vec);
|
||||
let dimensions = image.then(ImageDimensionsNode::new());
|
||||
let dimensions: TypeNode<_, (), (u32, u32)> = TypeNode::new(dimensions);
|
||||
let new_image = dimensions.then(new_image);
|
||||
let new_image = ForgetNode::new().then(new_image);
|
||||
let new_image = FutureWrapperNode::new(new_image);
|
||||
let node: DynAnyNode<&Image<Color>, _, _> = DynAnyNode::new(ValueNode::new(new_image));
|
||||
Box::pin(node)
|
||||
},
|
||||
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![value_fn!(u32), value_fn!(f64)]),
|
||||
),
|
||||
//register_node!(graphene_std::memo::CacheNode<_>, input: Image<Color>, params: []),
|
||||
*/
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), Image<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<Image<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(Image<Color>), vec![value_fn!(Image<Color>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(ImageFrame<Color>), vec![value_fn!(ImageFrame<Color>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<ImageFrame<Color>, ImageFrame<Color>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<ImageFrame<Color>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(ImageFrame<Color>), concrete!(ImageFrame<Color>), vec![fn_type!(ImageFrame<Color>, ImageFrame<Color>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), QuantizationChannels> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<QuantizationChannels, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(QuantizationChannels), vec![value_fn!(QuantizationChannels)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), Vec<DVec2>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<Vec<DVec2>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(Vec<DVec2>), vec![value_fn!(Vec<DVec2>)]),
|
||||
),
|
||||
(
|
||||
NodeIdentifier::new("graphene_std::memo::CacheNode"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let input: DowncastBothNode<(), Arc<WasmSurfaceHandle>> = DowncastBothNode::new(args[0]);
|
||||
let node: CacheNode<Arc<WasmSurfaceHandle>, _> = graphene_std::memo::CacheNode::new(input);
|
||||
let any = DynAnyNode::new(ValueNode::new(node));
|
||||
Box::pin(any) as TypeErasedPinned
|
||||
})
|
||||
},
|
||||
NodeIOTypes::new(concrete!(()), concrete!(Arc<WasmSurfaceHandle>), vec![value_fn!(Arc<WasmSurfaceHandle>)]),
|
||||
),
|
||||
],
|
||||
)],
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Image<Color>, params: [Image<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: QuantizationChannels, params: [QuantizationChannels]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Vec<DVec2>, params: [Vec<DVec2>]),
|
||||
async_node!(graphene_core::memo::MemoNode<_, _>, input: (), output: Arc<WasmSurfaceHandle>, params: [Arc<WasmSurfaceHandle>]),
|
||||
register_node!(graphene_core::structural::ConsNode<_, _>, input: Image<Color>, params: [&str]),
|
||||
register_node!(graphene_std::raster::ImageFrameNode<_, _>, input: Image<Color>, params: [DAffine2]),
|
||||
#[cfg(feature = "quantization")]
|
||||
|
@ -698,9 +494,9 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
input: Vec<graphene_core::vector::bezier_rs::Subpath<graphene_core::uuid::ManipulatorGroupId>>,
|
||||
params: [Vec<graphene_core::uuid::ManipulatorGroupId>]
|
||||
),
|
||||
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: &graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
|
||||
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: graphene_core::EditorApi, params: [String, graphene_core::text::Font, f64]),
|
||||
register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []),
|
||||
register_node!(graphene_core::ExtractImageFrame, input: &graphene_core::EditorApi, params: []),
|
||||
register_node!(graphene_core::ExtractImageFrame, input: graphene_core::EditorApi, params: []),
|
||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::vector::VectorData, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: ImageFrame<Color>, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||
register_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>, input: graphene_core::GraphicGroup, params: [String, BlendMode, f32, bool, bool, bool, graphene_core::GraphicGroup]),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue