Instance tables refactor part 1: wrap graphical data in the new Instances<T> struct (#2230)

* Port VectorData to Instances<VectorData>

* Port ImageFrame<P> and TextureFrame to Instances<ImageFrame<P>> and Instances<TextureFrame>

* Avoid mutation with the TransformMut trait

* Port GraphicGroup to Instances<GraphicGroup>

* It compiles!

* Organize debugging

* Document upgrading

* Fix Brush node

* Restore TransformMut in lieu of TransformSet trait

* Fix tests

* Final code review
This commit is contained in:
Keavon Chambers
2025-01-28 23:51:12 -08:00
committed by GitHub
parent 408f9bffa1
commit eb0ff20d3c
43 changed files with 1855 additions and 1221 deletions

View File

@@ -13,7 +13,6 @@ use graphene_core::vector::style::ViewMode;
use graphene_core::Color;
use graphene_std::renderer::ClickTarget;
use graphene_std::transform::Footprint;
use graphene_std::vector::VectorData;
use glam::DAffine2;
@@ -181,9 +180,6 @@ pub enum DocumentMessage {
UpdateClipTargets {
clip_targets: HashSet<NodeId>,
},
UpdateVectorModify {
vector_modify: HashMap<NodeId, VectorData>,
},
Undo,
UngroupSelectedLayers,
UngroupLayer {

View File

@@ -27,7 +27,8 @@ use crate::node_graph_executor::NodeGraphExecutor;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeNetwork, OldNodeNetwork};
use graphene_core::raster::{BlendMode, ImageFrame};
use graphene_core::raster::image::ImageFrame;
use graphene_core::raster::BlendMode;
use graphene_core::vector::style::ViewMode;
use graphene_std::renderer::{ClickTarget, Quad};
use graphene_std::vector::path_bool_lib;
@@ -1159,9 +1160,6 @@ impl MessageHandler<DocumentMessage, DocumentMessageData<'_>> for DocumentMessag
DocumentMessage::UpdateClipTargets { clip_targets } => {
self.network_interface.update_clip_targets(clip_targets);
}
DocumentMessage::UpdateVectorModify { vector_modify } => {
self.network_interface.update_vector_modify(vector_modify);
}
DocumentMessage::Undo => {
if self.network_interface.transaction_status() != TransactionStatus::Finished {
return;
@@ -2126,7 +2124,7 @@ impl DocumentMessageHandler {
/// Create a network interface with a single export
fn default_document_network_interface() -> NodeNetworkInterface {
let mut network_interface = NodeNetworkInterface::default();
network_interface.add_export(TaggedValue::ArtboardGroup(graphene_core::ArtboardGroup::EMPTY), -1, "", &[]);
network_interface.add_export(TaggedValue::ArtboardGroup(graphene_core::ArtboardGroup::default()), -1, "", &[]);
network_interface
}

View File

@@ -5,7 +5,8 @@ use crate::messages::prelude::*;
use bezier_rs::Subpath;
use graph_craft::document::NodeId;
use graphene_core::raster::{BlendMode, ImageFrame};
use graphene_core::raster::image::ImageFrame;
use graphene_core::raster::BlendMode;
use graphene_core::text::{Font, TypesettingConfig};
use graphene_core::vector::brush_stroke::BrushStroke;
use graphene_core::vector::style::{Fill, Stroke};

View File

@@ -8,16 +8,17 @@ use bezier_rs::Subpath;
use graph_craft::concrete;
use graph_craft::document::value::TaggedValue;
use graph_craft::document::{NodeId, NodeInput};
use graphene_core::raster::{BlendMode, ImageFrame};
use graphene_core::raster::image::{ImageFrame, ImageFrameTable};
use graphene_core::raster::BlendMode;
use graphene_core::text::{Font, TypesettingConfig};
use graphene_core::vector::brush_stroke::BrushStroke;
use graphene_core::vector::style::{Fill, Stroke};
use graphene_core::vector::{PointId, VectorModificationType};
use graphene_core::{Artboard, Color};
use graphene_std::vector::{VectorData, VectorDataTable};
use graphene_std::GraphicGroupTable;
use glam::{DAffine2, DVec2, IVec2};
use graphene_std::vector::VectorData;
use graphene_std::GraphicGroup;
#[derive(PartialEq, Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
pub enum TransformIn {
@@ -125,8 +126,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, artboard: Artboard) -> LayerNodeIdentifier {
let artboard_node_template = resolve_document_node_type("Artboard").expect("Node").node_template_input_override([
Some(NodeInput::value(TaggedValue::ArtboardGroup(graphene_std::ArtboardGroup::EMPTY), true)),
Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroup::EMPTY), true)),
Some(NodeInput::value(TaggedValue::ArtboardGroup(graphene_std::ArtboardGroup::default()), true)),
Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroupTable::default()), true)),
Some(NodeInput::value(TaggedValue::IVec2(artboard.location), false)),
Some(NodeInput::value(TaggedValue::IVec2(artboard.dimensions), false)),
Some(NodeInput::value(TaggedValue::Color(artboard.background), false)),
@@ -138,7 +139,7 @@ impl<'a> ModifyInputsContext<'a> {
pub fn insert_boolean_data(&mut self, operation: graphene_std::vector::misc::BooleanOperation, layer: LayerNodeIdentifier) {
let boolean = resolve_document_node_type("Boolean Operation").expect("Boolean node does not exist").node_template_input_override([
Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_std::GraphicGroup::EMPTY), true)),
Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_std::GraphicGroupTable::default()), true)),
Some(NodeInput::value(TaggedValue::BooleanOperation(operation), false)),
]);
@@ -148,7 +149,7 @@ impl<'a> ModifyInputsContext<'a> {
}
pub fn insert_vector_data(&mut self, subpaths: Vec<Subpath<PointId>>, layer: LayerNodeIdentifier, include_transform: bool, include_fill: bool, include_stroke: bool) {
let vector_data = VectorData::from_subpaths(subpaths, true);
let vector_data = VectorDataTable::new(VectorData::from_subpaths(subpaths, true));
let shape = resolve_document_node_type("Path")
.expect("Path node does not exist")
@@ -213,9 +214,10 @@ impl<'a> ModifyInputsContext<'a> {
pub fn insert_image_data(&mut self, image_frame: ImageFrame<Color>, layer: LayerNodeIdentifier) {
let transform = resolve_document_node_type("Transform").expect("Transform node does not exist").default_node_template();
let image = resolve_document_node_type("Image")
.expect("Image node does not exist")
.node_template_input_override([Some(NodeInput::value(TaggedValue::None, false)), Some(NodeInput::value(TaggedValue::ImageFrame(image_frame), false))]);
let image = resolve_document_node_type("Image").expect("Image node does not exist").node_template_input_override([
Some(NodeInput::value(TaggedValue::None, false)),
Some(NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::new(image_frame)), false)),
]);
let image_id = NodeId::new();
self.network_interface.insert_node(image_id, image, &[]);
@@ -289,7 +291,7 @@ impl<'a> ModifyInputsContext<'a> {
// TODO: Allow the path node to operate on Graphic Group data by utilizing the reference for each vector data in a group.
if node_definition.identifier == "Path" {
let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]).0.nested_type();
if layer_input_type == concrete!(GraphicGroup) {
if layer_input_type == concrete!(GraphicGroupTable) {
let Some(flatten_vector_elements_definition) = resolve_document_node_type("Flatten Vector Elements") else {
log::error!("Flatten Vector Elements does not exist in ModifyInputsContext::existing_node_id");
return None;

View File

@@ -15,13 +15,13 @@ use graph_craft::document::*;
use graph_craft::imaginate_input::ImaginateSamplingMethod;
use graph_craft::ProtoNodeIdentifier;
use graphene_core::raster::brush_cache::BrushCache;
use graphene_core::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, ImageFrame, NoiseType, RedGreenBlue, RedGreenBlueAlpha};
use graphene_core::raster::image::ImageFrameTable;
use graphene_core::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlue, RedGreenBlueAlpha};
use graphene_core::text::{Font, TypesettingConfig};
use graphene_core::transform::Footprint;
use graphene_core::vector::VectorData;
use graphene_core::vector::VectorDataTable;
use graphene_core::*;
use graphene_std::wasm_application_io::WasmEditorApi;
#[cfg(feature = "gpu")]
use wgpu_executor::{Bindgroup, CommandBuffer, PipelineLayout, ShaderHandle, ShaderInputFrame, WgpuShaderInput};
@@ -40,9 +40,7 @@ pub struct NodePropertiesContext<'a> {
impl NodePropertiesContext<'_> {
pub fn call_widget_override(&mut self, node_id: &NodeId, index: usize) -> Option<Vec<LayoutGroup>> {
let Some(input_properties_row) = self.network_interface.input_properties_row(node_id, index, self.selection_network_path) else {
return None;
};
let input_properties_row = self.network_interface.input_properties_row(node_id, index, self.selection_network_path)?;
if let Some(widget_override) = &input_properties_row.widget_override {
let Some(widget_override_lambda) = INPUT_OVERRIDES.get(widget_override) else {
log::error!("Could not get widget override lambda in call_widget_override");
@@ -204,8 +202,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroup::EMPTY), true),
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroup::EMPTY), true),
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true),
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true),
],
..Default::default()
},
@@ -312,8 +310,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::ArtboardGroup(ArtboardGroup::EMPTY), true),
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroup::EMPTY), true),
NodeInput::value(TaggedValue::ArtboardGroup(ArtboardGroup::default()), true),
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true),
NodeInput::value(TaggedValue::IVec2(glam::IVec2::ZERO), false),
NodeInput::value(TaggedValue::IVec2(glam::IVec2::new(1920, 1080)), false),
NodeInput::value(TaggedValue::Color(Color::WHITE), false),
@@ -545,8 +543,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(3), 0)],
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(ImageFrame<Color>), 0)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, ImageFrame>")),
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, ImageFrame>")), // TODO: Possibly change `ImageFrame` to something else
..Default::default()
},
DocumentNode {
@@ -573,7 +571,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true)],
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
@@ -664,7 +662,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::VectorData(VectorData::default()), true),
NodeInput::value(TaggedValue::VectorData(VectorDataTable::default()), true),
NodeInput::value(
TaggedValue::Footprint(Footprint {
transform: DAffine2::from_scale_angle_translation(DVec2::new(100., 100.), 0., DVec2::new(0., 0.)),
@@ -811,8 +809,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_std::raster::MaskImageNode"),
inputs: vec![
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
],
..Default::default()
},
@@ -834,8 +832,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_std::raster::InsertChannelNode"),
inputs: vec![
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::default()), false),
],
..Default::default()
@@ -858,10 +856,10 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
implementation: DocumentNodeImplementation::proto("graphene_std::raster::CombineChannelsNode"),
inputs: vec![
NodeInput::value(TaggedValue::None, false),
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
],
..Default::default()
},
@@ -889,7 +887,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
nodes: [
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(ImageFrame<Color>), 0),
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false),
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
@@ -898,7 +896,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(ImageFrame<Color>), 0),
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Green), false),
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
@@ -907,7 +905,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(ImageFrame<Color>), 0),
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Blue), false),
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
@@ -916,7 +914,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(ImageFrame<Color>), 0),
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Alpha), false),
],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")),
@@ -931,7 +929,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true)],
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
@@ -997,8 +995,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(0), 0)],
nodes: vec![DocumentNode {
inputs: vec![
NodeInput::network(concrete!(graphene_core::raster::ImageFrame<Color>), 0),
NodeInput::network(concrete!(graphene_core::raster::ImageFrame<Color>), 1),
NodeInput::network(concrete!(ImageFrameTable<Color>), 0),
NodeInput::network(concrete!(ImageFrameTable<Color>), 1),
NodeInput::network(concrete!(Vec<graphene_core::vector::brush_stroke::BrushStroke>), 2),
NodeInput::network(concrete!(BrushCache), 3),
],
@@ -1013,8 +1011,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::BrushStrokes(Vec::new()), false),
NodeInput::value(TaggedValue::BrushCache(BrushCache::new_proto()), false),
],
@@ -1063,7 +1061,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
node_template: NodeTemplate {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MemoNode"),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true)],
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
manual_composition: Some(concrete!(())),
..Default::default()
},
@@ -1082,7 +1080,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
node_template: NodeTemplate {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_core::memo::ImpureMemoNode"),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true)],
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
manual_composition: Some(concrete!(Footprint)),
..Default::default()
},
@@ -1103,7 +1101,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
implementation: DocumentNodeImplementation::Network(NodeNetwork {
exports: vec![NodeInput::node(NodeId(0), 0)],
nodes: vec![DocumentNode {
inputs: vec![NodeInput::network(concrete!(ImageFrame<Color>), 1)],
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 1)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::transform::CullNode")),
manual_composition: Some(concrete!(Footprint)),
..Default::default()
@@ -1114,7 +1112,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::None, false), NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), false)],
inputs: vec![NodeInput::value(TaggedValue::None, false), NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), false)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
@@ -1809,7 +1807,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
},
DocumentNode {
inputs: vec![NodeInput::network(concrete!(ImageFrame<Color>), 0), NodeInput::node(NodeId(0), 0)],
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0), NodeInput::node(NodeId(0), 0)],
manual_composition: Some(generic!(T)),
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::UploadTextureNode")),
..Default::default()
@@ -1827,7 +1825,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
.collect(),
..Default::default()
}),
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true)],
inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
@@ -1883,7 +1881,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_std::executor::MapGpuSingleImageNode"),
inputs: vec![
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::DocumentNode(DocumentNode::default()), true),
],
..Default::default()
@@ -1925,7 +1923,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_core::raster::BrightnessContrastNode"),
inputs: vec![
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::Bool(false), false),
@@ -1956,7 +1954,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_core::raster::CurvesNode"),
inputs: vec![
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::value(TaggedValue::Curve(Default::default()), false),
],
..Default::default()
@@ -2046,7 +2044,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(1), 0)],
nodes: vec![
DocumentNode {
inputs: vec![NodeInput::network(concrete!(VectorData), 0)],
inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0)],
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
manual_composition: Some(generic!(T)),
skip_deduplication: true,
@@ -2066,7 +2064,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::VectorData(VectorData::empty()), true),
NodeInput::value(TaggedValue::VectorData(VectorDataTable::default()), true),
NodeInput::value(TaggedValue::VectorModification(Default::default()), false),
],
..Default::default()
@@ -2189,7 +2187,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
node_template: NodeTemplate {
document_node: DocumentNode {
inputs: vec![
NodeInput::value(TaggedValue::VectorData(VectorData::empty()), true),
NodeInput::value(TaggedValue::VectorData(VectorDataTable::default()), true),
NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false),
NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::DVec2(DVec2::ONE), false),
@@ -2200,7 +2198,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(1), 0)],
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(VectorData), 0)],
inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0)],
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
manual_composition: Some(generic!(T)),
skip_deduplication: true,
@@ -2296,7 +2294,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(1), 0)],
nodes: vec![
DocumentNode {
inputs: vec![NodeInput::network(concrete!(VectorData), 0), NodeInput::network(concrete!(vector::style::Fill), 1)],
inputs: vec![NodeInput::network(concrete!(VectorDataTable), 0), NodeInput::network(concrete!(vector::style::Fill), 1)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_std::vector::BooleanOperationNode")),
manual_composition: Some(generic!(T)),
..Default::default()
@@ -2315,7 +2313,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroup::EMPTY), true),
NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true),
NodeInput::value(TaggedValue::BooleanOperation(vector::misc::BooleanOperation::Union), false),
],
..Default::default()
@@ -2366,8 +2364,8 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
// TODO: Wrap this implementation with a document node that has a cache node so the output is cached?
implementation: DocumentNodeImplementation::proto("graphene_core::vector::CopyToPointsNode"),
inputs: vec![
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorDataTable::default()), true),
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorDataTable::default()), true),
NodeInput::value(TaggedValue::F64(1.), false),
NodeInput::value(TaggedValue::F64(1.), false),
NodeInput::value(TaggedValue::F64(0.), false),
@@ -2463,14 +2461,14 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
exports: vec![NodeInput::node(NodeId(2), 0)], // Taken from output 0 of Sample Points
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(graphene_core::vector::VectorData), 0)],
inputs: vec![NodeInput::network(concrete!(graphene_core::vector::VectorDataTable), 0)],
implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::vector::SubpathSegmentLengthsNode")),
manual_composition: Some(generic!(T)),
..Default::default()
},
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(graphene_core::vector::VectorData), 0),
NodeInput::network(concrete!(graphene_core::vector::VectorDataTable), 0),
NodeInput::network(concrete!(f64), 1), // From the document node's parameters
NodeInput::network(concrete!(f64), 2), // From the document node's parameters
NodeInput::network(concrete!(f64), 3), // From the document node's parameters
@@ -2495,7 +2493,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorDataTable::default()), true),
NodeInput::value(TaggedValue::F64(100.), false),
NodeInput::value(TaggedValue::F64(0.), false),
NodeInput::value(TaggedValue::F64(0.), false),
@@ -2586,7 +2584,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
nodes: [
DocumentNode {
inputs: vec![
NodeInput::network(concrete!(graphene_core::vector::VectorData), 0),
NodeInput::network(concrete!(graphene_core::vector::VectorDataTable), 0),
NodeInput::network(concrete!(f64), 1),
NodeInput::network(concrete!(u32), 2),
],
@@ -2608,7 +2606,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true),
NodeInput::value(TaggedValue::VectorData(graphene_core::vector::VectorDataTable::default()), true),
NodeInput::value(TaggedValue::F64(10.), false),
NodeInput::value(TaggedValue::U32(0), false),
],
@@ -2667,29 +2665,6 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
},
},
description: Cow::Borrowed("TODO"),
properties: None,
},
// TODO: This needs to work with resolution-aware (raster with footprint, post-Cull node) data.
DocumentNodeDefinition {
identifier: "Index",
category: "Debug",
node_template: NodeTemplate {
document_node: DocumentNode {
implementation: DocumentNodeImplementation::proto("graphene_core::raster::IndexNode"),
inputs: vec![NodeInput::value(TaggedValue::Segments(vec![ImageFrame::empty()]), true), NodeInput::value(TaggedValue::U32(0), false)],
..Default::default()
},
persistent_node_metadata: DocumentNodePersistentMetadata {
input_properties: vec![
"Segmentation".into(),
PropertiesRow::with_override("Index", WidgetOverride::Number(NumberInputSettings { min: Some(0.), ..Default::default() })),
],
output_names: vec!["Image".to_string()],
..Default::default()
},
},
description: Cow::Borrowed("TODO"),
properties: None,
},
@@ -2807,7 +2782,7 @@ pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentN
exports: vec![NodeInput::node(NodeId(1), 0)],
nodes: [
DocumentNode {
inputs: vec![NodeInput::network(concrete!(ImageFrame<Color>), 0)],
inputs: vec![NodeInput::network(concrete!(ImageFrameTable<Color>), 0)],
implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"),
manual_composition: Some(concrete!(())),
skip_deduplication: true,
@@ -2845,7 +2820,7 @@ pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentN
..Default::default()
}),
inputs: vec![
NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), true),
NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::default()), true),
NodeInput::scope("editor-api"),
NodeInput::value(TaggedValue::ImaginateController(Default::default()), false),
NodeInput::value(TaggedValue::F64(0.), false), // Remember to keep index used in `ImaginateRandom` updated with this entry's index

