From 501d968899d1bb6f5a99883fb332db1dda61c625 Mon Sep 17 00:00:00 2001 From: "dennis@kobert.dev" Date: Sat, 17 Aug 2024 15:56:22 +0200 Subject: [PATCH] Rebase onto master --- .../gcore/src/graphic_element/renderer.rs | 35 ++-------- node-graph/gstd/Cargo.toml | 7 +- node-graph/gstd/src/wasm_application_io.rs | 68 ++----------------- .../interpreted-executor/src/node_registry.rs | 34 ++++------ shell.nix | 29 +++++--- 5 files changed, 53 insertions(+), 120 deletions(-) diff --git a/node-graph/gcore/src/graphic_element/renderer.rs b/node-graph/gcore/src/graphic_element/renderer.rs index e0c2a19597..481be53ade 100644 --- a/node-graph/gcore/src/graphic_element/renderer.rs +++ b/node-graph/gcore/src/graphic_element/renderer.rs @@ -268,40 +268,15 @@ pub fn to_transform(transform: DAffine2) -> usvg::Transform { usvg::Transform::from_row(cols[0] as f32, cols[1] as f32, cols[2] as f32, cols[3] as f32, cols[4] as f32, cols[5] as f32) } -// TODO: Consider renaming this to better express what it does pub trait GraphicElementRendered { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams); - fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]>; - fn add_click_targets(&self, click_targets: &mut Vec); - - fn to_usvg_node(&self) -> usvg::Node { - let mut render = SvgRender::new(); - let render_params = RenderParams::new(crate::vector::style::ViewMode::Normal, ImageRenderMode::Base64, None, false, false, false); - self.render_svg(&mut render, &render_params); - render.format_svg(DVec2::ZERO, DVec2::ONE); - let svg = render.svg.to_svg_string(); - - let opt = usvg::Options::default(); - - let tree = usvg::Tree::from_str(&svg, &opt).expect("Failed to parse SVG"); - usvg::Node::Group(Box::new(tree.root.clone())) - } - - fn to_usvg_tree(&self, resolution: glam::UVec2, viewbox: [DVec2; 2]) -> usvg::Tree { - let root = match self.to_usvg_node() { - usvg::Node::Group(root_node) => *root_node, - _ => usvg::Group::default(), - }; - usvg::Tree { - size: usvg::Size::from_wh(resolution.x as f32, resolution.y as f32).unwrap(), - view_box: usvg::ViewBox { - rect: usvg::NonZeroRect::from_ltrb(viewbox[0].x as f32, viewbox[0].y as f32, viewbox[1].x as f32, viewbox[1].y as f32).unwrap(), - aspect: usvg::AspectRatio::default(), - }, - root, - } + #[cfg(feature = "vello")] + fn to_vello_scene(&self, transform: DAffine2, context: &mut RenderContext) -> Scene { + let mut scene = vello::Scene::new(); + self.render_to_vello(&mut scene, transform, context); + scene } #[cfg(feature = "vello")] fn render_to_vello(&self, _scene: &mut Scene, _transform: DAffine2, _render_condext: &mut RenderContext) {} diff --git a/node-graph/gstd/Cargo.toml b/node-graph/gstd/Cargo.toml index efc83ec3fd..9a2090c0ec 100644 --- a/node-graph/gstd/Cargo.toml +++ b/node-graph/gstd/Cargo.toml @@ -85,6 +85,9 @@ web-sys = { workspace = true, optional = true, features = [ "HtmlImageElement", "ImageBitmapRenderingContext", ] } +autoquant = { git = "https://github.com/truedoctor/autoquant", optional = true, features = [ + "fitting", +] } -[dev-dependencies] -tokio = { workspace = true, features = ["macros", "rt"] } +# Optional dependencies +image-compare = { version = "0.4.1", optional = true } diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index 13c1d9f246..21d8ac4367 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -1,6 +1,10 @@ -use base64::Engine; -use dyn_any::StaticType; -use graphene_core::application_io::{ApplicationError, ApplicationIo, ExportFormat, RenderConfig, ResourceFuture, SurfaceHandle, SurfaceHandleFrame, SurfaceId}; +pub use graph_craft::document::value::RenderOutput; +pub use graph_craft::wasm_application_io::*; +#[cfg(target_arch = "wasm32")] +use graphene_core::application_io::SurfaceHandle; +use graphene_core::application_io::{ApplicationIo, ExportFormat, RenderConfig}; +#[cfg(target_arch = "wasm32")] +use graphene_core::raster::bbox::Bbox; use graphene_core::raster::Image; use graphene_core::raster::ImageFrame; use graphene_core::renderer::{format_transform_matrix, GraphicElementRendered, ImageRenderMode, RenderParams, RenderSvgSegmentList, SvgRender}; @@ -186,66 +190,8 @@ async fn rasterize<_T: GraphicElementRendered + graphene_core::transform::Transf .draw_image_with_html_image_element_and_dw_and_dh(&image_data, 0., 0., resolution.x as f64, resolution.y as f64) .unwrap(); -pub struct RasterizeVectorNode { - footprint: Footprint, - surface_handle: Surface, -} - -#[node_macro::node_fn(RasterizeVectorNode)] -async fn rasterize_vector<_T: GraphicElementRendered>(data: _T, footprint: Footprint, surface_handle: Arc>) -> ImageFrame { - let mut render = SvgRender::new(); - - let resolution = footprint.resolution; - // 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()); - let render_params = RenderParams { - // TODO: Use correct bounds - culling_bounds: Some([min, max]), - ..Default::default() - }; - - data.render_svg(&mut render, &render_params); - render.format_svg(min, max); - let svg_string = render.svg.to_svg_string(); - - let canvas = &surface_handle.surface; - canvas.set_width(resolution.x); - canvas.set_height(resolution.y); - - let array = svg_string.as_bytes(); - let context = canvas.get_context("2d").unwrap().unwrap().dyn_into::().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 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.).unwrap(); - let rasterized = context.get_image_data(0., 0., resolution.x as f64, resolution.y as f64).unwrap(); - let image = Image::from_image_data(&rasterized.data().0, resolution.x, resolution.y); - ImageFrame { - image, - transform: glam::DAffine2::from_scale(resolution.as_dvec2()), - ..Default::default() - } -} - -// Render with the data node taking in Footprint. -impl<'input, 'a: 'input, T: 'input + GraphicElementRendered, F: 'input + Future, Data: 'input, Surface: 'input, SurfaceFuture: 'input> Node<'input, WasmEditorApi<'a>> - for RenderNode -where - Data: Node<'input, Footprint, Output = F>, - Surface: Node<'input, (), Output = SurfaceFuture>, - SurfaceFuture: core::future::Future>>, -{ - type Output = core::pin::Pin + 'input>>; - let image = Image::from_image_data(&rasterized.data().0, resolution.x as u32, resolution.y as u32); ImageFrame { image, diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index bf742831a2..c964f287f9 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -651,25 +651,21 @@ fn node_registry() -> HashMap, 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 => ImageFrame, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => VectorData, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => GraphicGroup, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Artboard, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => ArtboardGroup, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Option, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, fn_params: [Footprint => Vec, () => Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [ImageFrame, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [VectorData, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [GraphicGroup, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [Artboard, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [bool, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [f32, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [f64, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [String, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [Option, Arc]), - async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: WasmEditorApi, output: RenderOutput, params: [Vec, Arc]), - async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: VectorData, output: ImageFrame, params: [Footprint, Arc]), - async_node!(graphene_std::wasm_application_io::RasterizeVectorNode<_, _>, input: GraphicGroup, output: ImageFrame, params: [Footprint, Arc]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ImageFrame, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => VectorData, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => GraphicGroup, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Artboard, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => ArtboardGroup, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Option, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => Vec, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => bool, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f32, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => f64, () => Option]), + async_node!(graphene_std::wasm_application_io::RenderNode<_, _, _>, input: RenderConfig, output: RenderOutput, fn_params: [() => &WasmEditorApi, Footprint => String, () => Option]), + #[cfg(target_arch = "wasm32")] + async_node!(graphene_std::wasm_application_io::RasterizeNode<_, _>, input: VectorData, output: ImageFrame, params: [Footprint, Arc]), + #[cfg(target_arch = "wasm32")] + async_node!(graphene_std::wasm_application_io::RasterizeNode<_, _>, input: GraphicGroup, output: ImageFrame, params: [Footprint, Arc]), async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: VectorData, fn_params: [Footprint => VectorData, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), // async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: WasmSurfaceHandleFrame, fn_params: [Footprint => WasmSurfaceHandleFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), async_node!(graphene_core::transform::TransformNode<_, _, _, _, _, _>, input: Footprint, output: ImageFrame, fn_params: [Footprint => ImageFrame, () => DVec2, () => f64, () => DVec2, () => DVec2, () => DVec2]), diff --git a/shell.nix b/shell.nix index e1d675b01b..1ca9e01b87 100644 --- a/shell.nix +++ b/shell.nix @@ -41,28 +41,41 @@ let nodejs cargo cargo-watch + cargo-nextest + cargo-expand wasm-pack + binaryen + wasm-bindgen-cli + vulkan-loader + libxkbcommon + llvm + gcc-unwrapped.lib + llvmPackages.libcxxStdenv + pkg-config + # used for profiling + gnuplot + samply + cargo-flamegraph + # For Tauri openssl glib gtk3 libsoup webkitgtk - pkg-config + # For Raw-rs tests + libraw - # Use Mold as a Linke + # Use Mold as a linker mold - ]; + ]; in # Make a shell with the dependencies we need - pkgs.mkShell { - packages = packages; - + pkgs.mkShell { + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath packages; # Hacky way to run Cargo through Mold - LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [pkgs.openssl pkgs.vulkan-loader pkgs.libxkbcommon pkgs.llvmPackages.libcxxStdenv pkgs.gcc-unwrapped.lib pkgs.llvm pkgs.libraw]; shellHook = '' - export LD_LIBRARY_PATH=${pkgs.lib.makeLibraryPath packages}:$LD_LIBRARY_PATH alias cargo='mold --run cargo' ''; }