From 6111440afd932bbd4640eda6fe45eec5d759340f Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Tue, 17 Jun 2025 19:39:38 -0700 Subject: [PATCH] Instance tables refactor part 7: Remove RasterDataType and add Raster/Raster --- .../document/document_message_handler.rs | 5 +- .../graph_operation_message.rs | 6 +- .../document/graph_operation/utility_types.rs | 6 +- .../node_graph/document_node_definitions.rs | 22 +- .../document/node_graph/node_properties.rs | 7 +- .../spreadsheet_message_handler.rs | 6 +- .../graph_modification_utils.rs | 8 +- node-graph/gcore/src/application_io.rs | 3 +- node-graph/gcore/src/graphic_element.rs | 143 +++--- .../gcore/src/graphic_element/renderer.rs | 124 ++--- node-graph/gcore/src/lib.rs | 1 + node-graph/gcore/src/ops.rs | 6 +- node-graph/gcore/src/raster.rs | 8 +- node-graph/gcore/src/raster/adjustments.rs | 62 +-- node-graph/gcore/src/raster/brush_cache.rs | 30 +- node-graph/gcore/src/raster/image.rs | 136 ++++-- node-graph/gcore/src/raster_types.rs | 102 ++++ node-graph/gcore/src/transform.rs | 19 +- .../gcore/src/vector/algorithms/instance.rs | 7 +- node-graph/gcore/src/vector/brush_stroke.rs | 1 + node-graph/gcore/src/vector/vector_nodes.rs | 10 +- node-graph/graph-craft/src/document/value.rs | 3 +- node-graph/gstd/src/brush.rs | 38 +- node-graph/gstd/src/dehaze.rs | 9 +- node-graph/gstd/src/filter.rs | 11 +- node-graph/gstd/src/gpu_nodes.rs | 455 ------------------ node-graph/gstd/src/image_color_palette.rs | 11 +- node-graph/gstd/src/lib.rs | 2 - node-graph/gstd/src/raster.rs | 52 +- node-graph/gstd/src/vector.rs | 34 +- node-graph/gstd/src/wasm_application_io.rs | 16 +- .../interpreted-executor/src/node_registry.rs | 23 +- node-graph/node-macro/src/parsing.rs | 10 +- node-graph/wgpu-executor/src/lib.rs | 10 +- 34 files changed, 560 insertions(+), 826 deletions(-) create mode 100644 node-graph/gcore/src/raster_types.rs delete mode 100644 node-graph/gstd/src/gpu_nodes.rs diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 80963323..32844ed6 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -30,8 +30,9 @@ use glam::{DAffine2, DVec2, IVec2}; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork}; use graphene_core::raster::BlendMode; -use graphene_core::raster::image::RasterDataTable; +use graphene_core::raster_types::RasterDataTable; use graphene_core::vector::style::ViewMode; +use graphene_std::raster_types::Raster; use graphene_std::renderer::{ClickTarget, Quad}; use graphene_std::vector::{PointId, path_bool_lib}; use std::time::Duration; @@ -864,7 +865,7 @@ impl MessageHandler> for DocumentMessag responses.add(DocumentMessage::AddTransaction); - let layer = graph_modification_utils::new_image_layer(RasterDataTable::new(image), layer_node_id, self.new_layer_parent(true), responses); + let layer = graph_modification_utils::new_image_layer(RasterDataTable::new(Raster::new_cpu(image)), layer_node_id, self.new_layer_parent(true), responses); if let Some(name) = name { responses.add(NodeGraphMessage::SetDisplayName { diff --git a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs index e95c7e9d..17709104 100644 --- a/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs +++ b/editor/src/messages/portfolio/document/graph_operation/graph_operation_message.rs @@ -5,14 +5,14 @@ use crate::messages::prelude::*; use bezier_rs::Subpath; use glam::{DAffine2, DVec2, IVec2}; use graph_craft::document::NodeId; +use graphene_core::Artboard; use graphene_core::raster::BlendMode; -use graphene_core::raster::image::RasterDataTable; +use graphene_core::raster_types::{CPU, RasterDataTable}; use graphene_core::text::{Font, TypesettingConfig}; use graphene_core::vector::PointId; use graphene_core::vector::VectorModificationType; use graphene_core::vector::brush_stroke::BrushStroke; use graphene_core::vector::style::{Fill, Stroke}; -use graphene_core::{Artboard, Color}; #[impl_message(Message, DocumentMessage, GraphOperation)] #[derive(PartialEq, Clone, Debug, serde::Serialize, serde::Deserialize)] @@ -66,7 +66,7 @@ pub enum GraphOperationMessage { }, NewBitmapLayer { id: NodeId, - image_frame: RasterDataTable, + image_frame: RasterDataTable, parent: LayerNodeIdentifier, insert_index: usize, }, 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 d80faad2..1005b8f5 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -8,13 +8,13 @@ use glam::{DAffine2, DVec2, IVec2}; use graph_craft::concrete; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeInput}; +use graphene_core::Artboard; use graphene_core::raster::BlendMode; -use graphene_core::raster::image::RasterDataTable; +use graphene_core::raster_types::{CPU, RasterDataTable}; 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::GraphicGroupTable; use graphene_std::vector::{VectorData, VectorDataTable}; @@ -209,7 +209,7 @@ impl<'a> ModifyInputsContext<'a> { self.network_interface.move_node_to_chain_start(&stroke_id, layer, &[]); } - pub fn insert_image_data(&mut self, image_frame: RasterDataTable, layer: LayerNodeIdentifier) { + pub fn insert_image_data(&mut self, image_frame: RasterDataTable, 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") 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 6a3714ac..b5bf3d68 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 @@ -15,8 +15,8 @@ use graph_craft::concrete; use graph_craft::document::value::*; use graph_craft::document::*; use graphene_core::raster::brush_cache::BrushCache; -use graphene_core::raster::image::RasterDataTable; use graphene_core::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha}; +use graphene_core::raster_types::{CPU, RasterDataTable}; use graphene_core::text::{Font, TypesettingConfig}; use graphene_core::transform::Footprint; use graphene_core::vector::VectorDataTable; @@ -608,7 +608,7 @@ fn static_nodes() -> Vec { exports: vec![NodeInput::node(NodeId(3), 0)], nodes: [ DocumentNode { - inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0)], + inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0)], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, RasterDataTable>")), ..Default::default() }, @@ -852,7 +852,7 @@ fn static_nodes() -> Vec { nodes: [ DocumentNode { inputs: vec![ - NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Red), false), ], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), @@ -861,7 +861,7 @@ fn static_nodes() -> Vec { }, DocumentNode { inputs: vec![ - NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Green), false), ], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), @@ -870,7 +870,7 @@ fn static_nodes() -> Vec { }, DocumentNode { inputs: vec![ - NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Blue), false), ], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), @@ -879,7 +879,7 @@ fn static_nodes() -> Vec { }, DocumentNode { inputs: vec![ - NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::RedGreenBlueAlpha(RedGreenBlueAlpha::Alpha), false), ], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::raster::adjustments::ExtractChannelNode")), @@ -959,13 +959,13 @@ fn static_nodes() -> Vec { exports: vec![NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(1), 0)], nodes: [ DocumentNode { - inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::X), false)], + inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::X), false)], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::ExtractXyNode")), manual_composition: Some(generic!(T)), ..Default::default() }, DocumentNode { - inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::Y), false)], + inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::value(TaggedValue::XY(XY::Y), false)], implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::ExtractXyNode")), manual_composition: Some(generic!(T)), ..Default::default() @@ -1029,7 +1029,7 @@ fn static_nodes() -> Vec { exports: vec![NodeInput::node(NodeId(0), 0)], nodes: vec![DocumentNode { inputs: vec![ - NodeInput::network(concrete!(RasterDataTable), 0), + NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::network(concrete!(Vec), 1), NodeInput::network(concrete!(BrushCache), 2), ], @@ -1784,7 +1784,7 @@ fn static_nodes() -> Vec { ..Default::default() }, DocumentNode { - inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::node(NodeId(0), 0)], + inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0), NodeInput::node(NodeId(0), 0)], manual_composition: Some(generic!(T)), implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("wgpu_executor::UploadTextureNode")), ..Default::default() @@ -2646,7 +2646,7 @@ fn static_nodes() -> Vec { // exports: vec![NodeInput::node(NodeId(1), 0)], // nodes: [ // DocumentNode { -// inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0)], +// inputs: vec![NodeInput::network(concrete!(RasterDataTable), 0)], // implementation: DocumentNodeImplementation::proto("graphene_core::memo::MonitorNode"), // manual_composition: Some(concrete!(Context)), // skip_deduplication: true, diff --git a/editor/src/messages/portfolio/document/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index 3053af57..36d1b33d 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -12,24 +12,23 @@ use graph_craft::Type; use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput}; use graphene_core::raster::curve::Curve; -use graphene_core::raster::image::RasterDataTable; use graphene_core::raster::{ BlendMode, CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, LuminanceCalculation, NoiseType, RedGreenBlue, RedGreenBlueAlpha, RelativeAbsolute, SelectiveColorChoice, }; +use graphene_core::raster_types::{CPU, GPU, RasterDataTable}; use graphene_core::text::Font; use graphene_core::vector::generator_nodes::grid; use graphene_core::vector::misc::CentroidType; use graphene_core::vector::style::{GradientType, LineCap, LineJoin}; use graphene_std::animation::RealTimeMode; -use graphene_std::application_io::TextureDataTable; use graphene_std::ops::XY; use graphene_std::transform::{Footprint, ReferencePoint}; use graphene_std::vector::VectorDataTable; use graphene_std::vector::misc::ArcType; use graphene_std::vector::misc::{BooleanOperation, GridType}; use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops}; -use graphene_std::{GraphicGroupTable, NodeInputDecleration, RasterDataType}; +use graphene_std::{GraphicGroupTable, NodeInputDecleration}; pub(crate) fn string_properties(text: &str) -> Vec { let widget = TextLabel::new(text).widget_holder(); @@ -190,7 +189,7 @@ pub(crate) fn property_from_type( // GRAPHICAL DATA TYPES // ==================== Some(x) if x == TypeId::of::() => vector_data_widget(default_info).into(), - Some(x) if x == TypeId::of::() || x == TypeId::of::>() || x == TypeId::of::() => raster_widget(default_info).into(), + Some(x) if x == TypeId::of::>() || x == TypeId::of::>() => raster_widget(default_info).into(), Some(x) if x == TypeId::of::() => group_widget(default_info).into(), // ============ // STRUCT TYPES diff --git a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs index c9b4d386..b087ed4f 100644 --- a/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs +++ b/editor/src/messages/portfolio/spreadsheet/spreadsheet_message_handler.rs @@ -156,7 +156,8 @@ impl InstanceLayout for GraphicElement { match self { Self::GraphicGroup(instances) => instances.identifier(), Self::VectorData(instances) => instances.identifier(), - Self::RasterDataType(_) => "RasterDataType".to_string(), + Self::RasterDataCPU(_) => "RasterDataCPU".to_string(), + Self::RasterDataGPU(_) => "RasterDataGPU".to_string(), } } // Don't put a breadcrumb for GraphicElement @@ -167,7 +168,8 @@ impl InstanceLayout for GraphicElement { match self { Self::GraphicGroup(instances) => instances.layout_with_breadcrumb(data), Self::VectorData(instances) => instances.layout_with_breadcrumb(data), - Self::RasterDataType(_) => label("Raster frame not supported"), + Self::RasterDataCPU(_) => label("Raster frame not supported"), + Self::RasterDataGPU(_) => label("Raster frame not supported"), } } } diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index 00b178fb..084c7b6f 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -10,7 +10,7 @@ use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeInput}; use graphene_core::Color; use graphene_core::raster::BlendMode; -use graphene_core::raster::image::RasterDataTable; +use graphene_core::raster_types::{CPU, GPU, RasterDataTable}; use graphene_core::text::{Font, TypesettingConfig}; use graphene_core::vector::style::Gradient; use graphene_std::vector::{ManipulatorPointId, PointId, SegmentId, VectorModificationType}; @@ -207,7 +207,7 @@ pub fn new_vector_layer(subpaths: Vec>, id: NodeId, parent: Lay } /// Create a new bitmap layer. -pub fn new_image_layer(image_frame: RasterDataTable, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque) -> LayerNodeIdentifier { +pub fn new_image_layer(image_frame: RasterDataTable, id: NodeId, parent: LayerNodeIdentifier, responses: &mut VecDeque) -> LayerNodeIdentifier { let insert_index = 0; responses.add(GraphOperationMessage::NewBitmapLayer { id, @@ -425,8 +425,6 @@ impl<'a> NodeGraphLayer<'a> { pub fn is_raster_layer(layer: LayerNodeIdentifier, network_interface: &mut NodeNetworkInterface) -> bool { let layer_input_type = network_interface.input_type(&InputConnector::node(layer.to_node(), 1), &[]).0.nested_type().clone(); - layer_input_type == concrete!(graphene_std::RasterDataType) - || layer_input_type == concrete!(graphene_core::raster::image::RasterDataTable) - || layer_input_type == concrete!(graphene_core::application_io::TextureDataTable) + layer_input_type == concrete!(RasterDataTable) || layer_input_type == concrete!(RasterDataTable) } } diff --git a/node-graph/gcore/src/application_io.rs b/node-graph/gcore/src/application_io.rs index 2a760a47..d4e2067b 100644 --- a/node-graph/gcore/src/application_io.rs +++ b/node-graph/gcore/src/application_io.rs @@ -1,4 +1,3 @@ -use crate::instances::Instances; use crate::text::FontCache; use crate::transform::Footprint; use crate::vector::style::ViewMode; @@ -53,7 +52,7 @@ impl Size for web_sys::HtmlCanvasElement { } } -pub type TextureDataTable = Instances; +// pub type TextureDataTable = Instances; #[derive(Debug, Clone)] pub struct ImageTexture { diff --git a/node-graph/gcore/src/graphic_element.rs b/node-graph/gcore/src/graphic_element.rs index 7097fad1..f4eab563 100644 --- a/node-graph/gcore/src/graphic_element.rs +++ b/node-graph/gcore/src/graphic_element.rs @@ -1,7 +1,7 @@ -use crate::application_io::{ImageTexture, TextureDataTable}; use crate::instances::{Instance, Instances}; use crate::raster::BlendMode; -use crate::raster::image::{Image, RasterDataTable}; +use crate::raster::image::Image; +use crate::raster_types::{CPU, GPU, Raster, RasterDataTable}; use crate::transform::TransformMut; use crate::uuid::NodeId; use crate::vector::{VectorData, VectorDataTable}; @@ -124,22 +124,17 @@ impl From for GraphicGroupTable { } impl From> for GraphicGroupTable { fn from(image: Image) -> Self { - Self::new(GraphicElement::RasterDataType(RasterDataType::RasterData(RasterDataTable::new(image)))) + Self::new(GraphicElement::RasterDataCPU(RasterDataTable::::new(Raster::new_cpu(image)))) } } -impl From> for GraphicGroupTable { - fn from(image_frame: RasterDataTable) -> Self { - Self::new(GraphicElement::RasterDataType(RasterDataType::RasterData(image_frame))) +impl From> for GraphicGroupTable { + fn from(raster_data_table: RasterDataTable) -> Self { + Self::new(GraphicElement::RasterDataCPU(raster_data_table)) } } -impl From for GraphicGroupTable { - fn from(image_texture: ImageTexture) -> Self { - Self::new(GraphicElement::RasterDataType(RasterDataType::TextureData(TextureDataTable::new(image_texture)))) - } -} -impl From for GraphicGroupTable { - fn from(texture_frame: TextureDataTable) -> Self { - Self::new(GraphicElement::RasterDataType(RasterDataType::TextureData(texture_frame))) +impl From> for GraphicGroupTable { + fn from(raster_data_table: RasterDataTable) -> Self { + Self::new(GraphicElement::RasterDataGPU(raster_data_table)) } } @@ -151,7 +146,8 @@ pub enum GraphicElement { GraphicGroup(GraphicGroupTable), /// A vector shape, equivalent to the SVG tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path VectorData(VectorDataTable), - RasterDataType(RasterDataType), + RasterDataCPU(RasterDataTable), + RasterDataGPU(RasterDataTable), } impl Default for GraphicElement { @@ -189,50 +185,85 @@ impl GraphicElement { } } - pub fn as_raster(&self) -> Option<&RasterDataType> { + pub fn as_raster(&self) -> Option<&RasterDataTable> { match self { - GraphicElement::RasterDataType(raster) => Some(raster), + GraphicElement::RasterDataCPU(raster) => Some(raster), _ => None, } } - pub fn as_raster_mut(&mut self) -> Option<&mut RasterDataType> { + pub fn as_raster_mut(&mut self) -> Option<&mut RasterDataTable> { match self { - GraphicElement::RasterDataType(raster) => Some(raster), + GraphicElement::RasterDataCPU(raster) => Some(raster), _ => None, } } } -// TODO: Rename to Raster -#[derive(Clone, Debug, Hash, PartialEq, DynAny)] -pub enum RasterDataType { - /// A CPU-based bitmap image with a finite position and extent, equivalent to the SVG tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image - // TODO: Rename to ImageTable - RasterData(RasterDataTable), - /// A GPU texture with a finite position and extent - // TODO: Rename to ImageTextureTable - TextureData(TextureDataTable), -} +// // TODO: Rename to Raster +// #[derive(Clone, Debug, Hash, PartialEq, DynAny)] +// pub enum RasterDataType { +// /// A CPU-based bitmap image with a finite position and extent, equivalent to the SVG tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image +// // TODO: Rename to ImageTable +// RasterData(RasterDataTable), +// /// A GPU texture with a finite position and extent +// // TODO: Rename to ImageTextureTable +// TextureData(TextureDataTable), +// } -impl<'de> serde::Deserialize<'de> for RasterDataType { +// impl<'de> serde::Deserialize<'de> for RasterDataType { +// fn deserialize(deserializer: D) -> Result +// where +// D: serde::Deserializer<'de>, +// { +// Ok(RasterDataType::RasterData(RasterDataTable::new(Image::deserialize(deserializer)?))) +// } +// } + +// impl serde::Serialize for RasterDataType { +// fn serialize(&self, serializer: S) -> Result +// where +// S: serde::Serializer, +// { +// match self { +// RasterDataType::RasterData(_) => self.serialize(serializer), +// RasterDataType::TextureData(_) => todo!(), +// } +// } +// } + +impl<'de> serde::Deserialize<'de> for Raster { fn deserialize(deserializer: D) -> Result where D: serde::Deserializer<'de>, { - Ok(RasterDataType::RasterData(RasterDataTable::new(Image::deserialize(deserializer)?))) + Ok(Raster::new_cpu(Image::deserialize(deserializer)?)) } } -impl serde::Serialize for RasterDataType { +impl serde::Serialize for Raster { fn serialize(&self, serializer: S) -> Result where S: serde::Serializer, { - match self { - RasterDataType::RasterData(_) => self.serialize(serializer), - RasterDataType::TextureData(_) => todo!(), - } + self.data().serialize(serializer) + } +} +impl<'de> serde::Deserialize<'de> for Raster { + fn deserialize(_deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + unimplemented!() + } +} + +impl serde::Serialize for Raster { + fn serialize(&self, _serializer: S) -> Result + where + S: serde::Serializer, + { + unimplemented!() } } @@ -324,8 +355,8 @@ async fn to_element + 'n>( #[implementations( GraphicGroupTable, VectorDataTable, - RasterDataTable, - TextureDataTable, + RasterDataTable, + RasterDataTable, )] data: Data, ) -> GraphicElement { @@ -338,8 +369,8 @@ async fn to_group + 'n>( #[implementations( GraphicGroupTable, VectorDataTable, - RasterDataTable, - TextureDataTable, + RasterDataTable, + RasterDataTable, )] element: Data, ) -> GraphicGroupTable { @@ -391,8 +422,8 @@ async fn to_artboard + 'n>( #[implementations( Context -> GraphicGroupTable, Context -> VectorDataTable, - Context -> RasterDataTable, - Context -> TextureDataTable, + Context -> RasterDataTable, + Context -> RasterDataTable, )] contents: impl Node, Output = Data>, label: String, @@ -437,24 +468,28 @@ async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroupTable, artb // TODO: Remove this one impl From> for GraphicElement { - fn from(image_frame: Image) -> Self { - GraphicElement::RasterDataType(RasterDataType::RasterData(RasterDataTable::new(image_frame))) + fn from(raster_data: Image) -> Self { + GraphicElement::RasterDataCPU(RasterDataTable::::new(Raster::new_cpu(raster_data))) } } -impl From> for GraphicElement { - fn from(image_frame: RasterDataTable) -> Self { - GraphicElement::RasterDataType(RasterDataType::RasterData(image_frame)) +impl From> for GraphicElement { + fn from(raster_data: RasterDataTable) -> Self { + GraphicElement::RasterDataCPU(raster_data) } } -// TODO: Remove this one -impl From for GraphicElement { - fn from(image_texture: ImageTexture) -> Self { - GraphicElement::RasterDataType(RasterDataType::TextureData(TextureDataTable::new(image_texture))) +impl From> for GraphicElement { + fn from(raster_data: RasterDataTable) -> Self { + GraphicElement::RasterDataGPU(raster_data) } } -impl From for GraphicElement { - fn from(texture_data: TextureDataTable) -> Self { - GraphicElement::RasterDataType(RasterDataType::TextureData(texture_data)) +impl From> for GraphicElement { + fn from(raster_data: Raster) -> Self { + GraphicElement::RasterDataCPU(RasterDataTable::new(raster_data)) + } +} +impl From> for GraphicElement { + fn from(raster_data: Raster) -> Self { + GraphicElement::RasterDataGPU(RasterDataTable::new(raster_data)) } } // TODO: Remove this one diff --git a/node-graph/gcore/src/graphic_element/renderer.rs b/node-graph/gcore/src/graphic_element/renderer.rs index e83616d1..918e0471 100644 --- a/node-graph/gcore/src/graphic_element/renderer.rs +++ b/node-graph/gcore/src/graphic_element/renderer.rs @@ -1,13 +1,13 @@ mod quad; mod rect; -use crate::raster::image::RasterDataTable; use crate::raster::{BlendMode, Image}; +use crate::raster_types::{CPU, GPU, RasterDataTable}; use crate::transform::{Footprint, Transform}; use crate::uuid::{NodeId, generate_uuid}; use crate::vector::style::{Fill, Stroke, ViewMode}; use crate::vector::{PointId, VectorDataTable}; -use crate::{Artboard, ArtboardGroupTable, Color, GraphicElement, GraphicGroupTable, RasterDataType}; +use crate::{Artboard, ArtboardGroupTable, Color, GraphicElement, GraphicGroupTable}; use base64::Engine; use bezier_rs::Subpath; use dyn_any::DynAny; @@ -843,7 +843,7 @@ impl GraphicElementRendered for ArtboardGroupTable { } } -impl GraphicElementRendered for RasterDataTable { +impl GraphicElementRendered for RasterDataTable { fn render_svg(&self, render: &mut SvgRender, _render_params: &RenderParams) { for instance in self.instance_ref_iter() { let transform = *instance.transform * render.transform; @@ -923,12 +923,9 @@ impl GraphicElementRendered for RasterDataTable { } } -impl GraphicElementRendered for RasterDataType { - fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) { - match self { - RasterDataType::RasterData(image) => image.render_svg(render, render_params), - RasterDataType::TextureData(_) => log::warn!("tried to render texture as an svg"), - } +impl GraphicElementRendered for RasterDataTable { + fn render_svg(&self, _render: &mut SvgRender, _render_params: &RenderParams) { + log::warn!("tried to render texture as an svg"); } #[cfg(feature = "vello")] @@ -952,65 +949,34 @@ impl GraphicElementRendered for RasterDataType { } }; - match self { - RasterDataType::RasterData(image) => { - for instance in image.instance_ref_iter() { - let image = &instance.instance; - if image.data.is_empty() { - return; - } + for instance in self.instance_ref_iter() { + let image = vello::peniko::Image::new(vec![].into(), peniko::Format::Rgba8, instance.instance.data().width(), instance.instance.data().height()).with_extend(peniko::Extend::Repeat); - let image = vello::peniko::Image::new(image.to_flat_u8().0.into(), peniko::Format::Rgba8, image.width, image.height).with_extend(peniko::Extend::Repeat); + let id = image.data.id(); + context.resource_overrides.insert(id, instance.instance.data_owned()); - render_stuff(image, *instance.transform, *instance.alpha_blending); - } - } - RasterDataType::TextureData(image_texture) => { - for instance in image_texture.instance_ref_iter() { - let image = - vello::peniko::Image::new(vec![].into(), peniko::Format::Rgba8, instance.instance.texture.width(), instance.instance.texture.height()).with_extend(peniko::Extend::Repeat); - - let id = image.data.id(); - context.resource_overrides.insert(id, instance.instance.texture.clone()); - - render_stuff(image, *instance.transform, *instance.alpha_blending); - } - } + render_stuff(image, *instance.transform, *instance.alpha_blending); } } fn bounding_box(&self, transform: DAffine2, _include_stroke: bool) -> Option<[DVec2; 2]> { - let calculate_transform = |instance_transform| { - let transform: DAffine2 = transform * instance_transform; - (transform.matrix2.determinant() != 0.).then(|| (transform * Quad::from_box([DVec2::ZERO, DVec2::ONE])).bounding_box()) - }; - - match self { - RasterDataType::RasterData(instances) => instances.instance_ref_iter().flat_map(|instance| calculate_transform(*instance.transform)).reduce(Quad::combine_bounds), - RasterDataType::TextureData(instances) => instances.instance_ref_iter().flat_map(|instance| calculate_transform(*instance.transform)).reduce(Quad::combine_bounds), - } + self.instance_ref_iter() + .flat_map(|instance| { + let transform = transform * *instance.transform; + (transform.matrix2.determinant() != 0.).then(|| (transform * Quad::from_box([DVec2::ZERO, DVec2::ONE])).bounding_box()) + }) + .reduce(Quad::combine_bounds) } fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, element_id: Option) { let Some(element_id) = element_id else { return }; - let subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE); + metadata.click_targets.insert(element_id, vec![ClickTarget::new(subpath, 0.)]); metadata.upstream_footprints.insert(element_id, footprint); - - match self { - RasterDataType::RasterData(instances) => { - // TODO: Find a way to handle more than one row of the graphical data table - if let Some(image) = instances.instance_ref_iter().next() { - metadata.local_transforms.insert(element_id, *image.transform); - } - } - RasterDataType::TextureData(instances) => { - // TODO: Find a way to handle more than one row of the graphical data table - if let Some(image_texture) = instances.instance_ref_iter().next() { - metadata.local_transforms.insert(element_id, *image_texture.transform); - } - } + // TODO: Find a way to handle more than one row of the graphical data table + if let Some(image) = self.instance_ref_iter().next() { + metadata.local_transforms.insert(element_id, *image.transform); } } @@ -1024,7 +990,8 @@ impl GraphicElementRendered for GraphicElement { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) { match self { GraphicElement::VectorData(vector_data) => vector_data.render_svg(render, render_params), - GraphicElement::RasterDataType(raster) => raster.render_svg(render, render_params), + GraphicElement::RasterDataCPU(raster) => raster.render_svg(render, render_params), + GraphicElement::RasterDataGPU(_raster) => (), GraphicElement::GraphicGroup(graphic_group) => graphic_group.render_svg(render, render_params), } } @@ -1033,15 +1000,17 @@ impl GraphicElementRendered for GraphicElement { fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext, render_params: &RenderParams) { match self { GraphicElement::VectorData(vector_data) => vector_data.render_to_vello(scene, transform, context, render_params), + GraphicElement::RasterDataCPU(raster) => raster.render_to_vello(scene, transform, context, render_params), + GraphicElement::RasterDataGPU(raster) => raster.render_to_vello(scene, transform, context, render_params), GraphicElement::GraphicGroup(graphic_group) => graphic_group.render_to_vello(scene, transform, context, render_params), - GraphicElement::RasterDataType(raster) => raster.render_to_vello(scene, transform, context, render_params), } } fn bounding_box(&self, transform: DAffine2, include_stroke: bool) -> Option<[DVec2; 2]> { match self { GraphicElement::VectorData(vector_data) => vector_data.bounding_box(transform, include_stroke), - GraphicElement::RasterDataType(raster) => raster.bounding_box(transform, include_stroke), + GraphicElement::RasterDataCPU(raster) => raster.bounding_box(transform, include_stroke), + GraphicElement::RasterDataGPU(raster) => raster.bounding_box(transform, include_stroke), GraphicElement::GraphicGroup(graphic_group) => graphic_group.bounding_box(transform, include_stroke), } } @@ -1059,21 +1028,20 @@ impl GraphicElementRendered for GraphicElement { metadata.local_transforms.insert(element_id, *vector_data.transform); } } - GraphicElement::RasterDataType(raster_frame) => { + GraphicElement::RasterDataCPU(raster_frame) => { metadata.upstream_footprints.insert(element_id, footprint); - match raster_frame { - RasterDataType::RasterData(instances) => { - // TODO: Find a way to handle more than one row of images - if let Some(image) = instances.instance_ref_iter().next() { - metadata.local_transforms.insert(element_id, *image.transform); - } - } - RasterDataType::TextureData(instances) => { - // TODO: Find a way to handle more than one row of image textures - if let Some(image_texture) = instances.instance_ref_iter().next() { - metadata.local_transforms.insert(element_id, *image_texture.transform); - } - } + + // TODO: Find a way to handle more than one row of images + if let Some(image) = raster_frame.instance_ref_iter().next() { + metadata.local_transforms.insert(element_id, *image.transform); + } + } + GraphicElement::RasterDataGPU(raster_frame) => { + metadata.upstream_footprints.insert(element_id, footprint); + + // TODO: Find a way to handle more than one row of images + if let Some(image) = raster_frame.instance_ref_iter().next() { + metadata.local_transforms.insert(element_id, *image.transform); } } } @@ -1081,7 +1049,8 @@ impl GraphicElementRendered for GraphicElement { match self { GraphicElement::VectorData(vector_data) => vector_data.collect_metadata(metadata, footprint, element_id), - GraphicElement::RasterDataType(raster) => raster.collect_metadata(metadata, footprint, element_id), + GraphicElement::RasterDataCPU(raster) => raster.collect_metadata(metadata, footprint, element_id), + GraphicElement::RasterDataGPU(raster) => raster.collect_metadata(metadata, footprint, element_id), GraphicElement::GraphicGroup(graphic_group) => graphic_group.collect_metadata(metadata, footprint, element_id), } } @@ -1089,7 +1058,8 @@ impl GraphicElementRendered for GraphicElement { fn add_upstream_click_targets(&self, click_targets: &mut Vec) { match self { GraphicElement::VectorData(vector_data) => vector_data.add_upstream_click_targets(click_targets), - GraphicElement::RasterDataType(raster) => raster.add_upstream_click_targets(click_targets), + GraphicElement::RasterDataCPU(raster) => raster.add_upstream_click_targets(click_targets), + GraphicElement::RasterDataGPU(raster) => raster.add_upstream_click_targets(click_targets), GraphicElement::GraphicGroup(graphic_group) => graphic_group.add_upstream_click_targets(click_targets), } } @@ -1098,7 +1068,8 @@ impl GraphicElementRendered for GraphicElement { match self { GraphicElement::VectorData(vector_data) => vector_data.contains_artboard(), GraphicElement::GraphicGroup(graphic_group) => graphic_group.contains_artboard(), - GraphicElement::RasterDataType(raster) => raster.contains_artboard(), + GraphicElement::RasterDataCPU(raster) => raster.contains_artboard(), + GraphicElement::RasterDataGPU(raster) => raster.contains_artboard(), } } @@ -1106,7 +1077,8 @@ impl GraphicElementRendered for GraphicElement { match self { GraphicElement::VectorData(vector_data) => vector_data.new_ids_from_hash(reference), GraphicElement::GraphicGroup(graphic_group) => graphic_group.new_ids_from_hash(reference), - GraphicElement::RasterDataType(_) => (), + GraphicElement::RasterDataCPU(_) => (), + GraphicElement::RasterDataGPU(_) => (), } } } diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs index 1aa71eed..4ebd3502 100644 --- a/node-graph/gcore/src/lib.rs +++ b/node-graph/gcore/src/lib.rs @@ -22,6 +22,7 @@ pub mod instances; pub mod logic; pub mod misc; pub mod ops; +pub mod raster_types; pub mod structural; #[cfg(feature = "std")] pub mod text; diff --git a/node-graph/gcore/src/ops.rs b/node-graph/gcore/src/ops.rs index 891a693f..76ecead3 100644 --- a/node-graph/gcore/src/ops.rs +++ b/node-graph/gcore/src/ops.rs @@ -1,6 +1,6 @@ use crate::Ctx; use crate::raster::BlendMode; -use crate::raster::image::RasterDataTable; +use crate::raster_types::{CPU, RasterDataTable}; use crate::registry::types::{Fraction, Percentage}; use crate::vector::style::GradientStops; use crate::{Color, Node}; @@ -453,7 +453,7 @@ fn color_value(_: impl Ctx, _primary: (), #[default(Color::BLACK)] color: Option // _: impl Ctx, // #[implementations( // Color, -// RasterDataTable, +// RasterDataTable, // GradientStops, // )] // mut image: T, @@ -515,7 +515,7 @@ fn unwrap(_: impl Ctx, #[implementations(Option, Option, O /// Meant for debugging purposes, not general use. Clones the input value. #[node_macro::node(category("Debug"))] -fn clone<'i, T: Clone + 'i>(_: impl Ctx, #[implementations(&RasterDataTable)] value: &'i T) -> T { +fn clone<'i, T: Clone + 'i>(_: impl Ctx, #[implementations(&RasterDataTable)] value: &'i T) -> T { value.clone() } diff --git a/node-graph/gcore/src/raster.rs b/node-graph/gcore/src/raster.rs index ccaee7eb..a186efc1 100644 --- a/node-graph/gcore/src/raster.rs +++ b/node-graph/gcore/src/raster.rs @@ -1,7 +1,7 @@ pub use self::color::{Color, Luma, SRGBA8}; use crate::Ctx; use crate::GraphicGroupTable; -use crate::raster::image::RasterDataTable; +use crate::raster_types::{CPU, RasterDataTable}; use crate::registry::types::Percentage; use crate::vector::VectorDataTable; use bytemuck::{Pod, Zeroable}; @@ -310,7 +310,7 @@ impl SetBlendMode for GraphicGroupTable { } } } -impl SetBlendMode for RasterDataTable { +impl SetBlendMode for RasterDataTable { fn set_blend_mode(&mut self, blend_mode: BlendMode) { for instance in self.instance_mut_iter() { instance.alpha_blending.blend_mode = blend_mode; @@ -324,7 +324,7 @@ fn blend_mode( #[implementations( GraphicGroupTable, VectorDataTable, - RasterDataTable, + RasterDataTable, )] mut value: T, blend_mode: BlendMode, @@ -340,7 +340,7 @@ fn opacity( #[implementations( GraphicGroupTable, VectorDataTable, - RasterDataTable, + RasterDataTable, )] mut value: T, #[default(100.)] factor: Percentage, diff --git a/node-graph/gcore/src/raster/adjustments.rs b/node-graph/gcore/src/raster/adjustments.rs index 493151c5..e6ce4f7a 100644 --- a/node-graph/gcore/src/raster/adjustments.rs +++ b/node-graph/gcore/src/raster/adjustments.rs @@ -4,8 +4,9 @@ use crate::raster::curve::{CubicSplines, CurveManipulatorGroup}; #[cfg(feature = "alloc")] use crate::raster::curve::{Curve, ValueMapperNode}; #[cfg(feature = "alloc")] -use crate::raster::image::{Image, RasterDataTable}; +use crate::raster::image::Image; use crate::raster::{Channel, Color, Pixel}; +use crate::raster_types::{CPU, Raster, RasterDataTable}; use crate::registry::types::{Angle, Percentage, SignedPercentage}; use crate::vector::VectorDataTable; use crate::vector::style::GradientStops; @@ -265,7 +266,7 @@ fn luminance>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut input: T, @@ -289,7 +290,7 @@ fn extract_channel>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut input: T, @@ -312,7 +313,7 @@ fn make_opaque>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut input: T, @@ -337,7 +338,7 @@ fn brightness_contrast>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut input: T, @@ -426,7 +427,7 @@ fn levels>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut image: T, @@ -493,7 +494,7 @@ async fn black_and_white>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut image: T, @@ -565,7 +566,7 @@ async fn hue_saturation>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut input: T, @@ -599,7 +600,7 @@ async fn invert>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut input: T, @@ -621,7 +622,7 @@ async fn threshold>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut image: T, @@ -663,19 +664,19 @@ impl Blend for Option { } } } -impl Blend for RasterDataTable { +impl Blend for RasterDataTable { fn blend(&self, under: &Self, blend_fn: impl Fn(Color, Color) -> Color) -> Self { let mut result_table = self.clone(); for (over, under) in result_table.instance_mut_iter().zip(under.instance_ref_iter()) { let data = over.instance.data.iter().zip(under.instance.data.iter()).map(|(a, b)| blend_fn(*a, *b)).collect(); - *over.instance = Image { + *over.instance = Raster::new_cpu(Image { data, width: over.instance.width, height: over.instance.height, base64_string: None, - }; + }); } result_table @@ -706,14 +707,14 @@ async fn blend + Send>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] over: T, #[expose] #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] under: T, @@ -795,13 +796,13 @@ impl Adjust for GradientStops { } } } -impl Adjust

for RasterDataTable

+impl Adjust for RasterDataTable where - GraphicElement: From>, + GraphicElement: From>, { - fn adjust(&mut self, map_fn: impl Fn(&P) -> P) { + fn adjust(&mut self, map_fn: impl Fn(&Color) -> Color) { for instance in self.instance_mut_iter() { - for c in instance.instance.data.iter_mut() { + for c in instance.instance.data_mut().data.iter_mut() { *c = map_fn(c); } } @@ -829,7 +830,7 @@ async fn gradient_map>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut image: T, @@ -865,7 +866,7 @@ async fn vibrance>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut image: T, @@ -1037,7 +1038,7 @@ async fn channel_mixer>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut image: T, @@ -1166,7 +1167,7 @@ async fn selective_color>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut image: T, @@ -1309,9 +1310,9 @@ impl MultiplyAlpha for GraphicGroupTable { } } } -impl MultiplyAlpha for RasterDataTable

+impl MultiplyAlpha for RasterDataTable where - GraphicElement: From>, + GraphicElement: From>, { fn multiply_alpha(&mut self, factor: f64) { for instance in self.instance_mut_iter() { @@ -1331,7 +1332,7 @@ async fn posterize>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut input: T, @@ -1364,7 +1365,7 @@ async fn exposure>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut input: T, @@ -1438,7 +1439,7 @@ fn color_overlay>( _: impl Ctx, #[implementations( Color, - RasterDataTable, + RasterDataTable, GradientStops, )] mut image: T, @@ -1488,7 +1489,8 @@ fn color_overlay>( #[cfg(test)] mod test { use crate::raster::adjustments::BlendMode; - use crate::raster::image::{Image, RasterDataTable}; + use crate::raster::image::Image; + use crate::raster_types::{Raster, RasterDataTable}; use crate::{Color, Node}; use std::pin::Pin; @@ -1514,7 +1516,7 @@ mod test { // 100% of the output should come from the multiplied value let opacity = 100_f64; - let result = super::color_overlay((), RasterDataTable::new(image.clone()), overlay_color, BlendMode::Multiply, opacity); + let result = super::color_overlay((), RasterDataTable::new(Raster::new_cpu(image.clone())), overlay_color, BlendMode::Multiply, opacity); let result = result.instance_ref_iter().next().unwrap().instance; // The output should just be the original green and alpha channels (as we multiply them by 1 and other channels by 0) diff --git a/node-graph/gcore/src/raster/brush_cache.rs b/node-graph/gcore/src/raster/brush_cache.rs index bf8132a1..2220d250 100644 --- a/node-graph/gcore/src/raster/brush_cache.rs +++ b/node-graph/gcore/src/raster/brush_cache.rs @@ -1,6 +1,6 @@ -use crate::Color; use crate::instances::Instance; -use crate::raster::Image; +use crate::raster_types::CPU; +use crate::raster_types::Raster; use crate::vector::brush_stroke::BrushStroke; use crate::vector::brush_stroke::BrushStyle; use core::hash::Hash; @@ -17,19 +17,19 @@ struct BrushCacheImpl { // The strokes that have been fully processed and blended into the background. #[cfg_attr(feature = "serde", serde(deserialize_with = "crate::graphene_core::raster::image::migrate_image_frame_instance"))] - background: Instance>, + background: Instance>, #[cfg_attr(feature = "serde", serde(deserialize_with = "crate::graphene_core::raster::image::migrate_image_frame_instance"))] - blended_image: Instance>, + blended_image: Instance>, #[cfg_attr(feature = "serde", serde(deserialize_with = "crate::graphene_core::raster::image::migrate_image_frame_instance"))] - last_stroke_texture: Instance>, + last_stroke_texture: Instance>, // A cache for brush textures. #[cfg_attr(feature = "serde", serde(skip))] - brush_texture_cache: HashMap>, + brush_texture_cache: HashMap>, } impl BrushCacheImpl { - fn compute_brush_plan(&mut self, mut background: Instance>, input: &[BrushStroke]) -> BrushPlan { + fn compute_brush_plan(&mut self, mut background: Instance>, input: &[BrushStroke]) -> BrushPlan { // Do background invalidation. if background != self.background { self.background = background.clone(); @@ -57,7 +57,7 @@ impl BrushCacheImpl { // Check if the first non-blended stroke is an extension of the last one. let mut first_stroke_texture = Instance { - instance: Image::default(), + instance: Raster::::default(), transform: glam::DAffine2::ZERO, ..Default::default() }; @@ -84,7 +84,7 @@ impl BrushCacheImpl { } } - pub fn cache_results(&mut self, input: Vec, blended_image: Instance>, last_stroke_texture: Instance>) { + pub fn cache_results(&mut self, input: Vec, blended_image: Instance>, last_stroke_texture: Instance>) { self.prev_input = input; self.blended_image = blended_image; self.last_stroke_texture = last_stroke_texture; @@ -99,8 +99,8 @@ impl Hash for BrushCacheImpl { #[derive(Clone, Debug, Default)] pub struct BrushPlan { pub strokes: Vec, - pub background: Instance>, - pub first_stroke_texture: Instance>, + pub background: Instance>, + pub first_stroke_texture: Instance>, pub first_stroke_point_skip: usize, } @@ -164,22 +164,22 @@ impl BrushCache { } } - pub fn compute_brush_plan(&self, background: Instance>, input: &[BrushStroke]) -> BrushPlan { + pub fn compute_brush_plan(&self, background: Instance>, input: &[BrushStroke]) -> BrushPlan { let mut inner = self.inner.lock().unwrap(); inner.compute_brush_plan(background, input) } - pub fn cache_results(&self, input: Vec, blended_image: Instance>, last_stroke_texture: Instance>) { + pub fn cache_results(&self, input: Vec, blended_image: Instance>, last_stroke_texture: Instance>) { let mut inner = self.inner.lock().unwrap(); inner.cache_results(input, blended_image, last_stroke_texture) } - pub fn get_cached_brush(&self, style: &BrushStyle) -> Option> { + pub fn get_cached_brush(&self, style: &BrushStyle) -> Option> { let inner = self.inner.lock().unwrap(); inner.brush_texture_cache.get(style).cloned() } - pub fn store_brush(&self, style: BrushStyle, brush: Image) { + pub fn store_brush(&self, style: BrushStyle, brush: Raster) { let mut inner = self.inner.lock().unwrap(); inner.brush_texture_cache.insert(style, brush); } diff --git a/node-graph/gcore/src/raster/image.rs b/node-graph/gcore/src/raster/image.rs index 3de639c2..a1344308 100644 --- a/node-graph/gcore/src/raster/image.rs +++ b/node-graph/gcore/src/raster/image.rs @@ -1,11 +1,14 @@ +use crate::{ + AlphaBlending, + instances::{Instance, Instances}, + raster_types::Raster, +}; + use super::Color; use super::discrete_srgb::float_to_srgb_u8; -use crate::AlphaBlending; -use crate::GraphicElement; -use crate::instances::{Instance, Instances}; use alloc::vec::Vec; use core::hash::{Hash, Hasher}; -use dyn_any::StaticType; +use dyn_any::{DynAny, StaticType}; use glam::{DAffine2, DVec2}; #[cfg(feature = "serde")] @@ -208,9 +211,39 @@ impl IntoIterator for Image

{ } // TODO: Eventually remove this migration document upgrade code -pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result, D::Error> { +pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result, D::Error> { use serde::Deserialize; + type ImageFrameTable

= Instances>; + + #[derive(Clone, Debug, Hash, PartialEq, DynAny)] + enum RasterFrame { + /// A CPU-based bitmap image with a finite position and extent, equivalent to the SVG tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image + ImageFrame(ImageFrameTable), + } + impl<'de> serde::Deserialize<'de> for RasterFrame { + fn deserialize>(deserializer: D) -> Result { + Ok(RasterFrame::ImageFrame(ImageFrameTable::new(Image::deserialize(deserializer)?))) + } + } + impl serde::Serialize for RasterFrame { + fn serialize(&self, serializer: S) -> Result { + match self { + RasterFrame::ImageFrame(image_instances) => image_instances.serialize(serializer), + } + } + } + + #[derive(Clone, Debug, Hash, PartialEq, DynAny)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + pub enum GraphicElement { + /// Equivalent to the SVG tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g + GraphicGroup(GraphicGroupTable), + /// A vector shape, equivalent to the SVG tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path + VectorData(VectorDataTable), + RasterFrame(RasterFrame), + } + #[derive(Clone, Default, Debug, PartialEq, specta::Type)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImageFrame { @@ -218,13 +251,13 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) -> } impl From> for GraphicElement { fn from(image_frame: ImageFrame) -> Self { - GraphicElement::RasterDataType(crate::RasterDataType::RasterData(RasterDataTable::new(image_frame.image))) + GraphicElement::RasterFrame(RasterFrame::ImageFrame(ImageFrameTable::new(image_frame.image))) } } impl From for ImageFrame { fn from(element: GraphicElement) -> Self { match element { - GraphicElement::RasterDataType(crate::RasterDataType::RasterData(image)) => Self { + GraphicElement::RasterFrame(RasterFrame::ImageFrame(image)) => Self { image: image.instance_ref_iter().next().unwrap().instance.clone(), }, _ => panic!("Expected Image, found {:?}", element), @@ -255,27 +288,59 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Image(Image), OldImageFrame(OldImageFrame), ImageFrame(Instances>), - RasterDataTable(RasterDataTable), + ImageFrameTable(ImageFrameTable), + RasterDataTable(RasterDataTable), } Ok(match FormatVersions::deserialize(deserializer)? { - FormatVersions::Image(image) => RasterDataTable::new(image), + FormatVersions::Image(image) => RasterDataTable::new(Raster::new_cpu(image)), FormatVersions::OldImageFrame(image_frame_with_transform_and_blending) => { let OldImageFrame { image, transform, alpha_blending } = image_frame_with_transform_and_blending; - let mut image_frame_table = RasterDataTable::new(image); + let mut image_frame_table = RasterDataTable::new(Raster::new_cpu(image)); *image_frame_table.instance_mut_iter().next().unwrap().transform = transform; *image_frame_table.instance_mut_iter().next().unwrap().alpha_blending = alpha_blending; image_frame_table } - FormatVersions::ImageFrame(image_frame) => RasterDataTable::new(image_frame.instance_ref_iter().next().unwrap().instance.image.clone()), - FormatVersions::RasterDataTable(image_frame_table) => image_frame_table, + FormatVersions::ImageFrame(image_frame) => RasterDataTable::new(Raster::new_cpu(image_frame.instance_ref_iter().next().unwrap().instance.image.clone())), + FormatVersions::ImageFrameTable(image_frame_table) => RasterDataTable::new(Raster::new_cpu(image_frame_table.instance_ref_iter().next().unwrap().instance.clone())), + FormatVersions::RasterDataTable(raster_data_table) => raster_data_table, }) } // TODO: Eventually remove this migration document upgrade code -pub fn migrate_image_frame_instance<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result>, D::Error> { +pub fn migrate_image_frame_instance<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result>, D::Error> { use serde::Deserialize; + type ImageFrameTable

= Instances>; + + #[derive(Clone, Debug, Hash, PartialEq, DynAny)] + enum RasterFrame { + /// A CPU-based bitmap image with a finite position and extent, equivalent to the SVG tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/image + ImageFrame(ImageFrameTable), + } + impl<'de> serde::Deserialize<'de> for RasterFrame { + fn deserialize>(deserializer: D) -> Result { + Ok(RasterFrame::ImageFrame(ImageFrameTable::new(Image::deserialize(deserializer)?))) + } + } + impl serde::Serialize for RasterFrame { + fn serialize(&self, serializer: S) -> Result { + match self { + RasterFrame::ImageFrame(image_instances) => image_instances.serialize(serializer), + } + } + } + + #[derive(Clone, Debug, Hash, PartialEq, DynAny)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + pub enum GraphicElement { + /// Equivalent to the SVG tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/g + GraphicGroup(GraphicGroupTable), + /// A vector shape, equivalent to the SVG tag: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path + VectorData(VectorDataTable), + RasterFrame(RasterFrame), + } + #[derive(Clone, Default, Debug, PartialEq, specta::Type)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ImageFrame { @@ -283,13 +348,13 @@ pub fn migrate_image_frame_instance<'de, D: serde::Deserializer<'de>>(deserializ } impl From> for GraphicElement { fn from(image_frame: ImageFrame) -> Self { - GraphicElement::RasterDataType(crate::RasterDataType::RasterData(RasterDataTable::new(image_frame.image))) + GraphicElement::RasterFrame(RasterFrame::ImageFrame(ImageFrameTable::new(image_frame.image))) } } impl From for ImageFrame { fn from(element: GraphicElement) -> Self { match element { - GraphicElement::RasterDataType(crate::RasterDataType::RasterData(image)) => Self { + GraphicElement::RasterFrame(RasterFrame::ImageFrame(image)) => Self { image: image.instance_ref_iter().next().unwrap().instance.clone(), }, _ => panic!("Expected Image, found {:?}", element), @@ -320,23 +385,23 @@ pub fn migrate_image_frame_instance<'de, D: serde::Deserializer<'de>>(deserializ Image(Image), OldImageFrame(OldImageFrame), ImageFrame(Instances>), - RasterDataTable(RasterDataTable), - ImageInstance(Instance>), + RasterDataTable(RasterDataTable), + ImageInstance(Instance>), } Ok(match FormatVersions::deserialize(deserializer)? { FormatVersions::Image(image) => Instance { - instance: image, + instance: Raster::new_cpu(image), ..Default::default() }, FormatVersions::OldImageFrame(image_frame_with_transform_and_blending) => Instance { - instance: image_frame_with_transform_and_blending.image, + instance: Raster::new_cpu(image_frame_with_transform_and_blending.image), transform: image_frame_with_transform_and_blending.transform, alpha_blending: image_frame_with_transform_and_blending.alpha_blending, source_node_id: None, }, FormatVersions::ImageFrame(image_frame) => Instance { - instance: image_frame.instance_ref_iter().next().unwrap().instance.image.clone(), + instance: Raster::new_cpu(image_frame.instance_ref_iter().next().unwrap().instance.image.clone()), ..Default::default() }, FormatVersions::RasterDataTable(image_frame_table) => image_frame_table.instance_iter().next().unwrap_or_default(), @@ -344,8 +409,7 @@ pub fn migrate_image_frame_instance<'de, D: serde::Deserializer<'de>>(deserializ }) } -// TODO: Rename to ImageTable -pub type RasterDataTable

= Instances>; +// pub type RasterDataTable

= Instances>; impl Sample for Image

{ type Pixel = P; @@ -393,22 +457,22 @@ impl From> for Image { } } -impl From> for RasterDataTable { - fn from(image_frame_table: RasterDataTable) -> Self { - let mut result_table = RasterDataTable::::default(); +// impl From> for RasterDataTable { +// fn from(image_frame_table: RasterDataTable) -> Self { +// let mut result_table = RasterDataTable::::default(); - for image_frame_instance in image_frame_table.instance_iter() { - result_table.push(Instance { - instance: image_frame_instance.instance.into(), - transform: image_frame_instance.transform, - alpha_blending: image_frame_instance.alpha_blending, - source_node_id: image_frame_instance.source_node_id, - }); - } +// for image_frame_instance in image_frame_table.instance_iter() { +// result_table.push(Instance { +// instance: image_frame_instance.instance, +// transform: image_frame_instance.transform, +// alpha_blending: image_frame_instance.alpha_blending, +// source_node_id: image_frame_instance.source_node_id, +// }); +// } - result_table - } -} +// result_table +// } +// } impl From> for Image { fn from(image: Image) -> Self { diff --git a/node-graph/gcore/src/raster_types.rs b/node-graph/gcore/src/raster_types.rs new file mode 100644 index 00000000..45d9ec20 --- /dev/null +++ b/node-graph/gcore/src/raster_types.rs @@ -0,0 +1,102 @@ +use crate::Color; +use crate::instances::Instances; +use crate::raster::Image; +use core::ops::Deref; +use dyn_any::DynAny; +#[cfg(feature = "wgpu")] +use std::sync::Arc; + +#[derive(Clone, Debug, Hash, PartialEq, Eq, Copy)] +pub struct CPU; +#[derive(Clone, Debug, Hash, PartialEq, Eq, Copy)] +pub struct GPU; + +trait Storage {} +impl Storage for CPU {} +impl Storage for GPU {} + +#[derive(Clone, Debug, Hash, PartialEq)] +#[allow(private_bounds)] +pub struct Raster { + data: RasterStorage, + storage: T, +} + +unsafe impl dyn_any::StaticType for Raster { + type Static = Raster; +} +#[derive(Clone, Debug, Hash, PartialEq, DynAny)] +pub enum RasterStorage { + Cpu(Image), + #[cfg(feature = "wgpu")] + Gpu(Arc), + #[cfg(not(feature = "wgpu"))] + Gpu(()), +} + +impl RasterStorage {} +impl Raster { + pub fn new_cpu(image: Image) -> Self { + Self { + data: RasterStorage::Cpu(image), + storage: CPU, + } + } + pub fn data(&self) -> &Image { + let RasterStorage::Cpu(cpu) = &self.data else { unreachable!() }; + cpu + } + pub fn data_mut(&mut self) -> &mut Image { + let RasterStorage::Cpu(cpu) = &mut self.data else { unreachable!() }; + cpu + } + pub fn into_data(self) -> Image { + let RasterStorage::Cpu(cpu) = self.data else { unreachable!() }; + cpu + } +} +impl Default for Raster { + fn default() -> Self { + Self { + data: RasterStorage::Cpu(Image::default()), + storage: CPU, + } + } +} +impl Deref for Raster { + type Target = Image; + + fn deref(&self) -> &Self::Target { + self.data() + } +} +#[cfg(feature = "wgpu")] +impl Raster { + pub fn new_gpu(image: Arc) -> Self { + Self { + data: RasterStorage::Gpu(image), + storage: GPU, + } + } + pub fn data(&self) -> &wgpu::Texture { + let RasterStorage::Gpu(gpu) = &self.data else { unreachable!() }; + gpu + } + pub fn data_mut(&mut self) -> &mut Arc { + let RasterStorage::Gpu(gpu) = &mut self.data else { unreachable!() }; + gpu + } + pub fn data_owned(&self) -> Arc { + let RasterStorage::Gpu(gpu) = &self.data else { unreachable!() }; + gpu.clone() + } +} +#[cfg(feature = "wgpu")] +impl Deref for Raster { + type Target = wgpu::Texture; + + fn deref(&self) -> &Self::Target { + self.data() + } +} +pub type RasterDataTable = Instances>; diff --git a/node-graph/gcore/src/transform.rs b/node-graph/gcore/src/transform.rs index 9932e524..72fcf795 100644 --- a/node-graph/gcore/src/transform.rs +++ b/node-graph/gcore/src/transform.rs @@ -1,9 +1,8 @@ -use crate::application_io::TextureDataTable; use crate::instances::Instances; use crate::raster::bbox::AxisAlignedBbox; -use crate::raster::image::RasterDataTable; +use crate::raster_types::{CPU, GPU, RasterDataTable}; use crate::vector::VectorDataTable; -use crate::{Artboard, CloneVarArgs, Color, Context, Ctx, ExtractAll, GraphicGroupTable, OwnedContextImpl}; +use crate::{Artboard, CloneVarArgs, Context, Ctx, ExtractAll, GraphicGroupTable, OwnedContextImpl}; use core::f64; use glam::{DAffine2, DMat2, DVec2}; @@ -162,8 +161,8 @@ async fn transform( #[implementations( Context -> VectorDataTable, Context -> GraphicGroupTable, - Context -> RasterDataTable, - Context -> TextureDataTable, + Context -> RasterDataTable, + Context -> RasterDataTable, )] transform_target: impl Node, Output = Instances>, translate: DVec2, @@ -194,7 +193,7 @@ async fn transform( #[node_macro::node(category(""))] fn replace_transform( _: impl Ctx, - #[implementations(VectorDataTable, RasterDataTable, GraphicGroupTable)] mut data: Instances, + #[implementations(VectorDataTable, RasterDataTable, GraphicGroupTable)] mut data: Instances, #[implementations(DAffine2)] transform: TransformInput, ) -> Instances { for data_transform in data.instance_mut_iter() { @@ -209,8 +208,8 @@ async fn boundless_footprint( #[implementations( Context -> VectorDataTable, Context -> GraphicGroupTable, - Context -> RasterDataTable, - Context -> TextureDataTable, + Context -> RasterDataTable, + Context -> RasterDataTable, Context -> String, Context -> f64, )] @@ -226,8 +225,8 @@ async fn freeze_real_time( #[implementations( Context -> VectorDataTable, Context -> GraphicGroupTable, - Context -> RasterDataTable, - Context -> TextureDataTable, + Context -> RasterDataTable, + Context -> RasterDataTable, Context -> String, Context -> f64, )] diff --git a/node-graph/gcore/src/vector/algorithms/instance.rs b/node-graph/gcore/src/vector/algorithms/instance.rs index e109c5cf..e6b70f76 100644 --- a/node-graph/gcore/src/vector/algorithms/instance.rs +++ b/node-graph/gcore/src/vector/algorithms/instance.rs @@ -1,6 +1,5 @@ use crate::instances::{InstanceRef, Instances}; -use crate::raster::Color; -use crate::raster::image::RasterDataTable; +use crate::raster_types::{CPU, RasterDataTable}; use crate::transform::TransformMut; use crate::vector::VectorDataTable; use crate::{CloneVarArgs, Context, Ctx, ExtractAll, ExtractIndex, ExtractVarArgs, GraphicElement, GraphicGroupTable, OwnedContextImpl}; @@ -10,7 +9,7 @@ use glam::DVec2; async fn instance_on_points + Default + Clone + 'static>( ctx: impl ExtractAll + CloneVarArgs + Sync + Ctx, points: VectorDataTable, - #[implementations(Context -> GraphicGroupTable, Context -> VectorDataTable, Context -> RasterDataTable)] instance: impl Node<'n, Context<'static>, Output = Instances>, + #[implementations(Context -> GraphicGroupTable, Context -> VectorDataTable, Context -> RasterDataTable)] instance: impl Node<'n, Context<'static>, Output = Instances>, reverse: bool, ) -> GraphicGroupTable { let mut result_table = GraphicGroupTable::default(); @@ -46,7 +45,7 @@ async fn instance_on_points + Default + Clone + 'static> #[node_macro::node(category("Instancing"), path(graphene_core::vector))] async fn instance_repeat + Default + Clone + 'static>( ctx: impl ExtractAll + CloneVarArgs + Ctx, - #[implementations(Context -> GraphicGroupTable, Context -> VectorDataTable, Context -> RasterDataTable)] instance: impl Node<'n, Context<'static>, Output = Instances>, + #[implementations(Context -> GraphicGroupTable, Context -> VectorDataTable, Context -> RasterDataTable)] instance: impl Node<'n, Context<'static>, Output = Instances>, #[default(1)] count: u64, reverse: bool, ) -> GraphicGroupTable { diff --git a/node-graph/gcore/src/vector/brush_stroke.rs b/node-graph/gcore/src/vector/brush_stroke.rs index 1e5b06a9..5360686b 100644 --- a/node-graph/gcore/src/vector/brush_stroke.rs +++ b/node-graph/gcore/src/vector/brush_stroke.rs @@ -37,6 +37,7 @@ impl Hash for BrushStyle { self.hardness.to_bits().hash(state); self.flow.to_bits().hash(state); self.spacing.to_bits().hash(state); + self.blend_mode.hash(state); } } diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index b5150762..24bd5c23 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -4,7 +4,7 @@ use super::misc::{CentroidType, point_to_dvec2}; use super::style::{Fill, Gradient, GradientStops, Stroke}; use super::{PointId, SegmentDomain, SegmentId, StrokeId, VectorData, VectorDataTable}; use crate::instances::{Instance, InstanceMut, Instances}; -use crate::raster::image::RasterDataTable; +use crate::raster_types::{CPU, RasterDataTable}; use crate::registry::types::{Angle, Fraction, IntegerCount, Length, Multiplier, Percentage, PixelLength, PixelSize, SeedValue}; use crate::renderer::GraphicElementRendered; use crate::transform::{Footprint, ReferencePoint, Transform}; @@ -204,7 +204,7 @@ where async fn repeat( _: impl Ctx, // TODO: Implement other GraphicElementRendered types. - #[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable)] instance: Instances, + #[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable)] instance: Instances, #[default(100., 100.)] // TODO: When using a custom Properties panel layout in document_node_definitions.rs and this default is set, the widget weirdly doesn't show up in the Properties panel. Investigation is needed. direction: PixelSize, @@ -246,7 +246,7 @@ where async fn circular_repeat( _: impl Ctx, // TODO: Implement other GraphicElementRendered types. - #[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable)] instance: Instances, + #[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable)] instance: Instances, angle_offset: Angle, #[default(5)] radius: f64, #[default(5)] instances: IntegerCount, @@ -286,7 +286,7 @@ async fn copy_to_points( points: VectorDataTable, #[expose] /// Artwork to be copied and placed at each point. - #[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable)] + #[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable)] instance: Instances, /// Minimum range of randomized sizes given to each instance. #[default(1)] @@ -370,7 +370,7 @@ where #[node_macro::node(category("Vector"), path(graphene_core::vector))] async fn mirror( _: impl Ctx, - #[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable)] instance: Instances, + #[implementations(GraphicGroupTable, VectorDataTable, RasterDataTable)] instance: Instances, #[default(ReferencePoint::Center)] reference_point: ReferencePoint, offset: f64, #[range((-90., 90.))] angle: Angle, diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index b8ed2461..2db12318 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -6,6 +6,7 @@ pub use dyn_any::StaticType; pub use glam::{DAffine2, DVec2, IVec2, UVec2}; use graphene_core::raster::brush_cache::BrushCache; use graphene_core::raster::{BlendMode, LuminanceCalculation}; +use graphene_core::raster_types::CPU; use graphene_core::renderer::RenderMetadata; use graphene_core::transform::ReferencePoint; use graphene_core::uuid::NodeId; @@ -188,7 +189,7 @@ tagged_value! { #[cfg_attr(all(feature = "serde", target_arch = "wasm32"), serde(deserialize_with = "graphene_core::vector::migrate_vector_data"))] // TODO: Eventually remove this migration document upgrade code VectorData(graphene_core::vector::VectorDataTable), #[cfg_attr(all(feature = "serde", target_arch = "wasm32"), serde(alias = "ImageFrame", deserialize_with = "graphene_core::raster::image::migrate_image_frame"))] // TODO: Eventually remove this migration document upgrade code - RasterData(graphene_core::raster::image::RasterDataTable), + RasterData(graphene_core::raster_types::RasterDataTable), #[cfg_attr(all(feature = "serde", target_arch = "wasm32"), serde(deserialize_with = "graphene_core::migrate_graphic_group"))] // TODO: Eventually remove this migration document upgrade code GraphicGroup(graphene_core::GraphicGroupTable), #[cfg_attr(all(feature = "serde", target_arch = "wasm32"), serde(deserialize_with = "graphene_core::migrate_artboard_group"))] // TODO: Eventually remove this migration document upgrade code diff --git a/node-graph/gstd/src/brush.rs b/node-graph/gstd/src/brush.rs index b679f062..14576607 100644 --- a/node-graph/gstd/src/brush.rs +++ b/node-graph/gstd/src/brush.rs @@ -6,8 +6,9 @@ use graphene_core::instances::Instance; use graphene_core::raster::adjustments::blend_colors; use graphene_core::raster::bbox::{AxisAlignedBbox, Bbox}; use graphene_core::raster::brush_cache::BrushCache; -use graphene_core::raster::image::{Image, RasterDataTable}; +use graphene_core::raster::image::Image; use graphene_core::raster::{Alpha, BitmapMut, BlendMode, Color, Pixel, Sample}; +use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use graphene_core::renderer::GraphicElementRendered; use graphene_core::transform::Transform; use graphene_core::value::ClonedNode; @@ -80,11 +81,10 @@ fn brush_stamp_generator(diameter: f64, color: Color, hardness: f64, flow: f64) } #[node_macro::node(skip_impl)] -fn blit(mut target: RasterDataTable

, texture: Image

, positions: Vec, blend_mode: BlendFn) -> RasterDataTable

+fn blit(mut target: RasterDataTable, texture: Raster, positions: Vec, blend_mode: BlendFn) -> RasterDataTable where - P: Pixel + Alpha + std::fmt::Debug, - BlendFn: for<'any_input> Node<'any_input, (P, P), Output = P>, - GraphicElement: From>, + BlendFn: for<'any_input> Node<'any_input, (Color, Color), Output = Color>, + GraphicElement: From>, { if positions.is_empty() { return target; @@ -122,7 +122,7 @@ where for y in blit_area_offset.y..blit_area_offset.y + blit_area_dimensions.y { for x in blit_area_offset.x..blit_area_offset.x + blit_area_dimensions.x { let src_pixel = texture.data[texture_index(x, y)]; - let dst_pixel = &mut target_instance.instance.data[target_index(x + clamp_start.x, y + clamp_start.y)]; + let dst_pixel = &mut target_instance.instance.data_mut().data[target_index(x + clamp_start.x, y + clamp_start.y)]; *dst_pixel = blend_mode.eval((src_pixel, *dst_pixel)); } } @@ -132,7 +132,7 @@ where target } -pub async fn create_brush_texture(brush_style: &BrushStyle) -> Image { +pub async fn create_brush_texture(brush_style: &BrushStyle) -> Raster { let stamp = brush_stamp_generator(brush_style.diameter, brush_style.color, brush_style.hardness, brush_style.flow); let transform = DAffine2::from_scale_angle_translation(DVec2::splat(brush_style.diameter), 0., -DVec2::splat(brush_style.diameter / 2.)); let blank_texture = empty_image((), transform, Color::TRANSPARENT).instance_iter().next().unwrap_or_default(); @@ -141,7 +141,7 @@ pub async fn create_brush_texture(brush_style: &BrushStyle) -> Image { image.instance } -pub fn blend_with_mode(background: Instance>, foreground: Instance>, blend_mode: BlendMode, opacity: f64) -> Instance> { +pub fn blend_with_mode(background: Instance>, foreground: Instance>, blend_mode: BlendMode, opacity: f64) -> Instance> { let opacity = opacity / 100.; match std::hint::black_box(blend_mode) { // Normal group @@ -184,12 +184,12 @@ pub fn blend_with_mode(background: Instance>, foreground: Instance< } #[node_macro::node(category("Raster"))] -async fn brush(_: impl Ctx, mut image_frame_table: RasterDataTable, strokes: Vec, cache: BrushCache) -> RasterDataTable { +async fn brush(_: impl Ctx, mut image_frame_table: RasterDataTable, strokes: Vec, cache: BrushCache) -> RasterDataTable { + if image_frame_table.is_empty() { + image_frame_table.push(Instance::default()); + } // TODO: Find a way to handle more than one instance - let Some(image_frame_instance) = image_frame_table.instance_ref_iter().next() else { - return RasterDataTable::default(); - }; - let image_frame_instance = image_frame_instance.to_instance_cloned(); + let image_frame_instance = image_frame_table.instance_ref_iter().next().expect("Expected the one instance we just pushed").to_instance_cloned(); let [start, end] = image_frame_instance.clone().to_table().bounding_box(DAffine2::IDENTITY, false).unwrap_or([DVec2::ZERO, DVec2::ZERO]); let image_bbox = AxisAlignedBbox { start, end }; @@ -268,7 +268,7 @@ async fn brush(_: impl Ctx, mut image_frame_table: RasterDataTable, strok if has_erase_strokes { let opaque_image = Image::new(bbox.size().x as u32, bbox.size().y as u32, Color::WHITE); let mut erase_restore_mask = Instance { - instance: opaque_image, + instance: Raster::new_cpu(opaque_image), transform: background_bounds, ..Default::default() }; @@ -320,7 +320,7 @@ async fn brush(_: impl Ctx, mut image_frame_table: RasterDataTable, strok image_frame_table } -pub fn blend_image_closure(foreground: Instance>, mut background: Instance>, map_fn: impl Fn(Color, Color) -> Color) -> Instance> { +pub fn blend_image_closure(foreground: Instance>, mut background: Instance>, map_fn: impl Fn(Color, Color) -> Color) -> Instance> { let foreground_size = DVec2::new(foreground.instance.width as f64, foreground.instance.height as f64); let background_size = DVec2::new(background.instance.width as f64, background.instance.height as f64); @@ -340,7 +340,7 @@ pub fn blend_image_closure(foreground: Instance>, mut background: I let foreground_point = background_to_foreground.transform_point2(background_point); let source_pixel = foreground.instance.sample(foreground_point); - let Some(destination_pixel) = background.instance.get_pixel_mut(x, y) else { continue }; + let Some(destination_pixel) = background.instance.data_mut().get_pixel_mut(x, y) else { continue }; *destination_pixel = map_fn(source_pixel, *destination_pixel); } @@ -349,7 +349,7 @@ pub fn blend_image_closure(foreground: Instance>, mut background: I background } -pub fn blend_stamp_closure(foreground: BrushStampGenerator, mut background: Instance>, map_fn: impl Fn(Color, Color) -> Color) -> Instance> { +pub fn blend_stamp_closure(foreground: BrushStampGenerator, mut background: Instance>, map_fn: impl Fn(Color, Color) -> Color) -> Instance> { let background_size = DVec2::new(background.instance.width as f64, background.instance.height as f64); // Transforms a point from the background image to the foreground image @@ -369,7 +369,7 @@ pub fn blend_stamp_closure(foreground: BrushStampGenerator, mut backgroun let foreground_point = background_to_foreground.transform_point2(background_point); let Some(source_pixel) = foreground.sample(foreground_point, area) else { continue }; - let Some(destination_pixel) = background.instance.get_pixel_mut(x, y) else { continue }; + let Some(destination_pixel) = background.instance.data_mut().get_pixel_mut(x, y) else { continue }; *destination_pixel = map_fn(source_pixel, *destination_pixel); } @@ -397,7 +397,7 @@ mod test { async fn test_brush_output_size() { let image = brush( (), - RasterDataTable::::new(Image::::default()), + RasterDataTable::::new(Raster::new_cpu(Image::::default())), vec![BrushStroke { trace: vec![crate::vector::brush_stroke::BrushInputSample { position: DVec2::ZERO }], style: BrushStyle { diff --git a/node-graph/gstd/src/dehaze.rs b/node-graph/gstd/src/dehaze.rs index 5e0de85d..c927b31d 100644 --- a/node-graph/gstd/src/dehaze.rs +++ b/node-graph/gstd/src/dehaze.rs @@ -1,12 +1,13 @@ use graph_craft::proto::types::Percentage; -use graphene_core::raster::image::{Image, RasterDataTable}; -use graphene_core::{Color, Ctx}; +use graphene_core::Ctx; +use graphene_core::raster::image::Image; +use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use image::{DynamicImage, GenericImage, GenericImageView, GrayImage, ImageBuffer, Luma, Rgba, RgbaImage}; use ndarray::{Array2, ArrayBase, Dim, OwnedRepr}; use std::cmp::{max, min}; #[node_macro::node(category("Raster"))] -async fn dehaze(_: impl Ctx, image_frame: RasterDataTable, strength: Percentage) -> RasterDataTable { +async fn dehaze(_: impl Ctx, image_frame: RasterDataTable, strength: Percentage) -> RasterDataTable { let mut result_table = RasterDataTable::default(); for mut image_frame_instance in image_frame.instance_iter() { @@ -29,7 +30,7 @@ async fn dehaze(_: impl Ctx, image_frame: RasterDataTable, strength: Perc base64_string: None, }; - image_frame_instance.instance = dehazed_image; + image_frame_instance.instance = Raster::new_cpu(dehazed_image); image_frame_instance.source_node_id = None; result_table.push(image_frame_instance); } diff --git a/node-graph/gstd/src/filter.rs b/node-graph/gstd/src/filter.rs index 808c6ed5..0ae9becd 100644 --- a/node-graph/gstd/src/filter.rs +++ b/node-graph/gstd/src/filter.rs @@ -1,6 +1,7 @@ use graph_craft::proto::types::PixelLength; -use graphene_core::raster::image::{Image, RasterDataTable}; +use graphene_core::raster::image::Image; use graphene_core::raster::{Bitmap, BitmapMut}; +use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use graphene_core::{Color, Ctx}; /// Blurs the image with a Gaussian or blur kernel filter. @@ -8,7 +9,7 @@ use graphene_core::{Color, Ctx}; async fn blur( _: impl Ctx, /// The image to be blurred. - image_frame: RasterDataTable, + image_frame: RasterDataTable, /// The radius of the blur kernel. #[range((0., 100.))] #[hard_min(0.)] @@ -17,7 +18,7 @@ async fn blur( box_blur: bool, /// Opt to incorrectly apply the filter with color calculations in gamma space for compatibility with the results from other software. gamma: bool, -) -> RasterDataTable { +) -> RasterDataTable { let mut result_table = RasterDataTable::default(); for mut image_instance in image_frame.instance_iter() { @@ -28,9 +29,9 @@ async fn blur( // Minimum blur radius image.clone() } else if box_blur { - box_blur_algorithm(image, radius, gamma) + Raster::new_cpu(box_blur_algorithm(image.into_data(), radius, gamma)) } else { - gaussian_blur_algorithm(image, radius, gamma) + Raster::new_cpu(gaussian_blur_algorithm(image.into_data(), radius, gamma)) }; image_instance.instance = blurred_image; diff --git a/node-graph/gstd/src/gpu_nodes.rs b/node-graph/gstd/src/gpu_nodes.rs deleted file mode 100644 index 01cd6712..00000000 --- a/node-graph/gstd/src/gpu_nodes.rs +++ /dev/null @@ -1,455 +0,0 @@ -use glam::{DAffine2, DVec2, Mat2, Vec2}; -use gpu_executor::{ComputePassDimensions, StorageBufferOptions}; -use graph_craft::document::value::TaggedValue; -use graph_craft::document::*; -use graph_craft::proto::*; -use graphene_core::raster::BlendMode; -use graphene_core::raster::image::{Image, RasterDataTable}; -use graphene_core::*; -use std::sync::Arc; -use wgpu_executor::{Bindgroup, PipelineLayout, Shader, ShaderIO, ShaderInput, WgpuExecutor}; - -// TODO: Move to graph-craft -#[node_macro::node(category("Debug: GPU"))] -async fn compile_gpu<'a: 'n>(_: impl Ctx, node: &'a DocumentNode, typing_context: TypingContext, io: ShaderIO) -> Result { - let mut typing_context = typing_context; - let compiler = graph_craft::graphene_compiler::Compiler {}; - let DocumentNodeImplementation::Network(ref network) = node.implementation else { panic!() }; - let proto_networks: Result, _> = compiler.compile(network.clone()).collect(); - let proto_networks = proto_networks?; - - for network in proto_networks.iter() { - typing_context.update(network).expect("Failed to type check network"); - } - // TODO: do a proper union - let input_types = proto_networks[0] - .inputs - .iter() - .map(|id| typing_context.type_of(*id).unwrap()) - .map(|node_io| node_io.return_value.clone()) - .collect(); - let output_types = proto_networks.iter().map(|network| typing_context.type_of(network.output).unwrap().return_value.clone()).collect(); - - Ok(compilation_client::compile(proto_networks, input_types, output_types, io).await.unwrap()) -} - -#[node_macro::node(category("Debug: GPU"))] -async fn blend_gpu_image(_: impl Ctx, foreground: RasterDataTable, background: RasterDataTable, blend_mode: BlendMode, opacity: f64) -> RasterDataTable { - let mut result_table = RasterDataTable::default(); - - for (foreground_instance, mut background_instance) in foreground.instance_iter().zip(background.instance_iter()) { - let foreground_transform = foreground_instance.transform; - let background_transform = background_instance.transform; - - let foreground = foreground_instance.instance; - let background = background_instance.instance; - - let foreground_size = DVec2::new(foreground.width as f64, foreground.height as f64); - let background_size = DVec2::new(background.width as f64, background.height as f64); - - // Transforms a point from the background image to the foreground image - let bg_to_fg = DAffine2::from_scale(foreground_size) * foreground_transform.inverse() * background_transform * DAffine2::from_scale(1. / background_size); - - let transform_matrix: Mat2 = bg_to_fg.matrix2.as_mat2(); - let translation: Vec2 = bg_to_fg.translation.as_vec2(); - - log::debug!("Executing gpu blend node!"); - let compiler = graph_craft::graphene_compiler::Compiler {}; - - let network = NodeNetwork { - exports: vec![NodeInput::node(NodeId(0), 0)], - nodes: [DocumentNode { - inputs: vec![NodeInput::Inline(InlineRust::new( - format!( - r#"graphene_core::raster::adjustments::BlendNode::new( - graphene_core::value::CopiedNode::new({}), - graphene_core::value::CopiedNode::new({}), - ).eval(( - {{ - let bg_point = Vec2::new(_global_index.x as f32, _global_index.y as f32); - let fg_point = (*i4) * bg_point + (*i5); - - if !((fg_point.cmpge(Vec2::ZERO) & bg_point.cmpge(Vec2::ZERO)) == BVec2::new(true, true)) {{ - Color::from_rgbaf32_unchecked(0., 0., 0., 0.) - }} else {{ - i2[((fg_point.y as u32) * i3 + (fg_point.x as u32)) as usize] - }} - }}, - i1[(_global_index.y * i0 + _global_index.x) as usize], - ))"#, - TaggedValue::BlendMode(blend_mode).to_primitive_string(), - TaggedValue::F64(opacity).to_primitive_string(), - ), - concrete![Color], - ))], - implementation: DocumentNodeImplementation::ProtoNode("graphene_core::value::CopiedNode".into()), - ..Default::default() - }] - .into_iter() - .enumerate() - .map(|(id, node)| (NodeId(id as u64), node)) - .collect(), - ..Default::default() - }; - log::debug!("compiling network"); - let proto_networks: Result, _> = compiler.compile(network.clone()).collect(); - let Ok(proto_networks_result) = proto_networks else { - log::error!("Error compiling network in 'blend_gpu_image()"); - return RasterDataTable::default(); - }; - let proto_networks = proto_networks_result; - log::debug!("compiling shader"); - - let shader = compilation_client::compile( - proto_networks, - vec![ - concrete!(u32), - concrete!(Color), - concrete!(Color), - concrete!(u32), - concrete_with_name!(Mat2, "Mat2"), - concrete_with_name!(Vec2, "Vec2"), - ], - vec![concrete!(Color)], - ShaderIO { - inputs: vec![ - ShaderInput::UniformBuffer((), concrete!(u32)), // width of the output image - ShaderInput::StorageBuffer((), concrete!(Color)), // background image - ShaderInput::StorageBuffer((), concrete!(Color)), // foreground image - ShaderInput::UniformBuffer((), concrete!(u32)), // width of the foreground image - ShaderInput::UniformBuffer((), concrete_with_name!(Mat2, "Mat2")), // bg_to_fg.matrix2 - ShaderInput::UniformBuffer((), concrete_with_name!(Vec2, "Vec2")), // bg_to_fg.translation - ShaderInput::OutputBuffer((), concrete!(Color)), - ], - output: ShaderInput::OutputBuffer((), concrete!(Color)), - }, - ) - .await - .unwrap(); - let len = background.data.len(); - - let executor = WgpuExecutor::new() - .await - .expect("Failed to create wgpu executor. Please make sure that webgpu is enabled for your browser."); - log::debug!("creating buffer"); - let width_uniform = executor.create_uniform_buffer(background.width).unwrap(); - let bg_storage_buffer = executor - .create_storage_buffer( - background.data.clone(), - StorageBufferOptions { - cpu_writable: false, - gpu_writable: true, - cpu_readable: false, - storage: true, - }, - ) - .unwrap(); - let fg_storage_buffer = executor - .create_storage_buffer( - foreground.data.clone(), - StorageBufferOptions { - cpu_writable: false, - gpu_writable: true, - cpu_readable: false, - storage: true, - }, - ) - .unwrap(); - let fg_width_uniform = executor.create_uniform_buffer(foreground.width).unwrap(); - let transform_uniform = executor.create_uniform_buffer(transform_matrix).unwrap(); - let translation_uniform = executor.create_uniform_buffer(translation).unwrap(); - let width_uniform = Arc::new(width_uniform); - let bg_storage_buffer = Arc::new(bg_storage_buffer); - let fg_storage_buffer = Arc::new(fg_storage_buffer); - let fg_width_uniform = Arc::new(fg_width_uniform); - let transform_uniform = Arc::new(transform_uniform); - let translation_uniform = Arc::new(translation_uniform); - let output_buffer = executor.create_output_buffer(len, concrete!(Color), false).unwrap(); - let output_buffer = Arc::new(output_buffer); - let readback_buffer = executor.create_output_buffer(len, concrete!(Color), true).unwrap(); - let readback_buffer = Arc::new(readback_buffer); - log::debug!("created buffer"); - let bind_group = Bindgroup { - buffers: vec![ - width_uniform.clone(), - bg_storage_buffer.clone(), - fg_storage_buffer.clone(), - fg_width_uniform.clone(), - transform_uniform.clone(), - translation_uniform.clone(), - ], - }; - - let shader = Shader { - source: shader.spirv_binary.into(), - name: "gpu::eval", - io: shader.io, - }; - log::debug!("loading shader"); - log::debug!("shader: {:?}", shader.source); - let shader = executor.load_shader(shader).unwrap(); - log::debug!("loaded shader"); - let pipeline = PipelineLayout { - shader: shader.into(), - entry_point: "eval".to_string(), - bind_group: bind_group.into(), - output_buffer: output_buffer.clone(), - }; - log::debug!("created pipeline"); - let compute_pass = executor - .create_compute_pass(&pipeline, Some(readback_buffer.clone()), ComputePassDimensions::XY(background.width, background.height)) - .unwrap(); - executor.execute_compute_pipeline(compute_pass).unwrap(); - log::debug!("executed pipeline"); - log::debug!("reading buffer"); - let result = executor.read_output_buffer(readback_buffer).await.unwrap(); - let colors = bytemuck::pod_collect_to_vec::(result.as_slice()); - - let created_image = Image { - data: colors, - width: background.width, - height: background.height, - ..Default::default() - }; - - background_instance.instance = created_image; - background_instance.source_node_id = None; - result_table.push(background_instance); - } - - result_table -} - -// struct ComputePass { -// pipeline_layout: PipelineLayout, -// readback_buffer: Option>, -// } - -// impl Clone for ComputePass { -// fn clone(&self) -> Self { -// Self { -// pipeline_layout: self.pipeline_layout.clone(), -// readback_buffer: self.readback_buffer.clone(), -// } -// } -// } - -// pub struct MapGpuNode { -// node: Node, -// editor_api: EditorApi, -// cache: Mutex>, -// } - -// #[node_macro::old_node_impl(MapGpuNode)] -// async fn map_gpu<'a: 'input>(image: RasterDataTable, node: DocumentNode, editor_api: &'a graphene_core::application_io::EditorApi) -> RasterDataTable { -// let image_frame_table = ℑ -// let image = image.instance_ref_iter().next().unwrap().instance; - -// log::debug!("Executing gpu node"); -// let executor = &editor_api.application_io.as_ref().and_then(|io| io.gpu_executor()).unwrap(); - -// #[cfg(feature = "image-compare")] -// let img: image::DynamicImage = image::Rgba32FImage::from_raw(image.width, image.height, bytemuck::cast_vec(image.data.clone())).unwrap().into(); - -// // TODO: The cache should be based on the network topology not the node name -// let compute_pass_descriptor = if self.cache.lock().as_ref().unwrap().contains_key("placeholder") { -// self.cache.lock().as_ref().unwrap().get("placeholder").unwrap().clone() -// } else { -// let name = "placeholder".to_string(); -// let Ok(compute_pass_descriptor) = create_compute_pass_descriptor(node, image_frame_table, executor).await else { -// log::error!("Error creating compute pass descriptor in 'map_gpu()"); -// return RasterDataTable::default(); -// }; -// self.cache.lock().as_mut().unwrap().insert(name, compute_pass_descriptor.clone()); -// log::error!("created compute pass"); -// compute_pass_descriptor -// }; - -// let compute_pass = executor -// .create_compute_pass( -// &compute_pass_descriptor.pipeline_layout, -// compute_pass_descriptor.readback_buffer.clone(), -// ComputePassDimensions::XY(image.width / 12 + 1, image.height / 8 + 1), -// ) -// .unwrap(); -// executor.execute_compute_pipeline(compute_pass).unwrap(); -// log::debug!("executed pipeline"); -// log::debug!("reading buffer"); -// let result = executor.read_output_buffer(compute_pass_descriptor.readback_buffer.clone().unwrap()).await.unwrap(); -// let colors = bytemuck::pod_collect_to_vec::(result.as_slice()); -// log::debug!("first color: {:?}", colors[0]); - -// #[cfg(feature = "image-compare")] -// let img2: image::DynamicImage = image::Rgba32FImage::from_raw(image.width, image.height, bytemuck::cast_vec(colors.clone())).unwrap().into(); -// #[cfg(feature = "image-compare")] -// let score = image_compare::rgb_hybrid_compare(&img.into_rgb8(), &img2.into_rgb8()).unwrap(); -// #[cfg(feature = "image-compare")] -// log::debug!("score: {:?}", score.score); - -// let new_image = Image { -// data: colors, -// width: image.width, -// height: image.height, -// ..Default::default() -// }; -// let mut result = RasterDataTable::new(new_image); -// *result.transform_mut() = image_frame_table.transform(); -// *result.instance_mut_iter().next().unwrap().alpha_blending = *image_frame_table.instance_ref_iter().next().unwrap().alpha_blending; - -// result -// } - -// impl MapGpuNode { -// pub fn new(node: Node, editor_api: EditorApi) -> Self { -// Self { -// node, -// editor_api, -// cache: Mutex::new(HashMap::new()), -// } -// } -// } - -// async fn create_compute_pass_descriptor(node: DocumentNode, image: &RasterDataTable, executor: &&WgpuExecutor) -> Result -// where -// GraphicElement: From>, -// T::Static: Pixel, -// { -// let image = image.instance_ref_iter().next().unwrap().instance; - -// let compiler = graph_craft::graphene_compiler::Compiler {}; -// let inner_network = NodeNetwork::value_network(node); - -// log::debug!("inner_network: {inner_network:?}"); -// let network = NodeNetwork { -// exports: vec![NodeInput::node(NodeId(2), 0)], -// nodes: [ -// DocumentNode { -// inputs: vec![NodeInput::Inline(InlineRust::new("i1[(_global_index.y * i0 + _global_index.x) as usize]".into(), concrete![Color]))], -// implementation: DocumentNodeImplementation::ProtoNode("graphene_core::value::CopiedNode".into()), -// ..Default::default() -// }, -// DocumentNode { -// inputs: vec![NodeInput::network(concrete!(u32), 0)], -// implementation: DocumentNodeImplementation::ProtoNode("graphene_core::ops::IdentityNode".into()), -// ..Default::default() -// }, -// // DocumentNode { -// // name: "Index".into(), -// // // inputs: vec![NodeInput::Network(concrete!(UVec3))], -// // inputs: vec![NodeInput::Inline(InlineRust::new("i1.x as usize".into(), concrete![u32]))], -// // implementation: DocumentNodeImplementation::ProtoNode("graphene_core::value::CopiedNode".into()), -// // ..Default::default() -// // }, -// // DocumentNode { -// // name: "Get Node".into(), -// // inputs: vec![NodeInput::node(NodeId(1), 0), NodeInput::node(NodeId(0), 0)], -// // implementation: DocumentNodeImplementation::ProtoNode("graphene_core::storage::GetNode".into()), -// // ..Default::default() -// // }, -// DocumentNode { -// inputs: vec![NodeInput::node(NodeId(0), 0)], -// implementation: DocumentNodeImplementation::Network(inner_network), -// ..Default::default() -// }, -// // DocumentNode { -// // name: "Save Node".into(), -// // inputs: vec![ -// // NodeInput::node(NodeId(5), 0), -// // NodeInput::Inline(InlineRust::new( -// // "|x| o0[(_global_index.y * i1 + _global_index.x) as usize] = x".into(), -// // // "|x|()".into(), -// // Type::Fn(Box::new(concrete!(PackedPixel)), Box::new(concrete!(()))), -// // )), -// // ], -// // implementation: DocumentNodeImplementation::ProtoNode("graphene_core::generic::FnMutNode".into()), -// // ..Default::default() -// // }, -// ] -// .into_iter() -// .enumerate() -// .map(|(id, node)| (NodeId(id as u64), node)) -// .collect(), -// ..Default::default() -// }; -// log::debug!("compiling network"); -// let proto_networks: Result, _> = compiler.compile(network.clone()).collect(); -// log::debug!("compiling shader"); -// let shader = compilation_client::compile( -// proto_networks?, -// vec![concrete!(u32), concrete!(Color)], -// vec![concrete!(Color)], -// ShaderIO { -// inputs: vec![ -// ShaderInput::UniformBuffer((), concrete!(u32)), -// ShaderInput::StorageBuffer((), concrete!(Color)), -// ShaderInput::OutputBuffer((), concrete!(Color)), -// ], -// output: ShaderInput::OutputBuffer((), concrete!(Color)), -// }, -// ) -// .await -// .unwrap(); - -// let len: usize = image.data.len(); - -// let storage_buffer = executor -// .create_storage_buffer( -// image.data.clone(), -// StorageBufferOptions { -// cpu_writable: false, -// gpu_writable: true, -// cpu_readable: false, -// storage: true, -// }, -// ) -// .unwrap(); - -// // let canvas = editor_api.application_io.create_surface(); - -// // let surface = unsafe { executor.create_surface(canvas) }.unwrap(); -// // let surface_id = surface.surface_id; - -// // let texture = executor.create_texture_buffer(image.clone(), TextureBufferOptions::Texture).unwrap(); - -// // // executor.create_render_pass(texture, surface).unwrap(); - -// // let frame = SurfaceFrame { -// // surface_id, -// // transform: image.transform, -// // }; -// // return frame; - -// log::debug!("creating buffer"); -// let width_uniform = executor.create_uniform_buffer(image.width).unwrap(); - -// let storage_buffer = Arc::new(storage_buffer); -// let output_buffer = executor.create_output_buffer(len, concrete!(Color), false).unwrap(); -// let output_buffer = Arc::new(output_buffer); -// let readback_buffer = executor.create_output_buffer(len, concrete!(Color), true).unwrap(); -// let readback_buffer = Arc::new(readback_buffer); -// log::debug!("created buffer"); -// let bind_group = Bindgroup { -// buffers: vec![width_uniform.into(), storage_buffer], -// }; - -// let shader = Shader { -// source: shader.spirv_binary.into(), -// name: "gpu::eval", -// io: shader.io, -// }; -// log::debug!("loading shader"); -// let shader = executor.load_shader(shader).unwrap(); -// log::debug!("loaded shader"); -// let pipeline = PipelineLayout { -// shader: shader.into(), -// entry_point: "eval".to_string(), -// bind_group: bind_group.into(), -// output_buffer, -// }; -// log::debug!("created pipeline"); - -// Ok(ComputePass { -// pipeline_layout: pipeline, -// readback_buffer: Some(readback_buffer), -// }) -// } diff --git a/node-graph/gstd/src/image_color_palette.rs b/node-graph/gstd/src/image_color_palette.rs index 931ad809..6ed548f0 100644 --- a/node-graph/gstd/src/image_color_palette.rs +++ b/node-graph/gstd/src/image_color_palette.rs @@ -1,10 +1,10 @@ -use graphene_core::raster::image::RasterDataTable; +use graphene_core::raster_types::{CPU, RasterDataTable}; use graphene_core::{Color, Ctx}; #[node_macro::node(category("Raster"))] async fn image_color_palette( _: impl Ctx, - image: RasterDataTable, + image: RasterDataTable, #[hard_min(1.)] #[soft_max(28.)] max_size: u32, @@ -64,18 +64,19 @@ async fn image_color_palette( #[cfg(test)] mod test { use super::*; - use graphene_core::raster::image::{Image, RasterDataTable}; + use graphene_core::raster::image::Image; + use graphene_core::raster_types::{Raster, RasterDataTable}; #[test] fn test_image_color_palette() { let result = image_color_palette( (), - RasterDataTable::new(Image { + RasterDataTable::new(Raster::new_cpu(Image { width: 100, height: 100, data: vec![Color::from_rgbaf32(0., 0., 0., 1.).unwrap(); 10000], base64_string: None, - }), + })), 1, ); assert_eq!(futures::executor::block_on(result), [Color::from_rgbaf32(0., 0., 0., 1.).unwrap()]); diff --git a/node-graph/gstd/src/lib.rs b/node-graph/gstd/src/lib.rs index 2beb43cb..c469d9d3 100644 --- a/node-graph/gstd/src/lib.rs +++ b/node-graph/gstd/src/lib.rs @@ -1,6 +1,4 @@ pub mod any; -#[cfg(feature = "gpu")] -pub mod gpu_nodes; pub mod http; pub mod raster; pub mod text; diff --git a/node-graph/gstd/src/raster.rs b/node-graph/gstd/src/raster.rs index 6aa3de21..be14cc58 100644 --- a/node-graph/gstd/src/raster.rs +++ b/node-graph/gstd/src/raster.rs @@ -3,8 +3,10 @@ use fastnoise_lite; use glam::{DAffine2, DVec2, Vec2}; use graphene_core::instances::Instance; use graphene_core::raster::bbox::Bbox; -use graphene_core::raster::image::{Image, RasterDataTable}; -use graphene_core::raster::{Alpha, AlphaMut, Bitmap, BitmapMut, CellularDistanceFunction, CellularReturnType, Channel, DomainWarpType, FractalType, LinearChannel, Luminance, NoiseType, RGBMut}; +use graphene_core::raster::{ + Alpha, AlphaMut, Bitmap, BitmapMut, CellularDistanceFunction, CellularReturnType, Channel, DomainWarpType, FractalType, Image, LinearChannel, Luminance, NoiseType, RGBMut, +}; +use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use graphene_core::transform::Transform; use graphene_core::{AlphaBlending, Color, Ctx, ExtractFootprint}; use rand::prelude::*; @@ -25,7 +27,7 @@ impl From for Error { } #[node_macro::node(category("Debug: Raster"))] -fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: RasterDataTable) -> RasterDataTable { +fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: RasterDataTable) -> RasterDataTable { let mut result_table = RasterDataTable::default(); for mut image_frame_instance in image_frame.instance_iter() { @@ -84,7 +86,7 @@ fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: RasterDa image_frame_instance.transform = new_transform; image_frame_instance.source_node_id = None; - image_frame_instance.instance = image; + image_frame_instance.instance = Raster::new_cpu(image); result_table.push(image_frame_instance) } @@ -95,11 +97,11 @@ fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: RasterDa fn combine_channels( _: impl Ctx, _primary: (), - #[expose] red: RasterDataTable, - #[expose] green: RasterDataTable, - #[expose] blue: RasterDataTable, - #[expose] alpha: RasterDataTable, -) -> RasterDataTable { + #[expose] red: RasterDataTable, + #[expose] green: RasterDataTable, + #[expose] blue: RasterDataTable, + #[expose] alpha: RasterDataTable, +) -> RasterDataTable { let mut result_table = RasterDataTable::default(); let max_len = red.len().max(green.len()).max(blue.len()).max(alpha.len()); @@ -170,7 +172,7 @@ fn combine_channels( // Add this instance to the result table result_table.push(Instance { - instance: image, + instance: Raster::new_cpu(image), transform, alpha_blending, source_node_id: None, @@ -184,11 +186,11 @@ fn combine_channels( fn mask( _: impl Ctx, /// The image to be masked. - image: RasterDataTable, + image: RasterDataTable, /// The stencil to be used for masking. #[expose] - stencil: RasterDataTable, -) -> RasterDataTable { + stencil: RasterDataTable, +) -> RasterDataTable { // TODO: Support multiple stencil instances let Some(stencil_instance) = stencil.instance_iter().next() else { // No stencil provided so we return the original image @@ -218,7 +220,7 @@ fn mask( let mask_point = stencil_instance.transform.transform_point2(local_mask_point.clamp(DVec2::ZERO, DVec2::ONE)); let mask_point = (DAffine2::from_scale(stencil_size) * stencil_instance.transform.inverse()).transform_point2(mask_point); - let image_pixel = image_instance.instance.get_pixel_mut(x, y).unwrap(); + let image_pixel = image_instance.instance.data_mut().get_pixel_mut(x, y).unwrap(); let mask_pixel = stencil_instance.instance.sample(mask_point); *image_pixel = image_pixel.multiplied_alpha(mask_pixel.l().cast_linear_channel()); } @@ -231,7 +233,7 @@ fn mask( } #[node_macro::node(category(""))] -fn extend_image_to_bounds(_: impl Ctx, image: RasterDataTable, bounds: DAffine2) -> RasterDataTable { +fn extend_image_to_bounds(_: impl Ctx, image: RasterDataTable, bounds: DAffine2) -> RasterDataTable { let mut result_table = RasterDataTable::default(); for mut image_instance in image.instance_iter() { @@ -242,7 +244,7 @@ fn extend_image_to_bounds(_: impl Ctx, image: RasterDataTable, bounds: DA continue; } - let image_data = image_instance.instance.data; + let image_data = &image_instance.instance.data; let (image_width, image_height) = (image_instance.instance.width, image_instance.instance.height); if image_width == 0 || image_height == 0 { for image_instance in empty_image((), bounds, Color::TRANSPARENT).instance_iter() { @@ -274,7 +276,7 @@ fn extend_image_to_bounds(_: impl Ctx, image: RasterDataTable, bounds: DA // let layer_to_new_texture_space = (DAffine2::from_scale(1. / new_scale) * DAffine2::from_translation(new_start) * layer_to_image_space).inverse(); let new_texture_to_layer_space = image_instance.transform * DAffine2::from_scale(1. / orig_image_scale) * DAffine2::from_translation(new_start) * DAffine2::from_scale(new_scale); - image_instance.instance = new_image; + image_instance.instance = Raster::new_cpu(new_image); image_instance.transform = new_texture_to_layer_space; image_instance.source_node_id = None; result_table.push(image_instance); @@ -284,13 +286,13 @@ fn extend_image_to_bounds(_: impl Ctx, image: RasterDataTable, bounds: DA } #[node_macro::node(category("Debug: Raster"))] -fn empty_image(_: impl Ctx, transform: DAffine2, color: Color) -> RasterDataTable { +fn empty_image(_: impl Ctx, transform: DAffine2, color: Color) -> RasterDataTable { let width = transform.transform_vector2(DVec2::new(1., 0.)).length() as u32; let height = transform.transform_vector2(DVec2::new(0., 1.)).length() as u32; let image = Image::new(width, height, color); - let mut result_table = RasterDataTable::new(image); + let mut result_table = RasterDataTable::new(Raster::new_cpu(image)); let image_instance = result_table.get_mut(0).unwrap(); *image_instance.transform = transform; *image_instance.alpha_blending = AlphaBlending::default(); @@ -301,7 +303,7 @@ fn empty_image(_: impl Ctx, transform: DAffine2, color: Color) -> RasterDataTabl /// Constructs a raster image. #[node_macro::node(category(""))] -fn image(_: impl Ctx, _primary: (), image: RasterDataTable) -> RasterDataTable { +fn image(_: impl Ctx, _primary: (), image: RasterDataTable) -> RasterDataTable { image } @@ -424,7 +426,7 @@ fn noise_pattern( cellular_distance_function: CellularDistanceFunction, cellular_return_type: CellularReturnType, cellular_jitter: f64, -) -> RasterDataTable { +) -> RasterDataTable { let footprint = ctx.footprint(); let viewport_bounds = footprint.viewport_bounds_in_local_space(); @@ -488,7 +490,7 @@ fn noise_pattern( let mut result = RasterDataTable::default(); result.push(Instance { - instance: image, + instance: Raster::new_cpu(image), transform: DAffine2::from_translation(offset) * DAffine2::from_scale(size), ..Default::default() }); @@ -553,7 +555,7 @@ fn noise_pattern( let mut result = RasterDataTable::default(); result.push(Instance { - instance: image, + instance: Raster::new_cpu(image), transform: DAffine2::from_translation(offset) * DAffine2::from_scale(size), ..Default::default() }); @@ -562,7 +564,7 @@ fn noise_pattern( } #[node_macro::node(category("Raster"))] -fn mandelbrot(ctx: impl ExtractFootprint + Send) -> RasterDataTable { +fn mandelbrot(ctx: impl ExtractFootprint + Send) -> RasterDataTable { let footprint = ctx.footprint(); let viewport_bounds = footprint.viewport_bounds_in_local_space(); @@ -604,7 +606,7 @@ fn mandelbrot(ctx: impl ExtractFootprint + Send) -> RasterDataTable { }; let mut result = RasterDataTable::default(); result.push(Instance { - instance: image, + instance: Raster::new_cpu(image), transform: DAffine2::from_translation(offset) * DAffine2::from_scale(size), ..Default::default() }); diff --git a/node-graph/gstd/src/vector.rs b/node-graph/gstd/src/vector.rs index f0a5111d..332694f8 100644 --- a/node-graph/gstd/src/vector.rs +++ b/node-graph/gstd/src/vector.rs @@ -1,6 +1,5 @@ use bezier_rs::{ManipulatorGroup, Subpath}; use glam::{DAffine2, DVec2}; -use graphene_core::RasterDataType; use graphene_core::instances::{Instance, InstanceRef}; use graphene_core::vector::misc::BooleanOperation; use graphene_core::vector::style::Fill; @@ -203,7 +202,7 @@ fn flatten_vector_data(graphic_group_table: &GraphicGroupTable) -> VectorDataTab result_table.push(sub_vector_data); } } - GraphicElement::RasterDataType(image) => { + GraphicElement::RasterDataCPU(image) => { let make_instance = |transform| { // Convert the image frame into a rectangular subpath with the image's transform let mut subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE); @@ -217,17 +216,26 @@ fn flatten_vector_data(graphic_group_table: &GraphicGroupTable) -> VectorDataTab }; // Apply the parent group's transform to each element of raster data - match image { - RasterDataType::RasterData(image) => { - for instance in image.instance_ref_iter() { - result_table.push(make_instance(*element.transform * *instance.transform)); - } - } - RasterDataType::TextureData(image) => { - for instance in image.instance_ref_iter() { - result_table.push(make_instance(*element.transform * *instance.transform)); - } - } + for instance in image.instance_ref_iter() { + result_table.push(make_instance(*element.transform * *instance.transform)); + } + } + GraphicElement::RasterDataGPU(image) => { + let make_instance = |transform| { + // Convert the image frame into a rectangular subpath with the image's transform + let mut subpath = Subpath::new_rect(DVec2::ZERO, DVec2::ONE); + subpath.apply_transform(transform); + + // Create a vector data table row from the rectangular subpath, with a default black fill + let mut instance = VectorData::from_subpath(subpath); + instance.style.set_fill(Fill::Solid(Color::BLACK)); + + Instance { instance, ..Default::default() } + }; + + // Apply the parent group's transform to each element of raster data + for instance in image.instance_ref_iter() { + result_table.push(make_instance(*element.transform * *instance.transform)); } } GraphicElement::GraphicGroup(mut graphic_group) => { diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index 6a1afd59..176355ea 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -8,7 +8,8 @@ use graphene_core::application_io::{ApplicationIo, ExportFormat, RenderConfig}; use graphene_core::instances::Instances; #[cfg(target_arch = "wasm32")] use graphene_core::raster::bbox::Bbox; -use graphene_core::raster::image::{Image, RasterDataTable}; +use graphene_core::raster::image::Image; +use graphene_core::raster_types::{CPU, Raster, RasterDataTable}; use graphene_core::renderer::RenderMetadata; use graphene_core::renderer::{GraphicElementRendered, RenderParams, RenderSvgSegmentList, SvgRender, format_transform_matrix}; use graphene_core::transform::Footprint; @@ -76,7 +77,7 @@ async fn load_resource<'a: 'n>(_: impl Ctx, _primary: (), #[scope("editor-api")] } #[node_macro::node(category("Network"))] -fn decode_image(_: impl Ctx, data: Arc<[u8]>) -> RasterDataTable { +fn decode_image(_: impl Ctx, data: Arc<[u8]>) -> RasterDataTable { let Some(image) = image::load_from_memory(data.as_ref()).ok() else { return RasterDataTable::default(); }; @@ -91,7 +92,7 @@ fn decode_image(_: impl Ctx, data: Arc<[u8]>) -> RasterDataTable { ..Default::default() }; - RasterDataTable::new(image) + RasterDataTable::new(Raster::new_cpu(image)) } fn render_svg(data: impl GraphicElementRendered, mut render: SvgRender, render_params: RenderParams, footprint: Footprint) -> RenderOutputType { @@ -165,13 +166,13 @@ async fn rasterize( _: impl Ctx, #[implementations( VectorDataTable, - RasterDataTable, + RasterDataTable, GraphicGroupTable, )] mut data: Instances, footprint: Footprint, surface_handle: Arc>, -) -> RasterDataTable +) -> RasterDataTable where Instances: GraphicElementRendered, { @@ -219,8 +220,9 @@ where let rasterized = context.get_image_data(0., 0., resolution.x as f64, resolution.y as f64).unwrap(); let mut result = RasterDataTable::default(); + let image = Image::from_image_data(&rasterized.data().0, resolution.x as u32, resolution.y as u32); result.push(Instance { - instance: Image::from_image_data(&rasterized.data().0, resolution.x as u32, resolution.y as u32), + instance: Raster::new_cpu(image), transform: footprint.transform, ..Default::default() }); @@ -234,7 +236,7 @@ async fn render<'a: 'n, T: 'n + GraphicElementRendered + WasmNotSend>( editor_api: impl Node, Output = &'a WasmEditorApi>, #[implementations( Context -> VectorDataTable, - Context -> RasterDataTable, + Context -> RasterDataTable, Context -> GraphicGroupTable, Context -> graphene_core::Artboard, Context -> graphene_core::ArtboardGroupTable, diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index cd08873c..8423d6a8 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -3,8 +3,8 @@ use glam::{DVec2, UVec2}; use graph_craft::document::value::RenderOutput; use graph_craft::proto::{NodeConstructor, TypeErasedBox}; use graphene_core::raster::color::Color; -use graphene_core::raster::image::RasterDataTable; use graphene_core::raster::*; +use graphene_core::raster_types::{CPU, GPU, RasterDataTable}; use graphene_core::vector::VectorDataTable; use graphene_core::{Artboard, GraphicGroupTable, concrete, generic}; use graphene_core::{Cow, ProtoNodeIdentifier, Type}; @@ -13,7 +13,7 @@ use graphene_core::{fn_type_fut, future}; use graphene_std::Context; use graphene_std::GraphicElement; use graphene_std::any::{ComposeTypeErased, DowncastBothNode, DynAnyNode, IntoTypeErasedNode}; -use graphene_std::application_io::{ImageTexture, TextureDataTable}; +use graphene_std::application_io::ImageTexture; use graphene_std::wasm_application_io::*; use node_registry_macros::{async_node, into_node}; use once_cell::sync::Lazy; @@ -34,17 +34,18 @@ fn node_registry() -> HashMap, to: RasterDataTable), - into_node!(from: RasterDataTable, to: RasterDataTable), - into_node!(from: RasterDataTable, to: GraphicElement), - into_node!(from: RasterDataTable, to: GraphicGroupTable), - async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => RasterDataTable]), + into_node!(from: RasterDataTable, to: RasterDataTable), + // into_node!(from: RasterDataTable, to: RasterDataTable), + into_node!(from: RasterDataTable, to: GraphicElement), + into_node!(from: RasterDataTable, to: GraphicGroupTable), + async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => RasterDataTable]), async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]), async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => VectorDataTable]), async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => GraphicGroupTable]), async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => GraphicElement]), async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => Artboard]), - async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::RasterDataType]), + async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => RasterDataTable]), + async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => RasterDataTable]), async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => graphene_core::instances::Instances]), async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => String]), async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => glam::IVec2]), @@ -70,7 +71,7 @@ fn node_registry() -> HashMap, input: Context, fn_params: [Context => Box]), async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Image]), async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => VectorDataTable]), - async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RasterDataTable]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RasterDataTable]), async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => GraphicGroupTable]), async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Vec]), async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => Arc]), @@ -112,9 +113,9 @@ fn node_registry() -> HashMap, input: Context, fn_params: [Context => ShaderInputFrame]), #[cfg(feature = "gpu")] - async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => TextureDataTable]), + async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => RasterDataTable]), #[cfg(feature = "gpu")] - async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => TextureDataTable]), + async_node!(graphene_core::memo::MemoNode<_, _>, input: Context, fn_params: [Context => RasterDataTable]), #[cfg(feature = "gpu")] into_node!(from: &WasmEditorApi, to: &WgpuExecutor), #[cfg(feature = "gpu")] diff --git a/node-graph/node-macro/src/parsing.rs b/node-graph/node-macro/src/parsing.rs index ab570520..64fac25e 100644 --- a/node-graph/node-macro/src/parsing.rs +++ b/node-graph/node-macro/src/parsing.rs @@ -992,7 +992,7 @@ mod tests { fn test_async_node() { let attr = quote!(category("IO")); let input = quote!( - async fn load_image(api: &WasmEditorApi, #[expose] path: String) -> RasterDataTable { + async fn load_image(api: &WasmEditorApi, #[expose] path: String) -> RasterDataTable { // Implementation details... } ); @@ -1016,7 +1016,7 @@ mod tests { ty: parse_quote!(&WasmEditorApi), implementations: Punctuated::new(), }, - output_type: parse_quote!(RasterDataTable), + output_type: parse_quote!(RasterDataTable), is_async: true, fields: vec![ParsedField::Regular { pat_ident: pat_ident("path"), @@ -1132,7 +1132,7 @@ mod tests { fn test_invalid_implementation_syntax() { let attr = quote!(category("Test")); let input = quote!( - fn test_node(_: (), #[implementations((Footprint, Color), (Footprint, RasterDataTable))] input: impl Node) -> T { + fn test_node(_: (), #[implementations((Footprint, Color), (Footprint, RasterDataTable))] input: impl Node) -> T { // Implementation details... } ); @@ -1158,10 +1158,10 @@ mod tests { #[implementations((), #tuples, Footprint)] footprint: F, #[implementations( () -> Color, - () -> RasterDataTable, + () -> RasterDataTable, () -> GradientStops, Footprint -> Color, - Footprint -> RasterDataTable, + Footprint -> RasterDataTable, Footprint -> GradientStops, )] image: impl Node, diff --git a/node-graph/wgpu-executor/src/lib.rs b/node-graph/wgpu-executor/src/lib.rs index b70764a2..7f50e9d1 100644 --- a/node-graph/wgpu-executor/src/lib.rs +++ b/node-graph/wgpu-executor/src/lib.rs @@ -8,10 +8,10 @@ pub use executor::GpuExecutor; use futures::Future; use glam::{DAffine2, UVec2}; use gpu_executor::{ComputePassDimensions, GPUConstant, StorageBufferOptions, TextureBufferOptions, TextureBufferType, ToStorageBuffer, ToUniformBuffer}; -use graphene_core::application_io::{ApplicationIo, EditorApi, ImageTexture, SurfaceHandle, TextureDataTable}; +use graphene_core::application_io::{ApplicationIo, EditorApi, SurfaceHandle}; use graphene_core::instances::Instance; -use graphene_core::raster::image::RasterDataTable; use graphene_core::raster::{Image, SRGBA8}; +use graphene_core::raster_types::{CPU, GPU, Raster, RasterDataTable}; use graphene_core::transform::{Footprint, Transform}; use graphene_core::{Color, Cow, Ctx, ExtractFootprint, Node, SurfaceFrame, Type}; use std::pin::Pin; @@ -911,8 +911,8 @@ async fn render_texture<'a: 'n>( } #[node_macro::node(category(""))] -async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: RasterDataTable, executor: &'a WgpuExecutor) -> TextureDataTable { - let mut result_table = TextureDataTable::default(); +async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: RasterDataTable, executor: &'a WgpuExecutor) -> RasterDataTable { + let mut result_table = RasterDataTable::::default(); for instance in input.instance_ref_iter() { let image = instance.instance; @@ -932,7 +932,7 @@ async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: RasterDat }; result_table.push(Instance { - instance: ImageTexture { texture: texture.into() }, + instance: Raster::new_gpu(texture.into()), transform: *instance.transform, alpha_blending: *instance.alpha_blending, source_node_id: *instance.source_node_id,