View File

@@ -11,8 +11,9 @@ use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, No
use graph_craft::imaginate_input::{ImaginateMaskStartingFill, ImaginateSamplingMethod};
use graph_craft::Type;
use graphene_core::raster::curve::Curve;
use graphene_core::raster::image::ImageFrameTable;
use graphene_core::raster::{
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, ImageFrame, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute,
SelectiveColorChoice,
};
use graphene_core::text::Font;
@@ -22,8 +23,8 @@ use graphene_std::application_io::TextureFrame;
use graphene_std::transform::Footprint;
use graphene_std::vector::misc::BooleanOperation;
use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops};
use graphene_std::vector::VectorData;
use graphene_std::{GraphicGroup, Raster};
use graphene_std::vector::VectorDataTable;
use graphene_std::{GraphicGroupTable, RasterFrame};
use glam::{DAffine2, DVec2, IVec2, UVec2};
@@ -152,11 +153,11 @@ pub(crate) fn property_from_type(node_id: NodeId, index: usize, ty: &Type, numbe
}
Some(x) if x == TypeId::of::<Curve>() => curves_widget(document_node, node_id, index, name, true),
Some(x) if x == TypeId::of::<GradientStops>() => color_widget(document_node, node_id, index, name, ColorButton::default().allow_none(false), true),
Some(x) if x == TypeId::of::<VectorData>() => vector_widget(document_node, node_id, index, name, true).into(),
Some(x) if x == TypeId::of::<Raster>() || x == TypeId::of::<ImageFrame<Color>>() || x == TypeId::of::<TextureFrame>() => {
Some(x) if x == TypeId::of::<VectorDataTable>() => vector_widget(document_node, node_id, index, name, true).into(),
Some(x) if x == TypeId::of::<RasterFrame>() || x == TypeId::of::<ImageFrameTable<Color>>() || x == TypeId::of::<TextureFrame>() => {
raster_widget(document_node, node_id, index, name, true).into()
}
Some(x) if x == TypeId::of::<GraphicGroup>() => group_widget(document_node, node_id, index, name, true).into(),
Some(x) if x == TypeId::of::<GraphicGroupTable>() => group_widget(document_node, node_id, index, name, true).into(),
Some(x) if x == TypeId::of::<Footprint>() => {
let widgets = footprint_widget(document_node, node_id, index);
let (last, rest) = widgets.split_last().expect("Footprint widget should return multiple rows");

View File

@@ -30,7 +30,7 @@ impl FrontendGraphDataType {
| TaggedValue::F64Array4(_)
| TaggedValue::VecF64(_)
| TaggedValue::VecDVec2(_) => Self::Number,
TaggedValue::GraphicGroup(_) | TaggedValue::GraphicElement(_) => Self::Group,
TaggedValue::GraphicGroup(_) | TaggedValue::GraphicElement(_) => Self::Group, // TODO: Is GraphicElement supposed to be included here?
TaggedValue::ArtboardGroup(_) => Self::Artboard,
_ => Self::General,
}

View File

@@ -3,8 +3,7 @@ use graph_craft::document::NodeId;
use graphene_core::renderer::ClickTarget;
use graphene_core::renderer::Quad;
use graphene_core::transform::Footprint;
use graphene_std::vector::PointId;
use graphene_std::vector::VectorData;
use graphene_std::vector::{PointId, VectorData};
use glam::{DAffine2, DVec2};
use std::collections::{HashMap, HashSet};

View File

@@ -1323,7 +1323,7 @@ impl NodeNetworkInterface {
}
/// Layers excluding ones that are children of other layers in the list.
/// TODO: Cache this
// TODO: Cache this
pub fn shallowest_unique_layers(&self, network_path: &[NodeId]) -> impl Iterator<Item = LayerNodeIdentifier> {
let mut sorted_layers = if let Some(selected_nodes) = self.selected_nodes(network_path) {
selected_nodes
@@ -5977,9 +5977,11 @@ pub struct NodeNetworkPersistentMetadata {
// Stores the transform and navigation state for the network
pub navigation_metadata: NavigationMetadata,
/// Stack of selection snapshots for previous history states.
// TODO: Use `#[serde(skip)]` here instead? @TrueDoctor claims this isn't valid but hasn't satisfactorily explained how it differs from the situation where `#[serde(default)]` fills in the default value. From brief testing, skip seems to work without issue.
#[serde(default)]
pub selection_undo_history: VecDeque<SelectedNodes>,
/// Stack of selection snapshots for future history states.
// TODO: Use `#[serde(skip)]` here instead? See above.
#[serde(default)]
pub selection_redo_history: VecDeque<SelectedNodes>,
}
@@ -6016,7 +6018,7 @@ pub struct NodeNetworkTransientMetadata {
// node_group_bounding_box: Vec<(Subpath<ManipulatorGroupId>, Vec<Nodes>)>,
/// Cache for all outward wire connections
pub outward_wires: TransientMetadata<HashMap<OutputConnector, Vec<InputConnector>>>,
/// TODO: Cache all wire paths instead of calculating in Graph.svelte
// TODO: Cache all wire paths instead of calculating in Graph.svelte
// pub wire_paths: Vec<WirePath>
/// All export connector click targets
pub import_export_ports: TransientMetadata<Ports>,
@@ -6132,7 +6134,7 @@ pub enum WidgetOverride {
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct PropertiesRow {
/// A general datastore than can store key value pairs of any types for any input
/// TODO: This could be simplified to just Value, and key value pairs could be stored as the Object variant
// TODO: This could be simplified to just Value, and key value pairs could be stored as the Object variant
pub input_data: HashMap<String, Value>,
// An input can override a widget, which would otherwise be automatically generated from the type
// The string is the identifier to the widget override function stored in INPUT_OVERRIDES
@@ -6220,13 +6222,36 @@ impl PropertiesRow {
}
}
// TODO: Eventually remove this migration document upgrade code
fn migrate_output_names<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result<Vec<String>, D::Error> {
use serde::Deserialize;
const REPLACEMENTS: [(&str, &str); 3] = [
("VectorData", "Instances<VectorData>"),
("GraphicGroup", "Instances<GraphicGroup>"),
("ImageFrame", "Instances<ImageFrame>"),
];
let mut names = Vec::<String>::deserialize(deserializer)?;
for name in names.iter_mut() {
for (old, new) in REPLACEMENTS.iter() {
if name == old {
*name = new.to_string();
}
}
}
Ok(names)
}
/// Persistent metadata for each node in the network, which must be included when creating, serializing, and deserializing saving a node.
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct DocumentNodePersistentMetadata {
/// The name of the node definition, as originally set by [`DocumentNodeDefinition`], used to display in the UI and to display the appropriate properties if no display name is set.
/// TODO: Used during serialization/deserialization to prevent storing implementation or inputs (and possible other fields) if they are the same as the definition.
/// TODO: The reference is removed once the node is modified, since the node now stores its own implementation and inputs.
/// TODO: Implement node versioning so that references to old nodes can be updated to the new node definition.
// TODO: Used during serialization/deserialization to prevent storing implementation or inputs (and possible other fields) if they are the same as the definition.
// TODO: The reference is removed once the node is modified, since the node now stores its own implementation and inputs.
// TODO: Implement node versioning so that references to old nodes can be updated to the new node definition.
pub reference: Option<String>,
/// A name chosen by the user for this instance of the node. Empty indicates no given name, in which case the reference name is displayed to the user in italics.
#[serde(default)]
@@ -6234,6 +6259,7 @@ pub struct DocumentNodePersistentMetadata {
/// Stores metadata to override the properties in the properties panel for each input. These can either be generated automatically based on the type, or with a custom function.
/// Must match the length of node inputs
pub input_properties: Vec<PropertiesRow>,
#[serde(deserialize_with = "migrate_output_names")]
pub output_names: Vec<String>,
/// Indicates to the UI if a primary output should be drawn for this node.
/// True for most nodes, but the Split Channels node is an example of a node that has multiple secondary outputs but no primary output.

View File

@@ -428,7 +428,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
}
};
const REPLACEMENTS: [(&str, &str); 36] = [
const REPLACEMENTS: [(&str, &str); 35] = [
("graphene_core::AddArtboardNode", "graphene_core::graphic_element::AppendArtboardNode"),
("graphene_core::ConstructArtboardNode", "graphene_core::graphic_element::ToArtboardNode"),
("graphene_core::ToGraphicElementNode", "graphene_core::graphic_element::ToElementNode"),
@@ -445,8 +445,8 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
("graphene_core::raster::ExtractChannelNode", "graphene_core::raster::adjustments::ExtractChannelNode"),
("graphene_core::raster::GradientMapNode", "graphene_core::raster::adjustments::GradientMapNode"),
("graphene_core::raster::HueSaturationNode", "graphene_core::raster::adjustments::HueSaturationNode"),
("graphene_core::raster::IndexNode", "graphene_core::raster::adjustments::IndexNode"),
("graphene_core::raster::InvertNode", "graphene_core::raster::adjustments::InvertNode"),
// ("graphene_core::raster::IndexNode", "graphene_core::raster::adjustments::IndexNode"),
("graphene_core::raster::InvertRGBNode", "graphene_core::raster::adjustments::InvertNode"),
("graphene_core::raster::LevelsNode", "graphene_core::raster::adjustments::LevelsNode"),
("graphene_core::raster::LuminanceNode", "graphene_core::raster::adjustments::LuminanceNode"),

View File

@@ -3,7 +3,8 @@ use crate::messages::portfolio::document::utility_types::network_interface::{Flo
use crate::messages::prelude::*;
use bezier_rs::Subpath;
use graph_craft::document::{value::TaggedValue, NodeId, NodeInput};
use graphene_core::raster::{BlendMode, ImageFrame};
use graphene_core::raster::image::ImageFrame;
use graphene_core::raster::BlendMode;
use graphene_core::text::{Font, TypesettingConfig};
use graphene_core::vector::style::Gradient;
use graphene_core::vector::PointId;
@@ -12,7 +13,7 @@ use graphene_core::Color;
use glam::DVec2;
use std::collections::VecDeque;
/// Create a new vector layer from a vector of [`bezier_rs::Subpath`].
/// Create a new vector layer.
pub fn new_vector_layer(subpaths: Vec<Subpath<PointId>>, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
let insert_index = 0;
responses.add(GraphOperationMessage::NewVectorLayer { id, subpaths, parent, insert_index });
@@ -21,7 +22,7 @@ pub fn new_vector_layer(subpaths: Vec<Subpath<PointId>>, id: NodeId, parent: Lay
LayerNodeIdentifier::new_unchecked(id)
}
/// Create a new bitmap layer from an [`graphene_core::raster::ImageFrame<Color>`]
/// Create a new bitmap layer.
pub fn new_image_layer(image_frame: ImageFrame<Color>, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
let insert_index = 0;
responses.add(GraphOperationMessage::NewBitmapLayer {
@@ -33,7 +34,7 @@ pub fn new_image_layer(image_frame: ImageFrame<Color>, id: NodeId, parent: Layer
LayerNodeIdentifier::new_unchecked(id)
}
/// Create a new group layer from an svg
/// Create a new group layer from an SVG string.
pub fn new_svg_layer(svg: String, transform: glam::DAffine2, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque<Message>) -> LayerNodeIdentifier {
let insert_index = 0;
responses.add(GraphOperationMessage::NewSvg {

View File

@@ -372,7 +372,7 @@ impl Fsm for ArtboardToolFsmState {
responses.add(GraphOperationMessage::NewArtboard {
id,
artboard: graphene_core::Artboard {
graphic_group: graphene_core::GraphicGroup::EMPTY,
graphic_group: graphene_core::GraphicGroupTable::default(),
label: String::from("Artboard"),
location: start.round().as_ivec2(),
dimensions: IVec2::splat(1),

View File

@@ -502,7 +502,7 @@ impl PathToolData {
});
// Make handles colinear if opposite handle is zero length
if opposite_handle_length.map_or(false, |l| l == 0.) {
if opposite_handle_length == Some(0.) {
shape_editor.convert_selected_manipulators_to_colinear_handles(responses, document);
return true;
}