diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index f8f7919347..1894aaa53f 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -2767,7 +2767,7 @@ impl DocumentMessageHandler { } let solidify_stroke_definition = document_node_definitions::resolve_proto_node_type(graphene_std::vector::solidify_stroke::IDENTIFIER).expect("Solidify Stroke node should exist"); - let item_at_index_definition = document_node_definitions::resolve_proto_node_type(graphene_std::graphic::item_at_index::IDENTIFIER).expect("Item at Index node should exist"); + let item_at_index_definition = document_node_definitions::resolve_proto_node_type(graphene_std::graphic::index_elements::IDENTIFIER).expect("Item at Index node should exist"); let mut resulting_layers: Vec = Vec::new(); @@ -2777,13 +2777,14 @@ impl DocumentMessageHandler { continue; } - let appearance = self.network_interface.document_metadata().layer_appearance_attributes.get(&layer); + let metadata = self.network_interface.document_metadata(); + let fill_paint = metadata.layer_fill_attributes.get(&layer); + let stroke_paint = metadata.layer_stroke_attributes.get(&layer); - let has_fill = appearance.is_some_and(|appearance| appearance.has_painted_cover(Cover::Fill)); + let has_fill = fill_paint.is_some_and(|paint| paint.element(0).is_some_and(|graphic| !graphic.is_guaranteed_fully_transparent())); // A visible stroke needs both renderable geometry (non-zero weight) and paint that draws something - let has_stroke = appearance.is_some_and(|appearance| { - appearance.first_coverage_of(Cover::Stroke).is_some_and(|coverage| coverage.stroke_params().has_renderable_stroke()) - && appearance.first_paint_of(Cover::Stroke).is_some_and(|paint| !paint.is_guaranteed_fully_transparent()) + let has_stroke = stroke_paint.is_some_and(|paint| { + graphene_std::renderer::stroke_params(paint).has_renderable_stroke() && paint.element(0).is_some_and(|graphic| !graphic.is_guaranteed_fully_transparent()) }); // No stroke means there's nothing to solidify. Fill-only layers are already in the desired form, so skip. diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index f488adafd6..bd14a58d2d 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -12,7 +12,7 @@ use glam::{DAffine2, DVec2, IVec2}; use graph_craft::application_io::resource::ResourceId; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeInput}; -use graph_craft::{ProtoNodeIdentifier, concrete}; +use graph_craft::{ProtoNodeIdentifier, concrete, descriptor}; use graphene_std::list::List; use graphene_std::raster::BlendMode; use graphene_std::raster_types::Image; @@ -71,8 +71,8 @@ impl<'a> ModifyInputsContext<'a> { /// Creates an artboard as the primary export for the document network. pub fn create_artboard(&mut self, new_id: NodeId, location: DVec2, dimensions: DVec2, background: Color, clip: bool) -> LayerNodeIdentifier { let artboard_node_template = resolve_network_node_type("Artboard").expect("Node").node_template_input_override([ - Some(NodeInput::type_default(concrete!(List), true)), - Some(NodeInput::type_default(concrete!(List), true)), + Some(NodeInput::type_default(descriptor!(List), true)), + Some(NodeInput::type_default(descriptor!(List), true)), Some(NodeInput::value(TaggedValue::DVec2(location), false)), Some(NodeInput::value(TaggedValue::DVec2(dimensions), false)), Some(NodeInput::value(TaggedValue::Color(background), false)), @@ -86,7 +86,7 @@ impl<'a> ModifyInputsContext<'a> { let boolean = resolve_proto_node_type(graphene_std::path_bool_nodes::boolean_operation::IDENTIFIER) .expect("Boolean node does not exist") .node_template_input_override([ - Some(NodeInput::type_default(concrete!(List), true)), + Some(NodeInput::type_default(descriptor!(List), true)), Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)), ]); @@ -98,7 +98,7 @@ impl<'a> ModifyInputsContext<'a> { pub fn insert_blend_data(&mut self, layer: LayerNodeIdentifier, count: f64) -> NodeId { let blend = resolve_network_node_type("Blend") .expect("Blend node does not exist") - .node_template_input_override([Some(NodeInput::type_default(concrete!(List), true)), Some(NodeInput::value(TaggedValue::F64(count), false))]); + .node_template_input_override([Some(NodeInput::type_default(descriptor!(List), true)), Some(NodeInput::value(TaggedValue::F64(count), false))]); let blend_id = NodeId::new(); self.network_interface.insert_node(blend_id, blend, &[]); @@ -110,7 +110,7 @@ impl<'a> ModifyInputsContext<'a> { pub fn insert_morph_data(&mut self, layer: LayerNodeIdentifier) -> NodeId { let morph = resolve_proto_node_type(graphene_std::vector::morph::IDENTIFIER) .expect("Morph node does not exist") - .node_template_input_override([Some(NodeInput::type_default(concrete!(List), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]); + .node_template_input_override([Some(NodeInput::type_default(descriptor!(List), true)), Some(NodeInput::value(TaggedValue::F64(0.5), false))]); let morph_id = NodeId::new(); self.network_interface.insert_node(morph_id, morph, &[]); @@ -859,9 +859,9 @@ impl<'a> ModifyInputsContext<'a> { self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::StrokeJoin(stroke.join), false), true); let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::MiterLimitInput); self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::F64(stroke.join_miter_limit), false), false); - // Our stroke node keeps a paint order input rather than encoding the order by Fill/Stroke node adjacency + // Our stroke node keeps a paint order input rather than encoding the order by Fill/Stroke node adjacency, and master's `Stroke` no longer carries one to copy let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::PaintOrderInput); - self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::PaintOrder(stroke.paint_order), false), false); + self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::PaintOrder(Default::default()), false), false); let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashPatternInput); self.set_input_with_refresh(input_connector, NodeInput::value(TaggedValue::DashPattern(stroke.dash_lengths), false), true); let input_connector = InputConnector::node(stroke_node_id, graphene_std::vector::stroke::DashOffsetInput); diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index c81e06a58f..c5a7251236 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -14,6 +14,7 @@ use graph_craft::ProtoNodeIdentifier; use graph_craft::document::value::*; use graph_craft::document::*; use graph_craft::concrete; +use graph_craft::descriptor; use graphene_std::extract_xy::XY; use graphene_std::list::List; use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha}; @@ -162,7 +163,7 @@ fn document_node_definitions() -> HashMap HashMap), true), NodeInput::type_default(concrete!(List), true)], + inputs: vec![NodeInput::type_default(descriptor!(List), true), NodeInput::type_default(descriptor!(List), true)], input_metadata: vec![("Base", "TODO").into(), ("Content", "TODO").into()], output_names: vec!["Out".to_string()], node_type_metadata: NodeTypePersistentMetadata::layer(IVec2::new(0, 0)), @@ -297,8 +298,8 @@ fn document_node_definitions() -> HashMap), true), - NodeInput::type_default(concrete!(List), true), + NodeInput::type_default(descriptor!(List), true), + NodeInput::type_default(descriptor!(List), true), NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false), NodeInput::value(TaggedValue::DVec2(DVec2::new(1920., 1080.)), false), NodeInput::value(TaggedValue::Color(Color::WHITE), false), @@ -493,11 +494,11 @@ fn document_node_definitions() -> HashMap), true), + NodeInput::type_default(descriptor!(List), true), NodeInput::value(TaggedValue::F64(10.), false), NodeInput::value(TaggedValue::Bool(Default::default()), false), NodeInput::value(TaggedValue::InterpolationDistribution(Default::default()), false), - NodeInput::type_default(concrete!(List), false), + NodeInput::type_default(descriptor!(List), false), ], input_metadata: vec![ ("Content", "TODO").into(), @@ -583,7 +584,7 @@ fn document_node_definitions() -> HashMap), true)], + inputs: vec![NodeInput::type_default(descriptor!(List), true)], input_metadata: vec![("Vector", "TODO").into()], output_names: vec!["Vector".to_string()], node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)), @@ -673,7 +674,7 @@ fn document_node_definitions() -> HashMap), true), + NodeInput::type_default(descriptor!(List), true), NodeInput::value( TaggedValue::Footprint(Footprint { transform: DAffine2::from_scale_angle_translation(DVec2::new(1000., 1000.), 0., DVec2::new(0., 0.)), @@ -750,7 +751,7 @@ fn document_node_definitions() -> HashMap>), true)], + inputs: vec![NodeInput::type_default(descriptor!(List>), true)], input_metadata: vec![("Image", "TODO").into()], output_names: vec!["".to_string(), "Red".to_string(), "Green".to_string(), "Blue".to_string(), "Alpha".to_string()], ..Default::default() @@ -803,7 +804,7 @@ fn document_node_definitions() -> HashMap HashMap Self::Number, TaggedValue::Color(_) => Self::Color, - TaggedValue::LegacyGradient(_) | TaggedValue::Gradient(_) => Self::Gradient, + TaggedValue::LegacyGradient(_) | TaggedValue::GradientRamp(_) => Self::Gradient, TaggedValue::String(_) => Self::Typography, // Types whose `TaggedValue` variant has been removed are routed through `TypeDefault` and identified by the descriptor's type name. TaggedValue::TypeDefault(td) => match td.name.as_ref() { diff --git a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs index 7e74fd96d0..c6e9f8822d 100644 --- a/editor/src/messages/portfolio/document/utility_types/document_metadata.rs +++ b/editor/src/messages/portfolio/document/utility_types/document_metadata.rs @@ -236,11 +236,8 @@ impl DocumentMetadata { /// bounds for non-vector layers (groups, raster, text, color, gradient). pub fn bounding_box_document_with_stroke(&self, layer: LayerNodeIdentifier) -> Option<[DVec2; 2]> { if let Some(vector) = self.layer_vector_data.get(&layer) { - let stroke = self - .layer_appearance_attributes - .get(&layer) - .and_then(|appearance| appearance.first_coverage_of(graphene_std::Cover::Stroke)) - .map(graphene_std::Coverage::stroke_params); + // The stroke geometry rides the stroke paint list's own attribute columns, the carrier that replaced the deleted `Vector::stroke`. + let stroke = self.layer_stroke_attributes.get(&layer).map(|paint| graphene_std::renderer::stroke_params(paint)); if let Some(bounds) = vector.stroke_inclusive_bounding_box_with_transform(self.transform_to_document(layer), stroke.as_ref()) { return Some(bounds); } diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs b/editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs index 0f3e90f31d..b38ed33f70 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface/resolved_types.rs @@ -194,7 +194,7 @@ impl NodeNetworkInterface { log::error!("Proto node {node:?} not found in the node registry, in layer_chain_hosts_node"); return false; }; - implementations.keys().any(|node_io| node_io.inputs.first().is_some_and(|content| content.nested_type() == element)) + implementations.iter().map(|entry| &entry.io).any(|node_io| node_io.inputs.first().is_some_and(|content| content.nested_type() == element)) } None => !matches!(chain_type, TypeSource::Invalid), } diff --git a/editor/src/messages/portfolio/document_migration.rs b/editor/src/messages/portfolio/document_migration.rs index e887c063cb..8e3433e1fc 100644 --- a/editor/src/messages/portfolio/document_migration.rs +++ b/editor/src/messages/portfolio/document_migration.rs @@ -9,7 +9,7 @@ use glam::{DVec2, IVec2}; use graph_craft::application_io::resource::{DataSource, Resource, ResourceHash, ResourceId}; use graph_craft::document::DocumentNode; use graph_craft::document::{DocumentNodeImplementation, NodeInput, value::TaggedValue}; -use graph_craft::{Type, concrete}; +use graph_craft::{Type, concrete, descriptor}; use graphene_std::Color; use graphene_std::ParameterRef; use graphene_std::ProtoNodeIdentifier; @@ -148,7 +148,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[ aliases: &["graphene_core::graphic::FlattenVectorNode", "graphene_core::graphic_element::FlattenVectorNode"], }, NodeReplacement { - node: graphene_std::graphic::item_at_index::IDENTIFIER, + node: graphene_std::graphic::index_elements::IDENTIFIER, aliases: &[ "graphene_core::graphic_element::IndexNode", "graphene_core::graphic::IndexNode", @@ -158,15 +158,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[ ], }, NodeReplacement { - node: graphene_std::graphic::read_attribute_gradient_form::IDENTIFIER, - aliases: &["graphic_nodes::graphic::ReadAttributeGradientTypeNode"], - }, - NodeReplacement { - node: graphene_std::graphic::read_attribute_gradient_spread::IDENTIFIER, - aliases: &["graphic_nodes::graphic::ReadAttributeSpreadMethodNode"], - }, - NodeReplacement { - node: graphene_std::graphic::remove_at_index::IDENTIFIER, + node: graphene_std::graphic::omit_element::IDENTIFIER, aliases: &["graphic_nodes::graphic::OmitElementNode"], }, NodeReplacement { @@ -784,7 +776,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[ aliases: &["graphene_core::vector::ClosePathNode"], }, NodeReplacement { - node: graphene_std::vector::list_length::IDENTIFIER, + node: graphene_std::vector::count_elements::IDENTIFIER, aliases: &["graphene_core::vector::CountElementsNode"], }, NodeReplacement { @@ -1425,10 +1417,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], if reference == DefinitionIdentifier::ProtoNode(graphene_std::vector::copy_to_points::IDENTIFIER) { let mut node_template = node_definition.default_node_template(); let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?; - document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[1].clone(), network_path); - document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 0), old_inputs[1].clone(), network_path); + document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 1), old_inputs[0].clone(), network_path); for (index, input) in old_inputs.into_iter().enumerate().skip(2) { - document.network_interface.set_input(&InputConnector::node(*node_id, index), input, network_path); + document.network_interface.set_input(&InputConnector::node_at_index(*node_id, index), input, network_path); } } @@ -1436,10 +1428,10 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], if reference == DefinitionIdentifier::ProtoNode(graphene_std::repeat::repeat_on_points::IDENTIFIER) { let mut node_template = node_definition.default_node_template(); let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?; - document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[1].clone(), network_path); - document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[0].clone(), network_path); + document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 0), old_inputs[1].clone(), network_path); + document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 1), old_inputs[0].clone(), network_path); for (index, input) in old_inputs.into_iter().enumerate().skip(2) { - document.network_interface.set_input(&InputConnector::node(*node_id, index), input, network_path); + document.network_interface.set_input(&InputConnector::node_at_index(*node_id, index), input, network_path); } } @@ -1898,7 +1890,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], // The stored no-paint sentinel was the `List` type default before the paint connectors ranked down to `Item`. // This must run before the stale-List-default cleanup below, which would otherwise adopt the definition's default paint. { - let legacy_no_paint = TaggedValue::TypeDefault(concrete!(List)); + let legacy_no_paint = TaggedValue::TypeDefault(descriptor!(List)); let paint_parameters: &[ParameterRef] = &[graphene_std::vector::fill::PaintInput.into(), graphene_std::vector::stroke::PaintInput.into()]; for parameter in paint_parameters { if reference != DefinitionIdentifier::ProtoNode(parameter.node_identifier.clone()) { @@ -2490,7 +2482,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], }; // Create List Length node: counts content `List` items → N - let Some(list_length_def) = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::list_length::IDENTIFIER)) else { + let Some(list_length_def) = resolve_document_node_type(&DefinitionIdentifier::ProtoNode(graphene_std::vector::count_elements::IDENTIFIER)) else { log::error!("Could not get list_length node from definition when upgrading morph"); document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 1), old_inputs[1].clone(), network_path); return None; @@ -2717,7 +2709,7 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], document.network_interface.set_input( &InputConnector::node_at_index(*node_id, 0), - NodeInput::type_default(concrete!(graphene_std::vector::Vector), true), + NodeInput::type_default(descriptor!(graphene_std::vector::Vector), true), network_path, ); @@ -2767,7 +2759,8 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId], .input_from_connector(&InputConnector::node_at_index(*node_id, index), network_path) .is_some_and(|stored_input| match stored_input { NodeInput::Value { tagged_value, .. } => match &**tagged_value { - TaggedValue::TypeDefault(stored_type) if matches!(stored_type, Type::Record(_)) && !tagged_value.is_no_paint() => { + // Our type defaults name their type rather than carrying a structural rank, so a list-carrying wire is recognized by its name. + TaggedValue::TypeDefault(stored_type) if stored_type.name.contains("list::List<") && !tagged_value.is_no_paint() => { !matches!(definition_input, NodeInput::Value { tagged_value, .. } if matches!(&**tagged_value, TaggedValue::TypeDefault(definition_type) if definition_type == stored_type)) } _ => false, @@ -2905,11 +2898,15 @@ fn migrate_removed_catalog_definitions(node_id: &NodeId, node: &DocumentNode, ne if let Some(DefinitionIdentifier::Network(name)) = document.network_interface.reference(node_id, network_path) && name == "Upload Texture" { - let mut node_template = resolve_proto_node_type(graphene_std::platform_application_io::upload_texture::IDENTIFIER)?.default_node_template(); - document.network_interface.replace_implementation(node_id, network_path, &mut node_template); - let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?; - if let Some(content) = old_inputs.first() { - document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 0), content.clone(), network_path); + // Our `upload_texture` node belongs to the optional wgpu-executor crate rather than to platform_application_io, so the conversion only exists in a GPU build. + #[cfg(feature = "gpu")] + { + let mut node_template = resolve_proto_node_type(wgpu_executor::texture_conversion::upload_texture::IDENTIFIER)?.default_node_template(); + document.network_interface.replace_implementation(node_id, network_path, &mut node_template); + let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?; + if let Some(content) = old_inputs.first() { + document.network_interface.set_input(&InputConnector::node_at_index(*node_id, 0), content.clone(), network_path); + } } } diff --git a/editor/src/messages/tool/tool_messages/artboard_tool.rs b/editor/src/messages/tool/tool_messages/artboard_tool.rs index 9c79297db6..b74f710411 100644 --- a/editor/src/messages/tool/tool_messages/artboard_tool.rs +++ b/editor/src/messages/tool/tool_messages/artboard_tool.rs @@ -582,7 +582,7 @@ mod test_artboard { Err(e) => panic!("Failed to evaluate graph: {e}"), }; let mut artboards = List::new(); - for list in instrumented.grab_all_input::, List>(&editor.runtime) { + for list in instrumented.grab_all_input::>(&editor.runtime) { for index in 0..list.len() { if let Some(item) = list.clone_item(index) { artboards.push(item); diff --git a/node-graph/libraries/rendering/src/renderer.rs b/node-graph/libraries/rendering/src/renderer.rs index 09b1f56357..fc74e953e9 100644 --- a/node-graph/libraries/rendering/src/renderer.rs +++ b/node-graph/libraries/rendering/src/renderer.rs @@ -388,7 +388,7 @@ const ATTR_PAINT_ORDER: &str = "paint_order"; /// `Vector::stroke` is gone upstream. In our paint model a lane's stroke is the `ATTR_STROKE` /// `List`, so the stroke's GEOMETRY parameters ride that list's own attribute columns, on the /// same names master's `Coverage` uses. Mirrors `vector_nodes::stroke_params`, which writes them. -fn stroke_params(paint: &List) -> StrokeStyle { +pub fn stroke_params(paint: &List) -> StrokeStyle { let defaults = StrokeStyle::default(); StrokeStyle { weight: paint.attribute_cloned_or(ATTR_WEIGHT, 0, defaults.weight), diff --git a/node-graph/node-macro/src/codegen/metadata.rs b/node-graph/node-macro/src/codegen/metadata.rs index 19e54f4b11..b3dbe9b8ff 100644 --- a/node-graph/node-macro/src/codegen/metadata.rs +++ b/node-graph/node-macro/src/codegen/metadata.rs @@ -29,25 +29,21 @@ pub(crate) fn generate_node_input_references( let struct_name = format_ident!("{}Input", input_ident.ident.to_string().to_case(Case::Pascal)); let (fn_generic_params, phantom_data_declerations) = generate_phantom_data(used.iter()); - // Only create structs with phantom data where necessary. - generated_input_accessor.push(if phantom_data_declerations.is_empty() { - quote! { - pub struct #struct_name; - } - } else { - quote! { - pub struct #struct_name <#(#used),*>{ - #(#phantom_data_declerations,)* - } - } - }); + // The marker is always a unit struct so it can be passed as a value; its generics would only have described + // `Result`, which nothing reads through the marker. + let _ = &phantom_data_declerations; generated_input_accessor.push(quote! { - impl <#(#used),*> #core_types::NodeInputDecleration for #struct_name <#(#fn_generic_params),*> { + pub struct #struct_name; + }); + let result_ty = if used.is_empty() { quote!(#ty) } else { quote!(()) }; + let _ = &fn_generic_params; + generated_input_accessor.push(quote! { + impl #core_types::NodeInputDecleration for #struct_name { const INDEX: usize = #input_index; fn identifier() -> #core_types::ProtoNodeIdentifier { #inputs_module_name::IDENTIFIER.clone() } - type Result = #ty; + type Result = #result_ty; } }) } diff --git a/node-graph/nodes/vector/src/vector_nodes.rs b/node-graph/nodes/vector/src/vector_nodes.rs index 1edd94711b..8a886c307a 100644 --- a/node-graph/nodes/vector/src/vector_nodes.rs +++ b/node-graph/nodes/vector/src/vector_nodes.rs @@ -393,10 +393,11 @@ fn fill<'e>( _backup_gradient: IList, _gradient_form: GradientForm, _gradient_spread: GradientSpread, - _transform: Option, + _has_transform: bool, + _transform: DAffine2, ) -> Result<(Vector, Attr<'e, Fill>), Interrupt> { let mut paint = paint_table(paint); - default_gradient_paint(&mut paint, element.bounding_box(), _gradient_form, _gradient_spread, _transform); + default_gradient_paint(&mut paint, element.bounding_box(), _gradient_form, _gradient_spread, _has_transform.then_some(_transform)); let parked = park_paint(ctx.arena(), paint)?; Ok((element, Attr(Some(parked)))) } @@ -413,14 +414,15 @@ fn fill_graphic_leveled<'e>( _backup_gradient: IList, _gradient_form: GradientForm, _gradient_spread: GradientSpread, - _transform: Option, + _has_transform: bool, + _transform: DAffine2, ) -> Result<(Graphic<'static>, Attr<'e, Fill>), Interrupt> { let bounds = match BoundingBox::bounding_box(&element, DAffine2::IDENTITY, false) { RenderBoundingBox::Rectangle(bounds) => Some(bounds), _ => None, }; let mut paint = paint_table(paint); - default_gradient_paint(&mut paint, bounds, _gradient_form, _gradient_spread, _transform); + default_gradient_paint(&mut paint, bounds, _gradient_form, _gradient_spread, _has_transform.then_some(_transform)); let parked = park_paint(ctx.arena(), paint)?; Ok((element, Attr(Some(parked)))) }