mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-08-03 21:08:18 +00:00
Improve previewing node data (#1446)
* Improve preview * Improve contrast * Restructure in order to duplicate code * Code review nits --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
parent
c823016316
commit
e0ac073805
18 changed files with 326 additions and 202 deletions
|
@ -2,7 +2,7 @@
|
|||
|
||||
## Purpose of Nodes
|
||||
|
||||
Graphite is an image editor which is centred around a node based editing workflow, which allows operations to be visually connected in a graph. This is flexible as it allows all operations to be viewed or modified at any time without losing original data. The node system has been designed to be as general as possible with all data types being representable and a broad selection of nodes for a variety of use cases being planned.
|
||||
Graphite is an image editor which is centered around a node based editing workflow, which allows operations to be visually connected in a graph. This is flexible as it allows all operations to be viewed or modified at any time without losing original data. The node system has been designed to be as general as possible with all data types being representable and a broad selection of nodes for a variety of use cases being planned.
|
||||
|
||||
## The Document Graph
|
||||
|
||||
|
|
|
@ -204,6 +204,18 @@ impl<'a, T> AsRef<EditorApi<'a, T>> for EditorApi<'a, T> {
|
|||
}
|
||||
}
|
||||
|
||||
// Required for the EndLetNode
|
||||
impl<'a, IO> From<EditorApi<'a, IO>> for Footprint {
|
||||
fn from(value: EditorApi<'a, IO>) -> Self {
|
||||
value.render_config.viewport
|
||||
}
|
||||
}
|
||||
|
||||
// Required for the EndLetNode
|
||||
impl<'a, IO> From<EditorApi<'a, IO>> for () {
|
||||
fn from(_value: EditorApi<'a, IO>) -> Self {}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct ExtractImageFrame;
|
||||
|
||||
|
|
|
@ -88,6 +88,15 @@ impl SvgRender {
|
|||
self.svg.push("</svg>");
|
||||
}
|
||||
|
||||
/// Wraps the SVG with `<svg><g transform="...">`, which allows for rotation
|
||||
pub fn wrap_with_transform(&mut self, transform: DAffine2) {
|
||||
let defs = &self.svg_defs;
|
||||
|
||||
let svg_header = format!(r#"<svg xmlns="http://www.w3.org/2000/svg"><defs>{defs}</defs><g transform="{}">"#, format_transform_matrix(transform));
|
||||
self.svg.insert(0, svg_header.into());
|
||||
self.svg.push("</g></svg>");
|
||||
}
|
||||
|
||||
pub fn leaf_tag(&mut self, name: impl Into<SvgSegment>, attributes: impl FnOnce(&mut SvgRenderAttrs)) {
|
||||
self.indent();
|
||||
self.svg.push("<");
|
||||
|
@ -97,6 +106,11 @@ impl SvgRender {
|
|||
self.svg.push("/>");
|
||||
}
|
||||
|
||||
pub fn leaf_node(&mut self, content: impl Into<SvgSegment>) {
|
||||
self.indent();
|
||||
self.svg.push(content);
|
||||
}
|
||||
|
||||
pub fn parent_tag(&mut self, name: impl Into<SvgSegment>, attributes: impl FnOnce(&mut SvgRenderAttrs), inner: impl FnOnce(&mut Self)) {
|
||||
let name = name.into();
|
||||
self.indent();
|
||||
|
@ -359,6 +373,55 @@ impl GraphicElementRendered for GraphicElementData {
|
|||
}
|
||||
}
|
||||
|
||||
/// Used to stop rust complaining about upstream traits adding display implementations to `Option<Color>`. This would not be an issue as we control that crate.
|
||||
trait Primitive: core::fmt::Display {}
|
||||
impl Primitive for String {}
|
||||
impl Primitive for bool {}
|
||||
impl Primitive for f32 {}
|
||||
impl Primitive for f64 {}
|
||||
|
||||
fn text_attributes(attributes: &mut SvgRenderAttrs) {
|
||||
attributes.push("fill", "white");
|
||||
attributes.push("y", "30");
|
||||
attributes.push("font-size", "30");
|
||||
}
|
||||
|
||||
impl<T: Primitive> GraphicElementRendered for T {
|
||||
fn render_svg(&self, render: &mut SvgRender, _render_params: &RenderParams) {
|
||||
render.parent_tag("text", text_attributes, |render| render.leaf_node(format!("{self}")));
|
||||
}
|
||||
|
||||
fn bounding_box(&self, _transform: DAffine2) -> Option<[DVec2; 2]> {
|
||||
None
|
||||
}
|
||||
|
||||
fn add_click_targets(&self, _click_targets: &mut Vec<ClickTarget>) {}
|
||||
}
|
||||
|
||||
impl GraphicElementRendered for Option<Color> {
|
||||
fn render_svg(&self, render: &mut SvgRender, _render_params: &RenderParams) {
|
||||
let Some(color) = self else {
|
||||
render.parent_tag("text", |_| {}, |render| render.leaf_node("Empty color"));
|
||||
return;
|
||||
};
|
||||
|
||||
render.leaf_tag("rect", |attributes| {
|
||||
attributes.push("width", "100");
|
||||
attributes.push("height", "100");
|
||||
attributes.push("y", "40");
|
||||
attributes.push("fill", format!("#{}", color.rgba_hex()));
|
||||
});
|
||||
let color_info = format!("{:?} #{} {:?}", color, color.rgba_hex(), color.to_rgba8_srgb());
|
||||
render.parent_tag("text", text_attributes, |render| render.leaf_node(color_info))
|
||||
}
|
||||
|
||||
fn bounding_box(&self, _transform: DAffine2) -> Option<[DVec2; 2]> {
|
||||
None
|
||||
}
|
||||
|
||||
fn add_click_targets(&self, _click_targets: &mut Vec<ClickTarget>) {}
|
||||
}
|
||||
|
||||
/// A segment of an svg string to allow for embedding blob urls
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum SvgSegment {
|
||||
|
|
|
@ -111,23 +111,24 @@ impl<T> LetNode<T> {
|
|||
|
||||
/// Caches the output of a given Node and acts as a proxy
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct EndLetNode<Input> {
|
||||
pub struct EndLetNode<Input, Parameter> {
|
||||
input: Input,
|
||||
paramenter: PhantomData<Parameter>,
|
||||
}
|
||||
impl<'i, T: 'i, Input> Node<'i, T> for EndLetNode<Input>
|
||||
impl<'i, T: 'i, Parameter: 'i + From<T>, Input> Node<'i, T> for EndLetNode<Input, Parameter>
|
||||
where
|
||||
Input: Node<'i, ()>,
|
||||
Input: Node<'i, Parameter>,
|
||||
{
|
||||
type Output = <Input>::Output;
|
||||
fn eval(&'i self, _: T) -> Self::Output {
|
||||
let result = self.input.eval(());
|
||||
fn eval(&'i self, t: T) -> Self::Output {
|
||||
let result = self.input.eval(Parameter::from(t));
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl<Input> EndLetNode<Input> {
|
||||
pub const fn new(input: Input) -> EndLetNode<Input> {
|
||||
EndLetNode { input }
|
||||
impl<Input, Parameter> EndLetNode<Input, Parameter> {
|
||||
pub const fn new(input: Input) -> EndLetNode<Input, Parameter> {
|
||||
EndLetNode { input, paramenter: PhantomData }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,8 @@ pub struct GenerateBrightnessContrastMapperNode<Brightness, Contrast> {
|
|||
contrast: Contrast,
|
||||
}
|
||||
|
||||
// TODO: Replace this node implementation with one that reuses the more generalized Curves adjustment node.
|
||||
// TODO: It will be necessary to ensure the tests below are faithfully translated in a way that ensures identical results.
|
||||
#[node_macro::node_fn(GenerateBrightnessContrastMapperNode)]
|
||||
fn brightness_contrast_node(_primary: (), brightness: f32, contrast: f32) -> BrightnessContrastMapperNode {
|
||||
// Brightness LUT
|
||||
|
|
|
@ -127,12 +127,12 @@ impl Gradient {
|
|||
|
||||
// Compute the color of the inserted stop
|
||||
let get_color = |index: usize, time: f64| match (self.positions[index].1, self.positions.get(index + 1).and_then(|x| x.1)) {
|
||||
// Lerp between the nearest colours if applicable
|
||||
// Lerp between the nearest colors if applicable
|
||||
(Some(a), Some(b)) => a.lerp(
|
||||
b,
|
||||
((time - self.positions[index].0) / self.positions.get(index + 1).map(|end| end.0 - self.positions[index].0).unwrap_or_default()) as f32,
|
||||
),
|
||||
// Use the start or the end colour if applicable
|
||||
// Use the start or the end color if applicable
|
||||
(Some(v), _) | (_, Some(v)) => v,
|
||||
_ => Color::WHITE,
|
||||
};
|
||||
|
|
|
@ -1019,15 +1019,15 @@ impl NodeNetwork {
|
|||
// We filter out the newly inserted empty stack in case `resolve_empty_stacks` runs multiple times.
|
||||
for node in self.nodes.values_mut().filter(|node| node.name != EMPTY_STACK) {
|
||||
for input in &mut node.inputs {
|
||||
if matches!(
|
||||
input,
|
||||
NodeInput::Value {
|
||||
tagged_value: TaggedValue::GraphicGroup(GraphicGroup::EMPTY),
|
||||
..
|
||||
if let NodeInput::Value {
|
||||
tagged_value: TaggedValue::GraphicGroup(graphic_group),
|
||||
..
|
||||
} = input
|
||||
{
|
||||
if *graphic_group == GraphicGroup::EMPTY {
|
||||
*input = NodeInput::node(new_id, 0);
|
||||
used = true;
|
||||
}
|
||||
) {
|
||||
*input = NodeInput::node(new_id, 0);
|
||||
used = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,7 +141,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork {
|
|||
inner_network,
|
||||
DocumentNode {
|
||||
name: "End Scope".to_string(),
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::memo::EndLetNode<_>"),
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::memo::EndLetNode<_, _>"),
|
||||
inputs: vec![NodeInput::node(0, 0), NodeInput::node(1, 0)],
|
||||
..Default::default()
|
||||
},
|
||||
|
|
|
@ -42,7 +42,7 @@ graphene-core = { path = "../gcore", features = [
|
|||
"alloc",
|
||||
], default-features = false }
|
||||
dyn-any = { path = "../../libraries/dyn-any", features = ["derive"] }
|
||||
graph-craft = { path = "../graph-craft" }
|
||||
graph-craft = { path = "../graph-craft", features = ["serde"] }
|
||||
vulkan-executor = { path = "../vulkan-executor", optional = true }
|
||||
wgpu-executor = { path = "../wgpu-executor", optional = true, version = "0.1" }
|
||||
gpu-executor = { path = "../gpu-executor", optional = true }
|
||||
|
|
|
@ -15,6 +15,7 @@ use graphene_core::{Color, GraphicGroup};
|
|||
#[cfg(target_arch = "wasm32")]
|
||||
use js_sys::{Object, Reflect};
|
||||
use std::collections::HashMap;
|
||||
use std::marker::PhantomData;
|
||||
use std::pin::Pin;
|
||||
use std::sync::Arc;
|
||||
#[cfg(feature = "tokio")]
|
||||
|
@ -288,77 +289,132 @@ fn decode_image_node<'a: 'input>(data: Arc<[u8]>) -> ImageFrame<Color> {
|
|||
}
|
||||
pub use graph_craft::document::value::RenderOutput;
|
||||
|
||||
pub struct RenderNode<Data, Surface> {
|
||||
pub struct RenderNode<Data, Surface, Parameter> {
|
||||
data: Data,
|
||||
surface_handle: Surface,
|
||||
parameter: PhantomData<Parameter>,
|
||||
}
|
||||
|
||||
#[node_macro::node_fn(RenderNode)]
|
||||
async fn render_node<'a: 'input, F: Future<Output = GraphicGroup>>(
|
||||
editor: WasmEditorApi<'a>,
|
||||
data: impl Node<'input, Footprint, Output = F>,
|
||||
fn render_svg(data: impl GraphicElementRendered, mut render: SvgRender, render_params: RenderParams, footprint: Footprint) -> RenderOutput {
|
||||
data.render_svg(&mut render, &render_params);
|
||||
render.wrap_with_transform(footprint.transform);
|
||||
RenderOutput::Svg(render.svg.to_string())
|
||||
}
|
||||
|
||||
#[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
fn render_canvas(
|
||||
data: impl GraphicElementRendered,
|
||||
mut render: SvgRender,
|
||||
render_params: RenderParams,
|
||||
footprint: Footprint,
|
||||
editor: WasmEditorApi<'_>,
|
||||
surface_handle: Arc<SurfaceHandle<HtmlCanvasElement>>,
|
||||
) -> RenderOutput {
|
||||
let footprint = editor.render_config.viewport;
|
||||
let data = self.data.eval(footprint).await;
|
||||
let mut render = SvgRender::new();
|
||||
let render_params = RenderParams::new(ViewMode::Normal, graphene_core::renderer::ImageRenderMode::Base64, None, false);
|
||||
let output_format = editor.render_config.export_format;
|
||||
let resolution = footprint.resolution;
|
||||
data.render_svg(&mut render, &render_params);
|
||||
// TODO: reenable once we switch to full node graph
|
||||
let min = footprint.transform.inverse().transform_point2((0., 0.).into());
|
||||
let max = footprint.transform.inverse().transform_point2(resolution.as_dvec2());
|
||||
render.format_svg(min, max);
|
||||
let string = render.svg.to_string();
|
||||
let array = string.as_bytes();
|
||||
let canvas = &surface_handle.surface;
|
||||
canvas.set_width(resolution.x);
|
||||
canvas.set_height(resolution.y);
|
||||
let usvg_tree = data.to_usvg_tree(resolution, [min, max]);
|
||||
|
||||
match output_format {
|
||||
ExportFormat::Svg => {
|
||||
data.render_svg(&mut render, &render_params);
|
||||
// TODO: reenable once we switch to full node graph
|
||||
let min = footprint.transform.inverse().transform_point2((0., 0.).into());
|
||||
let max = footprint.transform.inverse().transform_point2(resolution.as_dvec2());
|
||||
render.format_svg(min, max);
|
||||
RenderOutput::Svg(render.svg.to_string())
|
||||
}
|
||||
#[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
ExportFormat::Canvas => {
|
||||
data.render_svg(&mut render, &render_params);
|
||||
// TODO: reenable once we switch to full node graph
|
||||
let min = footprint.transform.inverse().transform_point2((0., 0.).into());
|
||||
let max = footprint.transform.inverse().transform_point2(resolution.as_dvec2());
|
||||
render.format_svg(min, max);
|
||||
let string = render.svg.to_string();
|
||||
let array = string.as_bytes();
|
||||
let canvas = &surface_handle.surface;
|
||||
canvas.set_width(resolution.x);
|
||||
canvas.set_height(resolution.y);
|
||||
let usvg_tree = data.to_usvg_tree(resolution, [min, max]);
|
||||
if let Some(exec) = editor.application_io.gpu_executor() {
|
||||
todo!()
|
||||
} else {
|
||||
let rtree = resvg::Tree::from_usvg(&usvg_tree);
|
||||
|
||||
if let Some(exec) = editor.application_io.gpu_executor() {
|
||||
todo!()
|
||||
} else {
|
||||
let rtree = resvg::Tree::from_usvg(&usvg_tree);
|
||||
let pixmap_size = rtree.size.to_int_size();
|
||||
let mut pixmap = resvg::tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap();
|
||||
rtree.render(resvg::tiny_skia::Transform::default(), &mut pixmap.as_mut());
|
||||
let array: Clamped<&[u8]> = Clamped(pixmap.data());
|
||||
let context = canvas.get_context("2d").unwrap().unwrap().dyn_into::<CanvasRenderingContext2d>().unwrap();
|
||||
let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(array, pixmap_size.width(), pixmap_size.height()).expect("Failed to construct ImageData");
|
||||
context.put_image_data(&image_data, 0.0, 0.0).unwrap();
|
||||
}
|
||||
/*
|
||||
let preamble = "data:image/svg+xml;base64,";
|
||||
let mut base64_string = String::with_capacity(preamble.len() + array.len() * 4);
|
||||
base64_string.push_str(preamble);
|
||||
base64::engine::general_purpose::STANDARD.encode_string(array, &mut base64_string);
|
||||
|
||||
let pixmap_size = rtree.size.to_int_size();
|
||||
let mut pixmap = resvg::tiny_skia::Pixmap::new(pixmap_size.width(), pixmap_size.height()).unwrap();
|
||||
rtree.render(resvg::tiny_skia::Transform::default(), &mut pixmap.as_mut());
|
||||
let array: Clamped<&[u8]> = Clamped(pixmap.data());
|
||||
let context = canvas.get_context("2d").unwrap().unwrap().dyn_into::<CanvasRenderingContext2d>().unwrap();
|
||||
let image_data = web_sys::ImageData::new_with_u8_clamped_array_and_sh(array, pixmap_size.width(), pixmap_size.height()).expect("Failed to construct ImageData");
|
||||
context.put_image_data(&image_data, 0.0, 0.0).unwrap();
|
||||
let image_data = web_sys::HtmlImageElement::new().unwrap();
|
||||
image_data.set_src(base64_string.as_str());
|
||||
wasm_bindgen_futures::JsFuture::from(image_data.decode()).await.unwrap();
|
||||
context.draw_image_with_html_image_element(&image_data, 0.0, 0.0).unwrap();
|
||||
*/
|
||||
let frame = SurfaceHandleFrame {
|
||||
surface_handle,
|
||||
transform: DAffine2::IDENTITY,
|
||||
};
|
||||
RenderOutput::CanvasFrame(frame.into())
|
||||
}
|
||||
|
||||
// Render with the data node taking in Footprint.
|
||||
impl<'input, 'a: 'input, T: 'input + GraphicElementRendered, F: 'input + Future<Output = T>, Data: 'input, Surface: 'input, SurfaceFuture: 'input> Node<'input, WasmEditorApi<'a>>
|
||||
for RenderNode<Data, Surface, Footprint>
|
||||
where
|
||||
Data: Node<'input, Footprint, Output = F>,
|
||||
Surface: Node<'input, (), Output = SurfaceFuture>,
|
||||
SurfaceFuture: core::future::Future<Output = Arc<SurfaceHandle<HtmlCanvasElement>>>,
|
||||
{
|
||||
type Output = core::pin::Pin<Box<dyn core::future::Future<Output = RenderOutput> + 'input>>;
|
||||
|
||||
#[inline]
|
||||
fn eval(&'input self, editor: WasmEditorApi<'a>) -> Self::Output {
|
||||
Box::pin(async move {
|
||||
let footprint = editor.render_config.viewport;
|
||||
let render_params = RenderParams::new(ViewMode::Normal, graphene_core::renderer::ImageRenderMode::Base64, None, false);
|
||||
|
||||
let output_format = editor.render_config.export_format;
|
||||
match output_format {
|
||||
ExportFormat::Svg => render_svg(self.data.eval(footprint).await, SvgRender::new(), render_params, footprint),
|
||||
#[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
ExportFormat::Canvas => render_canvas(self.data.eval(footprint).await, SvgRender::new(), render_params, footprint, editor, self.surface_handle.eval(()).await),
|
||||
_ => todo!("Non-SVG render output for {output_format:?}"),
|
||||
}
|
||||
/*
|
||||
let preamble = "data:image/svg+xml;base64,";
|
||||
let mut base64_string = String::with_capacity(preamble.len() + array.len() * 4);
|
||||
base64_string.push_str(preamble);
|
||||
base64::engine::general_purpose::STANDARD.encode_string(array, &mut base64_string);
|
||||
|
||||
let image_data = web_sys::HtmlImageElement::new().unwrap();
|
||||
image_data.set_src(base64_string.as_str());
|
||||
wasm_bindgen_futures::JsFuture::from(image_data.decode()).await.unwrap();
|
||||
context.draw_image_with_html_image_element(&image_data, 0.0, 0.0).unwrap();
|
||||
*/
|
||||
let frame = SurfaceHandleFrame {
|
||||
surface_handle,
|
||||
transform: DAffine2::IDENTITY,
|
||||
};
|
||||
RenderOutput::CanvasFrame(frame.into())
|
||||
}
|
||||
_ => todo!("Non svg render output for {output_format:?}"),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// Render with the data node taking in ().
|
||||
impl<'input, 'a: 'input, T: 'input + GraphicElementRendered, F: 'input + Future<Output = T>, Data: 'input, Surface: 'input, SurfaceFuture: 'input> Node<'input, WasmEditorApi<'a>>
|
||||
for RenderNode<Data, Surface, ()>
|
||||
where
|
||||
Data: Node<'input, (), Output = F>,
|
||||
Surface: Node<'input, (), Output = SurfaceFuture>,
|
||||
SurfaceFuture: core::future::Future<Output = Arc<SurfaceHandle<HtmlCanvasElement>>>,
|
||||
{
|
||||
type Output = core::pin::Pin<Box<dyn core::future::Future<Output = RenderOutput> + 'input>>;
|
||||
#[inline]
|
||||
fn eval(&'input self, editor: WasmEditorApi<'a>) -> Self::Output {
|
||||
Box::pin(async move {
|
||||
use graphene_core::renderer::ImageRenderMode;
|
||||
|
||||
let footprint = editor.render_config.viewport;
|
||||
let render_params = RenderParams::new(ViewMode::Normal, ImageRenderMode::Base64, None, false);
|
||||
|
||||
let output_format = editor.render_config.export_format;
|
||||
match output_format {
|
||||
ExportFormat::Svg => render_svg(self.data.eval(()).await, SvgRender::new(), render_params, footprint),
|
||||
#[cfg(any(feature = "resvg", feature = "vello"))]
|
||||
ExportFormat::Canvas => render_canvas(self.data.eval(()).await, SvgRender::new(), render_params, footprint, editor, self.surface_handle.eval(()).await),
|
||||
_ => todo!("Non-SVG render output for {output_format:?}"),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
#[automatically_derived]
|
||||
impl<Data, Surface, Parameter> RenderNode<Data, Surface, Parameter> {
|
||||
pub const fn new(data: Data, surface_handle: Surface) -> Self {
|
||||
Self {
|
||||
data,
|
||||
surface_handle,
|
||||
parameter: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ use graphene_core::value::{ClonedNode, CopiedNode, ValueNode};
|
|||
use graphene_core::vector::brush_stroke::BrushStroke;
|
||||
use graphene_core::vector::VectorData;
|
||||
use graphene_core::{application_io::SurfaceHandle, SurfaceFrame, WasmSurfaceHandleFrame};
|
||||
use graphene_core::{concrete, generic, GraphicGroup};
|
||||
use graphene_core::{concrete, generic, Artboard, GraphicGroup};
|
||||
use graphene_core::{fn_type, raster::*};
|
||||
use graphene_core::{Cow, NodeIdentifier, Type};
|
||||
use graphene_core::{Node, NodeIO, NodeIOTypes};
|
||||
|
@ -276,7 +276,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
async_node!(graphene_core::ops::IntoNode<_, GraphicGroup>, input: ImageFrame<Color>, output: GraphicGroup, params: []),
|
||||
async_node!(graphene_core::ops::IntoNode<_, GraphicGroup>, input: VectorData, output: GraphicGroup, params: []),
|
||||
async_node!(graphene_core::ops::IntoNode<_, GraphicGroup>, input: GraphicGroup, output: GraphicGroup, params: []),
|
||||
async_node!(graphene_core::ops::IntoNode<_, GraphicGroup>, input: graphene_core::Artboard, output: GraphicGroup, params: []),
|
||||
async_node!(graphene_core::ops::IntoNode<_, GraphicGroup>, input: Artboard, output: GraphicGroup, params: []),
|
||||
#[cfg(feature = "gpu")]
|
||||
async_node!(graphene_core::ops::IntoNode<_, &WgpuExecutor>, input: WasmEditorApi, output: &WgpuExecutor, params: []),
|
||||
register_node!(graphene_std::raster::MaskImageNode<_, _, _>, input: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||
|
@ -546,28 +546,35 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
raster_node!(graphene_core::raster::ExposureNode<_, _, _>, params: [f32, f32, f32]),
|
||||
register_node!(graphene_core::memo::LetNode<_>, input: Option<ImageFrame<Color>>, params: []),
|
||||
register_node!(graphene_core::memo::LetNode<_>, input: Option<WasmEditorApi>, params: []),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: VectorData, params: [VectorData]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: RenderOutput, params: [RenderOutput]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: ImageFrame<Color>, params: [ImageFrame<Color>]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: VectorData, params: [VectorData]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: RenderOutput, params: [RenderOutput]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: RenderOutput, params: [f32]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: RenderOutput, params: [f64]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: RenderOutput, params: [bool]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: RenderOutput, params: [String]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: RenderOutput, params: [Option<Color>]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => VectorData]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => ImageFrame<Color>]),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
graphene_core::memo::EndLetNode<_, _>,
|
||||
input: WasmEditorApi,
|
||||
output: graphene_core::GraphicGroup,
|
||||
params: [graphene_core::GraphicGroup]
|
||||
output: GraphicGroup,
|
||||
params: [GraphicGroup]
|
||||
),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
graphene_core::memo::EndLetNode<_, _>,
|
||||
input: WasmEditorApi,
|
||||
output: graphene_core::Artboard,
|
||||
params: [graphene_core::Artboard]
|
||||
output: Artboard,
|
||||
params: [Artboard]
|
||||
),
|
||||
async_node!(
|
||||
graphene_core::memo::EndLetNode<_>,
|
||||
graphene_core::memo::EndLetNode<_, _>,
|
||||
input: WasmEditorApi,
|
||||
output: WasmSurfaceHandleFrame,
|
||||
params: [WasmSurfaceHandleFrame]
|
||||
),
|
||||
async_node!(graphene_core::memo::EndLetNode<_>, input: WasmEditorApi, output: SurfaceFrame, params: [SurfaceFrame]),
|
||||
async_node!(graphene_core::memo::EndLetNode<_, _>, input: WasmEditorApi, output: SurfaceFrame, params: [SurfaceFrame]),
|
||||
vec![
|
||||
(
|
||||
NodeIdentifier::new("graphene_core::memo::RefNode<_, _>"),
|
||||
|
@ -639,7 +646,19 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
register_node!(graphene_core::quantization::QuantizeNode<_>, input: Color, params: [QuantizationChannels]),
|
||||
register_node!(graphene_core::quantization::DeQuantizeNode<_>, input: PackedPixel, params: [QuantizationChannels]),
|
||||
register_node!(graphene_core::ops::CloneNode<_>, input: &QuantizationChannels, params: []),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => GraphicGroup, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => ImageFrame<Color>, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => VectorData, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => GraphicGroup, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Artboard, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [() => ImageFrame<Color>, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [() => VectorData, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [() => GraphicGroup, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [() => Artboard, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [() => bool, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [() => f32, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [() => f64, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [() => String, () => Arc<WasmSurfaceHandle>]),
|
||||
async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [() => Option<Color>, () => Arc<WasmSurfaceHandle>]),
|
||||
//register_node!(graphene_core::transform::TranformNode<_, _, _, _, _, _>, input: , output: RenderOutput, fn_params: [Footprint => GraphicGroup, () => Arc<WasmSurfaceHandle>]),
|
||||
vec![
|
||||
(
|
||||
|
@ -740,34 +759,32 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
args.reverse();
|
||||
let node = <graphene_core::transform::CullNode<_>>::new(graphene_std::any::input_node::<VectorData>(args.pop().expect("Not enough arguments provided to construct node")));
|
||||
let any: DynAnyNode<Footprint, _, _> = graphene_std::any::DynAnyNode::new(node);
|
||||
Box::new(any) as Box<dyn for<'i> NodeIO<'i, graph_craft::proto::Any<'i>, Output = (core::pin::Pin<Box<dyn core::future::Future<Output = graph_craft::proto::Any<'i>> + 'i>>)> + '_>
|
||||
Box::new(any) as Box<dyn for<'i> NodeIO<'i, graph_craft::proto::Any<'i>, Output = core::pin::Pin<Box<dyn core::future::Future<Output = graph_craft::proto::Any<'i>> + 'i>>> + '_>
|
||||
})
|
||||
},
|
||||
{
|
||||
let node = <graphene_core::transform::CullNode<_>>::new((graphene_std::any::PanicNode::<(), VectorData>::new()));
|
||||
let node = <graphene_core::transform::CullNode<_>>::new(graphene_std::any::PanicNode::<(), VectorData>::new());
|
||||
let params = vec![fn_type!((), VectorData)];
|
||||
let mut node_io = <graphene_core::transform::CullNode<_> as NodeIO<'_, Footprint>>::to_node_io(&node, params);
|
||||
node_io.input = concrete!(<Footprint as StaticType>::Static);
|
||||
node_io
|
||||
},
|
||||
)],
|
||||
register_node!(graphene_core::transform::CullNode<_>, input: Footprint, params: [graphene_core::Artboard]),
|
||||
register_node!(graphene_core::transform::CullNode<_>, input: Footprint, params: [Artboard]),
|
||||
vec![(
|
||||
NodeIdentifier::new("graphene_core::transform::CullNode<_>"),
|
||||
|args| {
|
||||
Box::pin(async move {
|
||||
let mut args = args.clone();
|
||||
args.reverse();
|
||||
let node = <graphene_core::transform::CullNode<_>>::new(graphene_std::any::input_node::<graphene_core::GraphicGroup>(
|
||||
args.pop().expect("Not enough arguments provided to construct node"),
|
||||
));
|
||||
let node = <graphene_core::transform::CullNode<_>>::new(graphene_std::any::input_node::<GraphicGroup>(args.pop().expect("Not enough arguments provided to construct node")));
|
||||
let any: DynAnyNode<Footprint, _, _> = graphene_std::any::DynAnyNode::new(node);
|
||||
Box::new(any) as Box<dyn for<'i> NodeIO<'i, graph_craft::proto::Any<'i>, Output = (core::pin::Pin<Box<dyn core::future::Future<Output = graph_craft::proto::Any<'i>> + 'i>>)> + '_>
|
||||
Box::new(any) as Box<dyn for<'i> NodeIO<'i, graph_craft::proto::Any<'i>, Output = core::pin::Pin<Box<dyn core::future::Future<Output = graph_craft::proto::Any<'i>> + 'i>>> + '_>
|
||||
})
|
||||
},
|
||||
{
|
||||
let node = <graphene_core::transform::CullNode<_>>::new((graphene_std::any::PanicNode::<(), graphene_core::GraphicGroup>::new()));
|
||||
let params = vec![fn_type!((), graphene_core::GraphicGroup)];
|
||||
let node = <graphene_core::transform::CullNode<_>>::new(graphene_std::any::PanicNode::<(), GraphicGroup>::new());
|
||||
let params = vec![fn_type!((), GraphicGroup)];
|
||||
let mut node_io = <graphene_core::transform::CullNode<_> as NodeIO<'_, Footprint>>::to_node_io(&node, params);
|
||||
node_io.input = concrete!(<Footprint as StaticType>::Static);
|
||||
node_io
|
||||
|
@ -792,12 +809,12 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
|
|||
register_node!(graphene_core::text::TextGenerator<_, _, _>, input: WasmEditorApi, params: [String, graphene_core::text::Font, f64]),
|
||||
register_node!(graphene_std::brush::VectorPointsNode, input: VectorData, params: []),
|
||||
register_node!(graphene_core::ExtractImageFrame, input: WasmEditorApi, params: []),
|
||||
async_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => graphene_core::GraphicElementData, () => String, () => BlendMode, () => f32, () => bool, () => bool, () => bool, Footprint => graphene_core::GraphicGroup]),
|
||||
async_node!(graphene_core::ConstructLayerNode<_, _, _, _, _, _, _, _>, input: Footprint, output: GraphicGroup, fn_params: [Footprint => graphene_core::GraphicElementData, () => String, () => BlendMode, () => f32, () => bool, () => bool, () => bool, Footprint => GraphicGroup]),
|
||||
register_node!(graphene_core::ToGraphicElementData, input: graphene_core::vector::VectorData, params: []),
|
||||
register_node!(graphene_core::ToGraphicElementData, input: ImageFrame<Color>, params: []),
|
||||
register_node!(graphene_core::ToGraphicElementData, input: graphene_core::GraphicGroup, params: []),
|
||||
register_node!(graphene_core::ToGraphicElementData, input: graphene_core::Artboard, params: []),
|
||||
register_node!(graphene_core::ConstructArtboardNode<_, _, _, _>, input: graphene_core::GraphicGroup, params: [glam::IVec2, glam::IVec2, Color, bool]),
|
||||
register_node!(graphene_core::ToGraphicElementData, input: GraphicGroup, params: []),
|
||||
register_node!(graphene_core::ToGraphicElementData, input: Artboard, params: []),
|
||||
register_node!(graphene_core::ConstructArtboardNode<_, _, _, _>, input: GraphicGroup, params: [glam::IVec2, glam::IVec2, Color, bool]),
|
||||
];
|
||||
let mut map: HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstructor>> = HashMap::new();
|
||||
for (id, c, types) in node_types.into_iter().flatten() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue