mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-23 23:58:12 +08:00
Lay groundwork for adaptive resolution system (#1395)
* Make transform node accept footprint as input and pass it along to its input use f32 instead of f64 and add default to document node definition * Add cull node * Fix types for Transform and Cull Nodes * Add render config struct * Add Render Node skeleton * Add Render Node to node_registry * Make types macro use macro hygiene * Place Render Node as output * Start making DownresNode footprint aware * Correctly calculate footprint in Transform Node * Add cropping and resizing to downres node * Fix Output node declaration * Fix image transform * Fix Vector Data rendering * Add concept of ImageRenderMode * Take base image size into account when calculating the final image size * Supply viewport transform to the node graph * Start adapting document graph to resolution agnosticism * Make document node short circuting not shift the input index * Apply clippy lints
This commit is contained in:
committed by
Keavon Chambers
parent
239ca698e5
commit
d82f133514
@@ -86,19 +86,6 @@ impl LayoutHolder for ExportDialogMessageHandler {
|
||||
.widget_holder(),
|
||||
];
|
||||
|
||||
let resolution = vec![
|
||||
TextLabel::new("Scale Factor").table_align(true).min_width(100).widget_holder(),
|
||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||
NumberInput::new(Some(self.scale_factor))
|
||||
.unit("")
|
||||
.min(0.)
|
||||
.max((1u64 << std::f64::MANTISSA_DIGITS) as f64)
|
||||
.disabled(self.file_type == FileType::Svg)
|
||||
.on_update(|number_input: &NumberInput| ExportDialogMessage::ScaleFactor(number_input.value.unwrap()).into())
|
||||
.min_width(200)
|
||||
.widget_holder(),
|
||||
];
|
||||
|
||||
let artboards = self.artboards.iter().map(|(&layer, name)| (ExportBounds::Artboard(layer), name.to_string(), false));
|
||||
let mut export_area_options = vec![
|
||||
(ExportBounds::AllArtwork, "All Artwork".to_string(), false),
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::messages::frontend::utility_types::ExportBounds;
|
||||
use crate::messages::frontend::utility_types::FileType;
|
||||
use crate::messages::input_mapper::utility_types::macros::action_keys;
|
||||
use crate::messages::layout::utility_types::widget_prelude::*;
|
||||
use crate::messages::portfolio::document::node_graph::new_raster_network;
|
||||
use crate::messages::portfolio::document::node_graph::NodeGraphHandlerData;
|
||||
use crate::messages::portfolio::document::properties_panel::utility_types::PropertiesPanelMessageHandlerData;
|
||||
use crate::messages::portfolio::document::utility_types::clipboards::Clipboard;
|
||||
@@ -588,21 +589,7 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
||||
|
||||
let image_size = DVec2::new(image.width as f64, image.height as f64);
|
||||
|
||||
let Some(image_node_type) = crate::messages::portfolio::document::node_graph::resolve_document_node_type("Image") else {
|
||||
warn!("Image node should be in registry");
|
||||
return;
|
||||
};
|
||||
let Some(transform_node_type) = crate::messages::portfolio::document::node_graph::resolve_document_node_type("Transform") else {
|
||||
warn!("Transform node should be in registry");
|
||||
return;
|
||||
};
|
||||
let Some(downres_node_type) = crate::messages::portfolio::document::node_graph::resolve_document_node_type("Downres") else {
|
||||
warn!("Downres node should be in registry");
|
||||
return;
|
||||
};
|
||||
|
||||
let path = vec![generate_uuid()];
|
||||
let mut network = NodeNetwork::default();
|
||||
|
||||
// Transform of parent folder
|
||||
let to_parent_folder = self.document_legacy.generate_transform_across_scope(&path[..path.len() - 1], None).unwrap_or_default();
|
||||
@@ -622,19 +609,8 @@ impl MessageHandler<DocumentMessage, (u64, &InputPreprocessorMessageHandler, &Pe
|
||||
|
||||
responses.add(DocumentMessage::StartTransaction);
|
||||
|
||||
network.push_node(
|
||||
image_node_type.to_document_node(
|
||||
[graph_craft::document::NodeInput::value(
|
||||
graph_craft::document::value::TaggedValue::ImageFrame(ImageFrame { image, transform: DAffine2::IDENTITY }),
|
||||
false,
|
||||
)],
|
||||
graph_craft::document::DocumentNodeMetadata::position((8, 4)),
|
||||
),
|
||||
false,
|
||||
);
|
||||
network.push_node(transform_node_type.to_document_node_default_inputs([], Default::default()), true);
|
||||
network.push_node(downres_node_type.to_document_node_default_inputs([], Default::default()), true);
|
||||
network.push_output_node();
|
||||
let image_frame = ImageFrame { image, transform: DAffine2::IDENTITY };
|
||||
let network = new_raster_network(image_frame);
|
||||
|
||||
responses.add(DocumentOperation::AddFrame {
|
||||
path: path.clone(),
|
||||
|
||||
+23
-6
@@ -97,20 +97,24 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
// Locate the node output of the first sibling layer to the new layer
|
||||
let new_id = if let NodeInput::Node { node_id, output_index, .. } = &self.network.nodes.get(&output_node_id)?.inputs[input_index] {
|
||||
let sibling_node = &self.network.nodes.get(node_id)?;
|
||||
let node_id = *node_id;
|
||||
let output_index = *output_index;
|
||||
let sibling_layer = if sibling_node.name == "Layer" {
|
||||
// There is already a layer node
|
||||
NodeOutput::new(*node_id, 0)
|
||||
NodeOutput::new(node_id, 0)
|
||||
} else {
|
||||
// The user has connected another node to the output. Insert a layer node between the output and the node.
|
||||
let node = resolve_document_node_type("Layer").expect("Layer node").default_document_node();
|
||||
let node_id = self.insert_between(generate_uuid(), NodeOutput::new(*node_id, *output_index), output, node, 0, 0, IVec2::new(-8, 0))?;
|
||||
let mut node = resolve_document_node_type("Layer").expect("Layer node").default_document_node();
|
||||
self.add_empty_stack(&mut node);
|
||||
let node_id = self.insert_between(generate_uuid(), NodeOutput::new(node_id, output_index), output, node, 0, 0, IVec2::new(-8, 0))?;
|
||||
NodeOutput::new(node_id, 0)
|
||||
};
|
||||
|
||||
let node = resolve_document_node_type("Layer").expect("Layer node").default_document_node();
|
||||
self.insert_between(new_id, sibling_layer, output, node, 7, 0, IVec2::new(0, 3))
|
||||
} else {
|
||||
let layer_node = resolve_document_node_type("Layer").expect("Node").default_document_node();
|
||||
let mut layer_node = resolve_document_node_type("Layer").expect("Node").default_document_node();
|
||||
self.add_empty_stack(&mut layer_node);
|
||||
self.insert_node_before(new_id, output_node_id, input_index, layer_node, IVec2::new(-5, 3))
|
||||
};
|
||||
|
||||
@@ -125,7 +129,15 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
new_id
|
||||
}
|
||||
|
||||
fn add_empty_stack(&mut self, node: &mut DocumentNode) {
|
||||
let empty_stack = resolve_document_node_type("Empty Stack").expect("EmptyStack node").default_document_node();
|
||||
let empty_id = generate_uuid();
|
||||
self.network.nodes.insert(empty_id, empty_stack);
|
||||
*node.inputs.last_mut().unwrap() = NodeInput::node(empty_id, 0);
|
||||
}
|
||||
|
||||
fn insert_artboard(&mut self, artboard: Artboard, layer: NodeId) -> Option<NodeId> {
|
||||
let cull_node = resolve_document_node_type("Cull").expect("Node").default_document_node();
|
||||
let artboard_node = resolve_document_node_type("Artboard").expect("Node").to_document_node_default_inputs(
|
||||
[
|
||||
None,
|
||||
@@ -137,7 +149,9 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
Default::default(),
|
||||
);
|
||||
self.responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
|
||||
self.insert_node_before(generate_uuid(), layer, 0, artboard_node, IVec2::new(-8, 0))
|
||||
let cull_id = generate_uuid();
|
||||
self.insert_node_before(cull_id, layer, 0, cull_node, IVec2::new(-8, 0));
|
||||
self.insert_node_before(generate_uuid(), cull_id, 0, artboard_node, IVec2::new(-8, 0))
|
||||
}
|
||||
|
||||
fn insert_vector_data(&mut self, subpaths: Vec<Subpath<ManipulatorGroupId>>, layer: NodeId) {
|
||||
@@ -145,6 +159,7 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
let node_type = resolve_document_node_type("Shape").expect("Shape node does not exist");
|
||||
node_type.to_document_node_default_inputs([Some(NodeInput::value(TaggedValue::Subpaths(subpaths), false))], Default::default())
|
||||
};
|
||||
let cull = resolve_document_node_type("Cull").expect("Cull node does not exist").default_document_node();
|
||||
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_document_node();
|
||||
let fill = resolve_document_node_type("Fill").expect("Fill node does not exist").default_document_node();
|
||||
let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist").default_document_node();
|
||||
@@ -155,8 +170,10 @@ impl<'a> ModifyInputsContext<'a> {
|
||||
self.insert_node_before(fill_id, stroke_id, 0, fill, IVec2::new(-8, 0));
|
||||
let transform_id = generate_uuid();
|
||||
self.insert_node_before(transform_id, fill_id, 0, transform, IVec2::new(-8, 0));
|
||||
let cull_id = generate_uuid();
|
||||
self.insert_node_before(cull_id, transform_id, 0, cull, IVec2::new(-8, 0));
|
||||
let shape_id = generate_uuid();
|
||||
self.insert_node_before(shape_id, transform_id, 0, shape, IVec2::new(-8, 0));
|
||||
self.insert_node_before(shape_id, cull_id, 0, shape, IVec2::new(-8, 0));
|
||||
self.responses.add(NodeGraphMessage::SendGraph { should_rerender: true });
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ pub fn get_current_normalized_pivot(inputs: &[NodeInput]) -> DVec2 {
|
||||
if let NodeInput::Value {
|
||||
tagged_value: TaggedValue::DVec2(pivot),
|
||||
..
|
||||
} = inputs[5]
|
||||
} = inputs[4]
|
||||
{
|
||||
pivot
|
||||
} else {
|
||||
|
||||
+161
-109
@@ -13,6 +13,7 @@ use graphene_core::application_io::SurfaceHandle;
|
||||
use graphene_core::raster::brush_cache::BrushCache;
|
||||
use graphene_core::raster::{BlendMode, Color, Image, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RelativeAbsolute, SelectiveColorChoice};
|
||||
use graphene_core::text::Font;
|
||||
use graphene_core::transform::Footprint;
|
||||
use graphene_core::vector::VectorData;
|
||||
use graphene_core::*;
|
||||
|
||||
@@ -101,6 +102,7 @@ pub struct DocumentNodeType {
|
||||
pub outputs: Vec<DocumentOutputType>,
|
||||
pub primary_output: bool,
|
||||
pub properties: fn(&DocumentNode, NodeId, &mut NodePropertiesContext) -> Vec<LayoutGroup>,
|
||||
pub manual_composition: Option<graphene_core::Type>,
|
||||
}
|
||||
|
||||
impl Default for DocumentNodeType {
|
||||
@@ -113,6 +115,7 @@ impl Default for DocumentNodeType {
|
||||
outputs: Default::default(),
|
||||
primary_output: Default::default(),
|
||||
properties: node_properties::no_properties,
|
||||
manual_composition: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -187,7 +190,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
(
|
||||
0,
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::Network(concrete!(graphene_core::vector::VectorData))],
|
||||
name: "To Graphic Element".to_string(),
|
||||
inputs: vec![NodeInput::Network(generic!(T))],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::ToGraphicElementData"),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -196,6 +200,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
(
|
||||
1,
|
||||
DocumentNode {
|
||||
name: "Monitor".to_string(),
|
||||
inputs: vec![NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode<_>"),
|
||||
skip_deduplication: true,
|
||||
@@ -205,6 +210,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
(
|
||||
2,
|
||||
DocumentNode {
|
||||
name: "ConstructLayer".to_string(),
|
||||
manual_composition: Some(concrete!(Footprint)),
|
||||
inputs: vec![
|
||||
NodeInput::node(1, 0),
|
||||
NodeInput::Network(concrete!(String)),
|
||||
@@ -213,9 +220,9 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
NodeInput::Network(concrete!(bool)),
|
||||
NodeInput::Network(concrete!(bool)),
|
||||
NodeInput::Network(concrete!(bool)),
|
||||
NodeInput::Network(concrete!(graphene_core::GraphicGroup)),
|
||||
NodeInput::Network(graphene_core::Type::Fn(Box::new(concrete!(Footprint)), Box::new(concrete!(graphene_core::GraphicGroup)))),
|
||||
],
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::ConstructLayerNode<_, _, _, _, _, _, _>"),
|
||||
implementation: DocumentNodeImplementation::proto("graphene_core::ConstructLayerNode<_, _, _, _, _, _, _, _>"),
|
||||
..Default::default()
|
||||
},
|
||||
),
|
||||
@@ -253,55 +260,14 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Downres",
|
||||
category: "Raster",
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![0],
|
||||
outputs: vec![NodeOutput::new(1, 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
name: "Downres".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(ImageFrame<Color>))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::raster::DownresNode<_>")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
// We currently just clone by default
|
||||
/*DocumentNode {
|
||||
name: "Clone".to_string(),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::CloneNode<_>")),
|
||||
..Default::default()
|
||||
},*/
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (id as NodeId, node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), false)],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
properties: |_document_node, _node_id, _context| node_properties::string_properties("Downres the image to a lower resolution"),
|
||||
name: "Empty Stack",
|
||||
category: "Hidden",
|
||||
identifier: NodeImplementation::proto("graphene_core::transform::CullNode<_>"),
|
||||
manual_composition: Some(concrete!(Footprint)),
|
||||
inputs: vec![DocumentInputType::value("Graphic Group", TaggedValue::GraphicGroup(GraphicGroup::EMPTY), false)],
|
||||
outputs: vec![DocumentOutputType::new("Out", FrontendGraphDataType::Artboard)],
|
||||
..Default::default()
|
||||
},
|
||||
// DocumentNodeType {
|
||||
// name: "Input Frame",
|
||||
// category: "Ignore",
|
||||
// identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
|
||||
// inputs: vec![DocumentInputType {
|
||||
// name: "In",
|
||||
// data_type: FrontendGraphDataType::Raster,
|
||||
// default: NodeInput::Network,
|
||||
// }],
|
||||
// outputs: vec![DocumentOutputType::new("Out", FrontendGraphDataType::Raster)],
|
||||
// properties: node_properties::input_properties,
|
||||
// },
|
||||
DocumentNodeType {
|
||||
name: "Input Frame",
|
||||
category: "Ignore",
|
||||
@@ -374,11 +340,13 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
name: "Create Canvas".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
|
||||
skip_deduplication: true,
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(0, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -417,11 +385,13 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
name: "Create Canvas".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
|
||||
skip_deduplication: true,
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -465,7 +435,7 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
name: "SetNode".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(WasmEditorApi))],
|
||||
manual_composition: Some(concrete!(WasmEditorApi)),
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::SomeNode")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -477,7 +447,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNode {
|
||||
name: "RefNode".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::lambda(1, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::lambda(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::RefNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -533,12 +504,61 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
DocumentNodeType {
|
||||
name: "Output",
|
||||
category: "Ignore",
|
||||
identifier: NodeImplementation::proto("graphene_core::ops::IdNode"),
|
||||
inputs: vec![DocumentInputType {
|
||||
name: "Output",
|
||||
data_type: FrontendGraphDataType::Raster,
|
||||
default: NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
}],
|
||||
identifier: NodeImplementation::DocumentNode(NodeNetwork {
|
||||
inputs: vec![3, 0],
|
||||
outputs: vec![NodeOutput::new(4, 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
name: "EditorApi".to_string(),
|
||||
inputs: vec![NodeInput::Network(concrete!(WasmEditorApi))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Create Canvas".to_string(),
|
||||
inputs: vec![NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::wasm_application_io::CreateSurfaceNode")),
|
||||
skip_deduplication: true,
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Conversion".to_string(),
|
||||
inputs: vec![NodeInput::Network(graphene_core::Type::Fn(Box::new(concrete!(Footprint)), Box::new(generic!(T))))],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IntoNode<_, GraphicGroup>")),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
name: "RenderNode".to_string(),
|
||||
inputs: vec![NodeInput::node(0, 0), NodeInput::node(3, 0), NodeInput::node(2, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_std::wasm_application_io::RenderNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (id as NodeId, node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
DocumentInputType {
|
||||
name: "Output",
|
||||
data_type: FrontendGraphDataType::Raster,
|
||||
default: NodeInput::value(TaggedValue::GraphicGroup(GraphicGroup::default()), true),
|
||||
},
|
||||
DocumentInputType {
|
||||
name: "In",
|
||||
data_type: FrontendGraphDataType::General,
|
||||
default: NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
},
|
||||
],
|
||||
outputs: vec![],
|
||||
properties: node_properties::output_properties,
|
||||
..Default::default()
|
||||
@@ -866,11 +886,9 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
name: "Memoize",
|
||||
category: "Structural",
|
||||
identifier: NodeImplementation::proto("graphene_core::memo::MemoNode<_, _>"),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("ShortCircut", TaggedValue::None, false),
|
||||
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
|
||||
],
|
||||
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeType {
|
||||
@@ -882,14 +900,6 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
properties: |_document_node, _node_id, _context| node_properties::string_properties("A bitmap image embedded in this node"),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Ref",
|
||||
category: "Structural",
|
||||
identifier: NodeImplementation::proto("graphene_core::memo::MemoNode<_, _>"),
|
||||
inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
|
||||
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
|
||||
..Default::default()
|
||||
},
|
||||
#[cfg(feature = "gpu")]
|
||||
DocumentNodeType {
|
||||
name: "Uniform",
|
||||
@@ -912,7 +922,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -963,7 +974,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1014,7 +1026,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1076,7 +1089,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1172,7 +1186,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1223,7 +1238,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1268,7 +1284,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(0, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(0, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -1366,7 +1383,8 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
},
|
||||
DocumentNode {
|
||||
name: "Cache".to_string(),
|
||||
inputs: vec![NodeInput::ShortCircut(concrete!(())), NodeInput::node(1, 0)],
|
||||
manual_composition: Some(concrete!(())),
|
||||
inputs: vec![NodeInput::node(1, 0)],
|
||||
implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::memo::MemoNode<_, _>")),
|
||||
..Default::default()
|
||||
},
|
||||
@@ -2065,6 +2083,24 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Downres",
|
||||
category: "Structural",
|
||||
identifier: NodeImplementation::proto("graphene_std::raster::DownresNode<_>"),
|
||||
manual_composition: Some(concrete!(Footprint)),
|
||||
inputs: vec![DocumentInputType::value("Raseter Data", TaggedValue::ImageFrame(ImageFrame::empty()), true)],
|
||||
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Raster)],
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Cull",
|
||||
category: "Vector",
|
||||
identifier: NodeImplementation::proto("graphene_core::transform::CullNode<_>"),
|
||||
manual_composition: Some(concrete!(Footprint)),
|
||||
inputs: vec![DocumentInputType::value("Vector Data", TaggedValue::VectorData(VectorData::empty()), true)],
|
||||
outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)],
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNodeType {
|
||||
name: "Text",
|
||||
category: "Vector",
|
||||
@@ -2082,9 +2118,10 @@ fn static_nodes() -> Vec<DocumentNodeType> {
|
||||
DocumentNodeType {
|
||||
name: "Transform",
|
||||
category: "Transform",
|
||||
identifier: NodeImplementation::proto("graphene_core::transform::TransformNode<_, _, _, _, _>"),
|
||||
identifier: NodeImplementation::proto("graphene_core::transform::TransformNode<_, _, _, _, _, _>"),
|
||||
manual_composition: Some(concrete!(Footprint)),
|
||||
inputs: vec![
|
||||
DocumentInputType::value("Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
|
||||
DocumentInputType::value("Vector Data", TaggedValue::VectorData(VectorData::empty()), true),
|
||||
DocumentInputType::value("Translation", TaggedValue::DVec2(DVec2::ZERO), false),
|
||||
DocumentInputType::value("Rotation", TaggedValue::F32(0.), false),
|
||||
DocumentInputType::value("Scale", TaggedValue::DVec2(DVec2::ONE), false),
|
||||
@@ -2387,6 +2424,7 @@ impl DocumentNodeType {
|
||||
inputs,
|
||||
implementation: self.generate_implementation(),
|
||||
metadata,
|
||||
manual_composition: self.manual_composition.clone(),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
@@ -2421,7 +2459,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork {
|
||||
if input_type.is_none() {
|
||||
input_type = Some(input.clone());
|
||||
}
|
||||
assert_eq!(input, input_type.as_ref().unwrap(), "Networks wrapped in scope must have the same input type");
|
||||
assert_eq!(input, input_type.as_ref().unwrap(), "Networks wrapped in scope must have the same input type {network:#?}");
|
||||
network_inputs.push(*id);
|
||||
}
|
||||
}
|
||||
@@ -2431,6 +2469,7 @@ pub fn wrap_network_in_scope(mut network: NodeNetwork) -> NodeNetwork {
|
||||
|
||||
// if the network has no inputs, it doesn't need to be wrapped in a scope
|
||||
if len == 0 {
|
||||
log::warn!("Network has no inputs, not wrapping in scope");
|
||||
return network;
|
||||
}
|
||||
|
||||
@@ -2469,19 +2508,18 @@ pub fn new_image_network(output_offset: i32, output_node_id: NodeId) -> NodeNetw
|
||||
resolve_document_node_type("Input Frame")
|
||||
.expect("Input Frame node does not exist")
|
||||
.to_document_node_default_inputs([], DocumentNodeMetadata::position((8, 4))),
|
||||
false,
|
||||
);
|
||||
network.push_node(
|
||||
resolve_document_node_type("Output")
|
||||
.expect("Output node does not exist")
|
||||
.to_document_node([NodeInput::node(output_node_id, 0)], DocumentNodeMetadata::position((output_offset + 8, 4))),
|
||||
false,
|
||||
);
|
||||
network
|
||||
}
|
||||
|
||||
pub fn new_vector_network(subpaths: Vec<bezier_rs::Subpath<uuid::ManipulatorGroupId>>) -> NodeNetwork {
|
||||
let path_generator = resolve_document_node_type("Shape").expect("Shape node does not exist");
|
||||
let cull_node = resolve_document_node_type("Cull").expect("Cull node does not exist");
|
||||
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist");
|
||||
let fill = resolve_document_node_type("Fill").expect("Fill node does not exist");
|
||||
let stroke = resolve_document_node_type("Stroke").expect("Stroke node does not exist");
|
||||
@@ -2489,14 +2527,31 @@ pub fn new_vector_network(subpaths: Vec<bezier_rs::Subpath<uuid::ManipulatorGrou
|
||||
|
||||
let mut network = NodeNetwork::default();
|
||||
|
||||
network.push_node(
|
||||
path_generator.to_document_node_default_inputs([Some(NodeInput::value(TaggedValue::Subpaths(subpaths), false))], DocumentNodeMetadata::position((0, 4))),
|
||||
false,
|
||||
);
|
||||
network.push_node(transform.to_document_node_default_inputs([None], Default::default()), true);
|
||||
network.push_node(fill.to_document_node_default_inputs([None], Default::default()), true);
|
||||
network.push_node(stroke.to_document_node_default_inputs([None], Default::default()), true);
|
||||
network.push_node(output.to_document_node_default_inputs([None], Default::default()), true);
|
||||
network.push_node(path_generator.to_document_node_default_inputs([Some(NodeInput::value(TaggedValue::Subpaths(subpaths), false))], DocumentNodeMetadata::position((0, 4))));
|
||||
network.push_node(cull_node.to_document_node_default_inputs([None], Default::default()));
|
||||
network.push_node(transform.to_document_node_default_inputs([None], Default::default()));
|
||||
network.push_node(fill.to_document_node_default_inputs([None], Default::default()));
|
||||
network.push_node(stroke.to_document_node_default_inputs([None], Default::default()));
|
||||
network.push_node(output.to_document_node_default_inputs([None], Default::default()));
|
||||
network
|
||||
}
|
||||
|
||||
pub fn new_raster_network(image_frame: ImageFrame<Color>) -> NodeNetwork {
|
||||
let sample_node = resolve_document_node_type("Downres").expect("Downres node does not exist");
|
||||
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist");
|
||||
let output = resolve_document_node_type("Output").expect("Output node does not exist");
|
||||
|
||||
let mut network = NodeNetwork::default();
|
||||
|
||||
let image_node_type = resolve_document_node_type("Image").expect("Image node should be in registry");
|
||||
|
||||
network.push_node(image_node_type.to_document_node(
|
||||
[graph_craft::document::NodeInput::value(graph_craft::document::value::TaggedValue::ImageFrame(image_frame), false)],
|
||||
Default::default(),
|
||||
));
|
||||
network.push_node(sample_node.to_document_node_default_inputs([None], Default::default()));
|
||||
network.push_node(transform.to_document_node_default_inputs([None], Default::default()));
|
||||
network.push_node(output.to_document_node_default_inputs([None], Default::default()));
|
||||
network
|
||||
}
|
||||
|
||||
@@ -2511,21 +2566,18 @@ pub fn new_text_network(text: String, font: Font, size: f64) -> NodeNetwork {
|
||||
inputs: vec![0],
|
||||
..Default::default()
|
||||
};
|
||||
network.push_node(
|
||||
text_generator.to_document_node(
|
||||
[
|
||||
NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
NodeInput::value(TaggedValue::String(text), false),
|
||||
NodeInput::value(TaggedValue::Font(font), false),
|
||||
NodeInput::value(TaggedValue::F64(size), false),
|
||||
],
|
||||
DocumentNodeMetadata::position((0, 4)),
|
||||
),
|
||||
false,
|
||||
);
|
||||
network.push_node(transform.to_document_node_default_inputs([None], Default::default()), true);
|
||||
network.push_node(fill.to_document_node_default_inputs([None], Default::default()), true);
|
||||
network.push_node(stroke.to_document_node_default_inputs([None], Default::default()), true);
|
||||
network.push_node(output.to_document_node_default_inputs([None], Default::default()), true);
|
||||
network.push_node(text_generator.to_document_node(
|
||||
[
|
||||
NodeInput::Network(concrete!(WasmEditorApi)),
|
||||
NodeInput::value(TaggedValue::String(text), false),
|
||||
NodeInput::value(TaggedValue::Font(font), false),
|
||||
NodeInput::value(TaggedValue::F64(size), false),
|
||||
],
|
||||
DocumentNodeMetadata::position((0, 4)),
|
||||
));
|
||||
network.push_node(transform.to_document_node_default_inputs([None], Default::default()));
|
||||
network.push_node(fill.to_document_node_default_inputs([None], Default::default()));
|
||||
network.push_node(stroke.to_document_node_default_inputs([None], Default::default()));
|
||||
network.push_node(output.to_document_node_default_inputs([None], Default::default()));
|
||||
network
|
||||
}
|
||||
|
||||
+4
-2
@@ -13,7 +13,6 @@ use graph_craft::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingM
|
||||
use graphene_core::raster::{BlendMode, Color, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RelativeAbsolute, SelectiveColorChoice};
|
||||
use graphene_core::text::Font;
|
||||
use graphene_core::vector::style::{FillType, GradientType, LineCap, LineJoin};
|
||||
use graphene_core::{Cow, Type, TypeDescriptor};
|
||||
|
||||
use glam::{DVec2, IVec2};
|
||||
|
||||
@@ -1222,7 +1221,10 @@ pub fn transform_properties(document_node: &DocumentNode, node_id: NodeId, _cont
|
||||
};
|
||||
|
||||
let scale = vec2_widget(document_node, node_id, 3, "Scale", "W", "H", "x", add_blank_assist);
|
||||
vec![translation, rotation, scale]
|
||||
|
||||
let vector_data = start_widgets(document_node, node_id, 0, "Data", FrontendGraphDataType::Vector, false);
|
||||
let vector_data = LayoutGroup::Row { widgets: vector_data };
|
||||
vec![vector_data, translation, rotation, scale]
|
||||
}
|
||||
|
||||
pub fn node_section_font(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
|
||||
|
||||
@@ -13,12 +13,12 @@ use graph_craft::document::value::TaggedValue;
|
||||
use graph_craft::document::{generate_uuid, DocumentNodeImplementation, NodeId, NodeNetwork};
|
||||
use graph_craft::graphene_compiler::Compiler;
|
||||
use graph_craft::imaginate_input::ImaginatePreferences;
|
||||
use graph_craft::{concrete, Type, TypeDescriptor};
|
||||
use graphene_core::application_io::{ApplicationIo, NodeGraphUpdateMessage, NodeGraphUpdateSender};
|
||||
use graph_craft::{concrete, Type};
|
||||
use graphene_core::application_io::{ApplicationIo, NodeGraphUpdateMessage, NodeGraphUpdateSender, RenderConfig};
|
||||
use graphene_core::raster::{Image, ImageFrame};
|
||||
use graphene_core::renderer::{ClickTarget, SvgSegment, SvgSegmentList};
|
||||
use graphene_core::text::FontCache;
|
||||
use graphene_core::transform::Transform;
|
||||
use graphene_core::transform::{Footprint, Transform};
|
||||
use graphene_core::vector::style::ViewMode;
|
||||
|
||||
use graphene_core::{Color, SurfaceFrame, SurfaceId};
|
||||
@@ -26,7 +26,6 @@ use graphene_std::wasm_application_io::{WasmApplicationIo, WasmEditorApi};
|
||||
use interpreted_executor::dynamic_executor::DynamicExecutor;
|
||||
|
||||
use glam::{DAffine2, DVec2};
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
use std::sync::mpsc::{Receiver, Sender};
|
||||
@@ -72,6 +71,7 @@ pub(crate) struct GenerationRequest {
|
||||
graph: NodeNetwork,
|
||||
path: Vec<LayerId>,
|
||||
image_frame: Option<ImageFrame<Color>>,
|
||||
transform: DAffine2,
|
||||
}
|
||||
|
||||
pub(crate) struct GenerationResponse {
|
||||
@@ -140,6 +140,7 @@ impl NodeRuntime {
|
||||
generation_id,
|
||||
graph,
|
||||
image_frame,
|
||||
transform,
|
||||
path,
|
||||
..
|
||||
}) => {
|
||||
@@ -151,7 +152,7 @@ impl NodeRuntime {
|
||||
.map(|node| node.path.clone().unwrap_or_default())
|
||||
.collect();
|
||||
|
||||
let result = self.execute_network(&path, network, image_frame).await;
|
||||
let result = self.execute_network(&path, network, image_frame, transform).await;
|
||||
let mut responses = VecDeque::new();
|
||||
self.update_thumbnails(&path, monitor_nodes, &mut responses);
|
||||
let response = GenerationResponse {
|
||||
@@ -168,7 +169,7 @@ impl NodeRuntime {
|
||||
}
|
||||
}
|
||||
|
||||
async fn execute_network<'a>(&'a mut self, path: &[LayerId], scoped_network: NodeNetwork, image_frame: Option<ImageFrame<Color>>) -> Result<TaggedValue, String> {
|
||||
async fn execute_network<'a>(&'a mut self, path: &[LayerId], scoped_network: NodeNetwork, image_frame: Option<ImageFrame<Color>>, transform: DAffine2) -> Result<TaggedValue, String> {
|
||||
if self.wasm_io.is_none() {
|
||||
self.wasm_io = Some(WasmApplicationIo::new().await);
|
||||
}
|
||||
@@ -179,6 +180,10 @@ impl NodeRuntime {
|
||||
application_io: self.wasm_io.as_ref().unwrap(),
|
||||
node_graph_message_sender: &self.sender,
|
||||
imaginate_preferences: &self.imaginate_preferences,
|
||||
render_config: RenderConfig {
|
||||
viewport: Footprint { transform, ..Default::default() },
|
||||
..Default::default()
|
||||
},
|
||||
};
|
||||
|
||||
// We assume only one output
|
||||
@@ -197,7 +202,8 @@ impl NodeRuntime {
|
||||
let result = match self.executor.input_type() {
|
||||
Some(t) if t == concrete!(WasmEditorApi) => (&self.executor).execute(editor_api).await.map_err(|e| e.to_string()),
|
||||
Some(t) if t == concrete!(()) => (&self.executor).execute(()).await.map_err(|e| e.to_string()),
|
||||
_ => Err("Invalid input type".to_string()),
|
||||
Some(t) => Err(format!("Invalid input type {:?}", t)),
|
||||
_ => Err("No input type".to_string()),
|
||||
}?;
|
||||
|
||||
if let TaggedValue::SurfaceFrame(SurfaceFrame { surface_id, transform: _ }) = result {
|
||||
@@ -231,7 +237,7 @@ impl NodeRuntime {
|
||||
};
|
||||
use graphene_core::renderer::*;
|
||||
let bounds = graphic_element_data.bounding_box(DAffine2::IDENTITY);
|
||||
let render_params = RenderParams::new(ViewMode::Normal, bounds, true);
|
||||
let render_params = RenderParams::new(ViewMode::Normal, ImageRenderMode::BlobUrl, bounds, true);
|
||||
let mut render = SvgRender::new();
|
||||
graphic_element_data.render_svg(&mut render, &render_params);
|
||||
let [min, max] = bounds.unwrap_or_default();
|
||||
@@ -339,13 +345,14 @@ impl Default for NodeGraphExecutor {
|
||||
|
||||
impl NodeGraphExecutor {
|
||||
/// Execute the network by flattening it and creating a borrow stack.
|
||||
fn queue_execution(&self, network: NodeNetwork, image_frame: Option<ImageFrame<Color>>, layer_path: Vec<LayerId>) -> u64 {
|
||||
fn queue_execution(&self, network: NodeNetwork, image_frame: Option<ImageFrame<Color>>, layer_path: Vec<LayerId>, transform: DAffine2) -> u64 {
|
||||
let generation_id = generate_uuid();
|
||||
let request = GenerationRequest {
|
||||
path: layer_path,
|
||||
graph: network,
|
||||
image_frame,
|
||||
generation_id,
|
||||
transform,
|
||||
};
|
||||
self.sender.send(NodeRuntimeMessage::GenerationRequest(request)).expect("Failed to send generation request");
|
||||
|
||||
@@ -452,9 +459,10 @@ impl NodeGraphExecutor {
|
||||
// Construct the input image frame
|
||||
let transform = DAffine2::IDENTITY;
|
||||
let image_frame = ImageFrame { image, transform };
|
||||
let document_transform = document.document_legacy.metadata.document_to_viewport;
|
||||
|
||||
// Execute the node graph
|
||||
let generation_id = self.queue_execution(network, Some(image_frame), layer_path.clone());
|
||||
let generation_id = self.queue_execution(network, Some(image_frame), layer_path.clone(), document_transform);
|
||||
|
||||
self.futures.insert(generation_id, ExecutionContext { layer_path, document_id });
|
||||
|
||||
@@ -533,12 +541,21 @@ impl NodeGraphExecutor {
|
||||
warn!("Rendered graph produced artboard (which is not currently rendered): {artboard:#?}");
|
||||
return Err("Artboard (see console)".to_string());
|
||||
}
|
||||
TaggedValue::RenderOutput(graphene_std::wasm_application_io::RenderOutput::Svg(svg)) => {
|
||||
// Send to frontend
|
||||
log::debug!("svg: {svg}");
|
||||
responses.add(FrontendMessage::UpdateDocumentNodeRender { svg });
|
||||
responses.add(DocumentMessage::RenderScrollbars);
|
||||
//responses.add(FrontendMessage::UpdateDocumentNodeRender { svg });
|
||||
|
||||
//return Err("Graphic group (see console)".to_string());
|
||||
}
|
||||
TaggedValue::GraphicGroup(graphic_group) => {
|
||||
use graphene_core::renderer::{GraphicElementRendered, RenderParams, SvgRender};
|
||||
|
||||
// Setup rendering
|
||||
let mut render = SvgRender::new();
|
||||
let render_params = RenderParams::new(ViewMode::Normal, None, false);
|
||||
let render_params = RenderParams::new(ViewMode::Normal, graphene_core::renderer::ImageRenderMode::BlobUrl, None, false);
|
||||
|
||||
// Render svg
|
||||
graphic_group.render_svg(&mut render, &render_params);
|
||||
|
||||
Reference in New Issue
Block a user