diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 43691f39..004f5a9f 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -28,7 +28,7 @@ use crate::node_graph_executor::NodeGraphExecutor; use bezier_rs::Subpath; use graph_craft::document::value::TaggedValue; use graph_craft::document::{NodeId, NodeInput, NodeNetwork, OldNodeNetwork}; -use graphene_core::raster::image::{ImageFrame, ImageFrameTable}; +use graphene_core::raster::image::ImageFrameTable; use graphene_core::raster::BlendMode; use graphene_core::vector::style::ViewMode; use graphene_std::renderer::{ClickTarget, Quad}; @@ -818,7 +818,7 @@ impl MessageHandler> for DocumentMessag responses.add(DocumentMessage::AddTransaction); - let layer = graph_modification_utils::new_image_layer(ImageFrameTable::new(ImageFrame { image }), layer_node_id, self.new_layer_parent(true), responses); + let layer = graph_modification_utils::new_image_layer(ImageFrameTable::new(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/node_graph/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_properties.rs index ee3c56f7..2b68bccc 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_properties.rs @@ -20,7 +20,7 @@ use graphene_core::raster::{ use graphene_core::text::Font; use graphene_core::vector::misc::CentroidType; use graphene_core::vector::style::{GradientType, LineCap, LineJoin}; -use graphene_std::application_io::TextureFrame; +use graphene_std::application_io::TextureFrameTable; use graphene_std::transform::Footprint; use graphene_std::vector::misc::BooleanOperation; use graphene_std::vector::style::{Fill, FillChoice, FillType, GradientStops}; @@ -159,7 +159,7 @@ pub(crate) fn property_from_type( Some(x) if x == TypeId::of::() => curves_widget(document_node, node_id, index, name, true), Some(x) if x == TypeId::of::() => color_widget(document_node, node_id, index, name, ColorInput::default().allow_none(false), true), Some(x) if x == TypeId::of::() => vector_widget(document_node, node_id, index, name, true).into(), - Some(x) if x == TypeId::of::() || x == TypeId::of::>() || x == TypeId::of::() => { + Some(x) if x == TypeId::of::() || x == TypeId::of::>() || x == TypeId::of::() => { raster_widget(document_node, node_id, index, name, true).into() } Some(x) if x == TypeId::of::() => group_widget(document_node, node_id, index, name, true).into(), diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index f94f3716..3f74f9e4 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -6222,10 +6222,11 @@ impl PropertiesRow { fn migrate_output_names<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result, D::Error> { use serde::Deserialize; - const REPLACEMENTS: [(&str, &str); 3] = [ + const REPLACEMENTS: [(&str, &str); 4] = [ ("VectorData", "Instances"), ("GraphicGroup", "Instances"), - ("ImageFrame", "Instances"), + ("ImageFrame", "Instances"), + ("Instances", "Instances"), ]; let mut names = Vec::::deserialize(deserializer)?; diff --git a/node-graph/gcore/src/application_io.rs b/node-graph/gcore/src/application_io.rs index 88a256a8..f2cd8984 100644 --- a/node-graph/gcore/src/application_io.rs +++ b/node-graph/gcore/src/application_io.rs @@ -64,17 +64,18 @@ impl Size for web_sys::HtmlCanvasElement { } } -pub type TextureFrameTable = Instances; +// TODO: Rename to ImageTextureTable +pub type TextureFrameTable = Instances; #[derive(Debug, Clone)] -pub struct TextureFrame { +pub struct ImageTexture { #[cfg(feature = "wgpu")] pub texture: Arc, #[cfg(not(feature = "wgpu"))] pub texture: (), } -impl Hash for TextureFrame { +impl Hash for ImageTexture { #[cfg(feature = "wgpu")] fn hash(&self, state: &mut H) { self.texture.hash(state); @@ -83,18 +84,18 @@ impl Hash for TextureFrame { fn hash(&self, _state: &mut H) {} } -impl PartialEq for TextureFrame { +impl PartialEq for ImageTexture { fn eq(&self, other: &Self) -> bool { self.texture == other.texture } } -unsafe impl StaticType for TextureFrame { - type Static = TextureFrame; +unsafe impl StaticType for ImageTexture { + type Static = ImageTexture; } #[cfg(feature = "wgpu")] -impl Size for TextureFrame { +impl Size for ImageTexture { fn size(&self) -> UVec2 { UVec2::new(self.texture.width(), self.texture.height()) } diff --git a/node-graph/gcore/src/graphic_element.rs b/node-graph/gcore/src/graphic_element.rs index 2ef32a53..d10fa200 100644 --- a/node-graph/gcore/src/graphic_element.rs +++ b/node-graph/gcore/src/graphic_element.rs @@ -1,6 +1,6 @@ -use crate::application_io::{TextureFrame, TextureFrameTable}; +use crate::application_io::{ImageTexture, TextureFrameTable}; use crate::instances::Instances; -use crate::raster::image::{ImageFrame, ImageFrameTable}; +use crate::raster::image::{Image, ImageFrameTable}; use crate::raster::BlendMode; use crate::transform::{Transform, TransformMut}; use crate::uuid::NodeId; @@ -111,9 +111,9 @@ impl From for GraphicGroupTable { Self::new(GraphicGroup::new(vec![GraphicElement::VectorData(vector_data)])) } } -impl From> for GraphicGroupTable { - fn from(image_frame: ImageFrame) -> Self { - Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::ImageFrame(ImageFrameTable::new(image_frame)))])) +impl From> for GraphicGroupTable { + fn from(image: Image) -> Self { + Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::ImageFrame(ImageFrameTable::new(image)))])) } } impl From> for GraphicGroupTable { @@ -121,9 +121,9 @@ impl From> for GraphicGroupTable { Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::ImageFrame(image_frame))])) } } -impl From for GraphicGroupTable { - fn from(texture_frame: TextureFrame) -> Self { - Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::TextureFrame(TextureFrameTable::new(texture_frame)))])) +impl From for GraphicGroupTable { + fn from(image_texture: ImageTexture) -> Self { + Self::new(GraphicGroup::new(vec![GraphicElement::RasterFrame(RasterFrame::TextureFrame(TextureFrameTable::new(image_texture)))])) } } impl From for GraphicGroupTable { @@ -194,11 +194,14 @@ impl GraphicElement { } } +// TODO: Rename to Raster #[derive(Clone, Debug, Hash, PartialEq, DynAny)] pub 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 + // TODO: Rename to ImageTable ImageFrame(ImageFrameTable), /// A GPU texture with a finite position and extent + // TODO: Rename to ImageTextureTable TextureFrame(TextureFrameTable), } @@ -207,7 +210,7 @@ impl<'de> serde::Deserialize<'de> for RasterFrame { where D: serde::Deserializer<'de>, { - Ok(RasterFrame::ImageFrame(ImageFrameTable::new(ImageFrame::deserialize(deserializer)?))) + Ok(RasterFrame::ImageFrame(ImageFrameTable::new(Image::deserialize(deserializer)?))) } } @@ -239,7 +242,7 @@ impl Artboard { pub fn new(location: IVec2, dimensions: IVec2) -> Self { Self { graphic_group: GraphicGroupTable::default(), - label: String::from("Artboard"), + label: "Artboard".to_string(), location: location.min(location + dimensions), dimensions: dimensions.abs(), background: Color::WHITE, @@ -382,16 +385,13 @@ async fn to_artboard + 'n>( } #[node_macro::node(category(""))] -async fn append_artboard(ctx: impl Ctx, mut artboards: ArtboardGroup, artboard: Artboard, node_path: Vec) -> ArtboardGroup { +async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroup, artboard: Artboard, node_path: Vec) -> ArtboardGroup { // let mut artboards = artboards.eval(ctx.clone()).await; // let artboard = artboard.eval(ctx).await; // let foot = ctx.footprint(); // log::debug!("{:?}", foot); - // Get the penultimate element of the node path, or None if the path is too short - - // TODO: Delete this line - let _ctx = ctx; - + // Get the penultimate element of the node path, or None if the path is too short. + // This is used to get the ID of the user-facing "Artboard" node (which encapsulates this internal "Append Artboard" node). let encapsulating_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied(); artboards.append_artboard(artboard, encapsulating_node_id); @@ -399,8 +399,8 @@ async fn append_artboard(ctx: impl Ctx, mut artboards: ArtboardGroup, artboard: } // TODO: Remove this one -impl From> for GraphicElement { - fn from(image_frame: ImageFrame) -> Self { +impl From> for GraphicElement { + fn from(image_frame: Image) -> Self { GraphicElement::RasterFrame(RasterFrame::ImageFrame(ImageFrameTable::new(image_frame))) } } @@ -410,8 +410,8 @@ impl From> for GraphicElement { } } // TODO: Remove this one -impl From for GraphicElement { - fn from(texture: TextureFrame) -> Self { +impl From for GraphicElement { + fn from(texture: ImageTexture) -> Self { GraphicElement::RasterFrame(RasterFrame::TextureFrame(TextureFrameTable::new(texture))) } } @@ -462,7 +462,7 @@ trait ToGraphicElement: Into {} impl ToGraphicElement for VectorDataTable {} impl ToGraphicElement for ImageFrameTable {} -impl ToGraphicElement for TextureFrame {} +impl ToGraphicElement for ImageTexture {} impl From for GraphicGroup where diff --git a/node-graph/gcore/src/graphic_element/renderer.rs b/node-graph/gcore/src/graphic_element/renderer.rs index 2888b897..0b73ded9 100644 --- a/node-graph/gcore/src/graphic_element/renderer.rs +++ b/node-graph/gcore/src/graphic_element/renderer.rs @@ -276,6 +276,7 @@ pub struct RenderMetadata { pub clip_targets: HashSet, } +// TODO: Rename to "Graphical" pub trait GraphicElementRendered { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams); @@ -831,7 +832,7 @@ impl GraphicElementRendered for ImageFrameTable { match render_params.image_render_mode { ImageRenderMode::Base64 => { - let image = &instance.instance.image; + let image = &instance.instance; if image.data.is_empty() { return; } @@ -894,7 +895,7 @@ impl GraphicElementRendered for ImageFrameTable { use vello::peniko; for instance in self.instances() { - let image = &instance.instance.image; + let image = &instance.instance; if image.data.is_empty() { return; } @@ -918,7 +919,7 @@ impl GraphicElementRendered for RasterFrame { }; for instance in image.instances() { - let (image, blending) = (&instance.instance.image, instance.alpha_blending); + let (image, blending) = (&instance.instance, instance.alpha_blending); if image.data.is_empty() { return; } @@ -992,9 +993,9 @@ impl GraphicElementRendered for RasterFrame { }; match self { - RasterFrame::ImageFrame(image_frame) => { - for instance in image_frame.instances() { - let image = &instance.instance.image; + RasterFrame::ImageFrame(image) => { + for instance in image.instances() { + let image = &instance.instance; if image.data.is_empty() { return; } @@ -1004,8 +1005,8 @@ impl GraphicElementRendered for RasterFrame { render_stuff(image, *instance.alpha_blending); } } - RasterFrame::TextureFrame(texture) => { - for instance in texture.instances() { + RasterFrame::TextureFrame(image_texture) => { + for instance in image_texture.instances() { let image = vello::peniko::Image::new(vec![].into(), peniko::Format::Rgba8, instance.instance.texture.width(), instance.instance.texture.height()).with_extend(peniko::Extend::Repeat); diff --git a/node-graph/gcore/src/instances.rs b/node-graph/gcore/src/instances.rs index 9260b656..b86fb8b4 100644 --- a/node-graph/gcore/src/instances.rs +++ b/node-graph/gcore/src/instances.rs @@ -1,5 +1,5 @@ -use crate::application_io::{TextureFrame, TextureFrameTable}; -use crate::raster::image::{ImageFrame, ImageFrameTable}; +use crate::application_io::{ImageTexture, TextureFrameTable}; +use crate::raster::image::{Image, ImageFrameTable}; use crate::raster::Pixel; use crate::transform::{Transform, TransformMut}; use crate::vector::{InstanceId, VectorData, VectorDataTable}; @@ -180,18 +180,18 @@ impl TransformMut for GraphicGroupTable { } } -// TEXTURE FRAME -impl Transform for Instance<'_, TextureFrame> { +// IMAGE TEXTURE +impl Transform for Instance<'_, ImageTexture> { fn transform(&self) -> DAffine2 { *self.transform } } -impl Transform for InstanceMut<'_, TextureFrame> { +impl Transform for InstanceMut<'_, ImageTexture> { fn transform(&self) -> DAffine2 { *self.transform } } -impl TransformMut for InstanceMut<'_, TextureFrame> { +impl TransformMut for InstanceMut<'_, ImageTexture> { fn transform_mut(&mut self) -> &mut DAffine2 { self.transform } @@ -209,8 +209,8 @@ impl TransformMut for TextureFrameTable { } } -// IMAGE FRAME -impl Transform for Instance<'_, ImageFrame

> { +// IMAGE +impl Transform for Instance<'_, Image

> { fn transform(&self) -> DAffine2 { *self.transform } @@ -218,7 +218,7 @@ impl Transform for Instance<'_, ImageFrame

> { self.transform.transform_point2(pivot) } } -impl Transform for InstanceMut<'_, ImageFrame

> { +impl Transform for InstanceMut<'_, Image

> { fn transform(&self) -> DAffine2 { *self.transform } @@ -226,7 +226,7 @@ impl Transform for InstanceMut<'_, ImageFrame

> { self.transform.transform_point2(pivot) } } -impl TransformMut for InstanceMut<'_, ImageFrame

> { +impl TransformMut for InstanceMut<'_, Image

> { fn transform_mut(&mut self) -> &mut DAffine2 { self.transform } @@ -237,7 +237,7 @@ impl Transform for ImageFrameTable

where P: dyn_any::StaticType, P::Static: Pixel, - GraphicElement: From>, + GraphicElement: From>, { fn transform(&self) -> DAffine2 { self.one_instance().transform() @@ -247,7 +247,7 @@ impl TransformMut for ImageFrameTable

where P: dyn_any::StaticType, P::Static: Pixel, - GraphicElement: From>, + GraphicElement: From>, { fn transform_mut(&mut self) -> &mut DAffine2 { self.transform.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED")) diff --git a/node-graph/gcore/src/raster/adjustments.rs b/node-graph/gcore/src/raster/adjustments.rs index 845446cc..d19a559e 100644 --- a/node-graph/gcore/src/raster/adjustments.rs +++ b/node-graph/gcore/src/raster/adjustments.rs @@ -3,7 +3,7 @@ #[cfg(feature = "alloc")] use crate::raster::curve::{Curve, CurveManipulatorGroup, ValueMapperNode}; #[cfg(feature = "alloc")] -use crate::raster::image::{ImageFrame, ImageFrameTable}; +use crate::raster::image::{Image, ImageFrameTable}; use crate::raster::{Channel, Color, Pixel}; use crate::registry::types::{Angle, Percentage, SignedPercentage}; use crate::vector::style::GradientStops; @@ -605,15 +605,13 @@ impl Blend for ImageFrameTable { let mut result = self.clone(); for (over, under) in result.instances_mut().zip(under.instances()) { - let data = over.instance.image.data.iter().zip(under.instance.image.data.iter()).map(|(a, b)| blend_fn(*a, *b)).collect(); + let data = over.instance.data.iter().zip(under.instance.data.iter()).map(|(a, b)| blend_fn(*a, *b)).collect(); - *over.instance = ImageFrame { - image: super::Image { - data, - width: over.instance.image.width, - height: over.instance.image.height, - base64_string: None, - }, + *over.instance = Image { + data, + width: over.instance.width, + height: over.instance.height, + base64_string: None, }; } @@ -738,11 +736,11 @@ impl Adjust

for ImageFrameTable

where P: dyn_any::StaticType, P::Static: Pixel, - GraphicElement: From>, + GraphicElement: From>, { fn adjust(&mut self, map_fn: impl Fn(&P) -> P) { for instance in self.instances_mut() { - for c in instance.instance.image.data.iter_mut() { + for c in instance.instance.data.iter_mut() { *c = map_fn(c); } } @@ -1386,7 +1384,7 @@ impl MultiplyAlpha for ImageFrameTable

where P: dyn_any::StaticType, P::Static: Pixel, - GraphicElement: From>, + GraphicElement: From>, { fn multiply_alpha(&mut self, factor: f64) { for instance in self.instances_mut() { @@ -1539,13 +1537,13 @@ fn color_overlay>( // #[cfg(feature = "alloc")] // mod index_node { -// use crate::raster::{Color, ImageFrame}; +// use crate::raster::{Color, Image}; // use crate::Ctx; // #[node_macro::node(category(""))] // pub fn index( // _: impl Ctx, -// #[implementations(Vec>, Vec)] +// #[implementations(Vec>, Vec)] // #[widget(ParsedWidgetOverride::Hidden)] // input: Vec, // index: u32, @@ -1561,8 +1559,8 @@ fn color_overlay>( #[cfg(test)] mod test { - use crate::raster::image::{ImageFrame, ImageFrameTable}; - use crate::raster::{BlendMode, Image}; + use crate::raster::adjustments::BlendMode; + use crate::raster::image::{Image, ImageFrameTable}; use crate::{Color, Node}; use std::pin::Pin; @@ -1580,7 +1578,7 @@ mod test { #[tokio::test] async fn color_overlay_multiply() { let image_color = Color::from_rgbaf32_unchecked(0.7, 0.6, 0.5, 0.4); - let image = ImageFrame { image: Image::new(1, 1, image_color) }; + let image = Image::new(1, 1, image_color); // Color { red: 0., green: 1., blue: 0., alpha: 1. } let overlay_color = Color::GREEN; @@ -1592,6 +1590,6 @@ mod test { let result = result.one_instance().instance; // The output should just be the original green and alpha channels (as we multiply them by 1 and other channels by 0) - assert_eq!(result.image.data[0], Color::from_rgbaf32_unchecked(0., image_color.g(), 0., image_color.a())); + assert_eq!(result.data[0], Color::from_rgbaf32_unchecked(0., image_color.g(), 0., image_color.a())); } } diff --git a/node-graph/gcore/src/raster/brush_cache.rs b/node-graph/gcore/src/raster/brush_cache.rs index f4b08324..c00b8a39 100644 --- a/node-graph/gcore/src/raster/brush_cache.rs +++ b/node-graph/gcore/src/raster/brush_cache.rs @@ -32,7 +32,7 @@ struct BrushCacheImpl { impl BrushCacheImpl { fn compute_brush_plan(&mut self, mut background: ImageFrameTable, input: &[BrushStroke]) -> BrushPlan { // Do background invalidation. - if background.one_instance().instance.image != self.background.one_instance().instance.image { + if background.one_instance().instance != self.background.one_instance().instance { self.background = background.clone(); return BrushPlan { strokes: input.to_vec(), diff --git a/node-graph/gcore/src/raster/image.rs b/node-graph/gcore/src/raster/image.rs index 34eb5148..4a08f305 100644 --- a/node-graph/gcore/src/raster/image.rs +++ b/node-graph/gcore/src/raster/image.rs @@ -53,6 +53,8 @@ pub struct Image { /// to an svg string. This is used as a cache in order to not have to encode the data on every graph evaluation. #[cfg_attr(feature = "serde", serde(skip))] pub base64_string: Option, + // TODO: Add an `origin` field to store where in the local space the image is anchored. + // TODO: Currently it is always anchored at the top left corner at (0, 0). The bottom right corner of the new origin field would correspond to (1, 1). } impl Debug for Image

{ @@ -66,8 +68,9 @@ impl Debug for Image

{ } } -unsafe impl StaticType for Image

+unsafe impl

StaticType for Image

where + P: dyn_any::StaticTypeSized + Pixel, P::Static: Pixel, { type Static = Image; @@ -212,6 +215,34 @@ impl IntoIterator for Image

{ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result, D::Error> { use serde::Deserialize; + #[derive(Clone, Default, Debug, PartialEq, specta::Type)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + pub struct ImageFrame { + pub image: Image

, + } + impl From> for GraphicElement { + fn from(image_frame: ImageFrame) -> Self { + GraphicElement::RasterFrame(crate::RasterFrame::ImageFrame(ImageFrameTable::new(image_frame.image))) + } + } + impl From for ImageFrame { + fn from(element: GraphicElement) -> Self { + match element { + GraphicElement::RasterFrame(crate::RasterFrame::ImageFrame(image)) => Self { + image: image.one_instance().instance.clone(), + }, + _ => panic!("Expected Image, found {:?}", element), + } + } + } + unsafe impl

StaticType for ImageFrame

+ where + P: dyn_any::StaticTypeSized + Pixel, + P::Static: Pixel, + { + type Static = ImageFrame; + } + #[derive(Clone, Default, Debug, PartialEq, specta::Type)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct OldImageFrame { @@ -222,60 +253,58 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) -> #[derive(serde::Serialize, serde::Deserialize)] #[serde(untagged)] - enum EitherFormat { - ImageFrame(ImageFrame), + enum FormatVersions { + Image(Image), OldImageFrame(OldImageFrame), + ImageFrame(Instances>), ImageFrameTable(ImageFrameTable), } - Ok(match EitherFormat::deserialize(deserializer)? { - EitherFormat::ImageFrame(image_frame) => ImageFrameTable::::new(image_frame), - EitherFormat::OldImageFrame(image_frame_with_transform_and_blending) => { + Ok(match FormatVersions::deserialize(deserializer)? { + FormatVersions::Image(image) => ImageFrameTable::new(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 = ImageFrameTable::new(ImageFrame { image }); + let mut image_frame_table = ImageFrameTable::new(image); *image_frame_table.one_instance_mut().transform = transform; *image_frame_table.one_instance_mut().alpha_blending = alpha_blending; image_frame_table } - EitherFormat::ImageFrameTable(image_frame_table) => image_frame_table, + FormatVersions::ImageFrame(image_frame) => ImageFrameTable::new(image_frame.one_instance().instance.image.clone()), + FormatVersions::ImageFrameTable(image_frame_table) => image_frame_table, }) } -pub type ImageFrameTable

= Instances>; +// TODO: Rename to ImageTable +pub type ImageFrameTable

= Instances>; /// Construct a 0x0 image frame table. This is useful because ImageFrameTable::default() will return a 1x1 image frame table. impl ImageFrameTable { pub fn empty() -> Self { - let mut result = Self::new(ImageFrame::default()); + let mut result = Self::new(Image::default()); *result.transform_mut() = DAffine2::ZERO; result } } -#[derive(Clone, Default, Debug, PartialEq, specta::Type)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ImageFrame { - pub image: Image

, -} - -impl Sample for ImageFrame

{ +impl Sample for Image

{ type Pixel = P; // TODO: Improve sampling logic #[inline(always)] fn sample(&self, pos: DVec2, _area: DVec2) -> Option { - let image_size = DVec2::new(self.image.width() as f64, self.image.height() as f64); + let image_size = DVec2::new(self.width() as f64, self.height() as f64); if pos.x < 0. || pos.y < 0. || pos.x >= image_size.x || pos.y >= image_size.y { return None; } - self.image.get_pixel(pos.x as u32, pos.y as u32) + self.get_pixel(pos.x as u32, pos.y as u32) } } -impl Sample for ImageFrameTable

+impl

Sample for ImageFrameTable

where - GraphicElement: From>, + P: Debug + Copy + Pixel + dyn_any::StaticType, P::Static: Pixel, + GraphicElement: From>, { type Pixel = P; @@ -292,26 +321,11 @@ where } } -impl Bitmap for ImageFrame

{ - type Pixel = P; - - fn width(&self) -> u32 { - self.image.width() - } - - fn height(&self) -> u32 { - self.image.height() - } - - fn get_pixel(&self, x: u32, y: u32) -> Option { - self.image.get_pixel(x, y) - } -} - -impl Bitmap for ImageFrameTable

+impl

Bitmap for ImageFrameTable

where + P: Copy + Pixel + dyn_any::StaticType, P::Static: Pixel, - GraphicElement: From>, + GraphicElement: From>, { type Pixel = P; @@ -334,95 +348,57 @@ where } } -impl BitmapMut for ImageFrame

{ +impl

BitmapMut for ImageFrameTable

+where + P: Copy + Pixel + dyn_any::StaticType, + P::Static: Pixel, + GraphicElement: From>, +{ fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> { - self.image.get_pixel_mut(x, y) + self.one_instance_mut().instance.get_pixel_mut(x, y) } } -impl BitmapMut for ImageFrameTable

-where - GraphicElement: From>, - P::Static: Pixel, -{ - fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> { - let image = self.one_instance_mut().instance; - - BitmapMut::get_pixel_mut(image, x, y) - } -} - -unsafe impl StaticType for ImageFrame

-where - P::Static: Pixel, -{ - type Static = ImageFrame; -} - -impl ImageFrame

{ +impl Image

{ pub fn get_mut(&mut self, x: usize, y: usize) -> &mut P { - &mut self.image.data[y * (self.image.width as usize) + x] + &mut self.data[y * (self.width as usize) + x] } /// Clamps the provided point to ((0, 0), (ImageSize.x, ImageSize.y)) and returns the closest pixel pub fn sample(&self, position: DVec2) -> P { - let x = position.x.clamp(0., self.image.width as f64 - 1.) as usize; - let y = position.y.clamp(0., self.image.height as f64 - 1.) as usize; + let x = position.x.clamp(0., self.width as f64 - 1.) as usize; + let y = position.y.clamp(0., self.height as f64 - 1.) as usize; - self.image.data[x + y * self.image.width as usize] + self.data[x + y * self.width as usize] } } -impl AsRef> for ImageFrame

{ - fn as_ref(&self) -> &ImageFrame

{ +impl AsRef> for Image

{ + fn as_ref(&self) -> &Image

{ self } } -impl Hash for ImageFrame

{ - fn hash(&self, state: &mut H) { - 0.hash(state); - self.image.hash(state); - } -} - -/* This does not work because of missing specialization - * so we have to manually implement this for now -impl + Pixel, P: Pixel> From> for Image

{ - fn from(image: Image) -> Self { +impl From> for Image { + fn from(image: Image) -> Self { let data = image.data.into_iter().map(|x| x.into()).collect(); Self { data, width: image.width, height: image.height, - } - } -}*/ - -impl From> for ImageFrame { - fn from(image: ImageFrame) -> Self { - let data = image.image.data.into_iter().map(|x| x.into()).collect(); - Self { - image: Image { - data, - width: image.image.width, - height: image.image.height, - base64_string: None, - }, + base64_string: None, } } } -impl From> for ImageFrame { - fn from(image: ImageFrame) -> Self { - let data = image.image.data.into_iter().map(|x| x.into()).collect(); +impl From> for Image { + fn from(image: Image) -> Self { + let data = image.data.into_iter().map(|x| x.into()).collect(); Self { - image: Image { - data, - width: image.image.width, - height: image.image.height, - base64_string: None, - }, + data, + width: image.width, + height: image.height, + base64_string: None, } } } diff --git a/node-graph/gcore/src/types.rs b/node-graph/gcore/src/types.rs index 86a034cf..a71dcd44 100644 --- a/node-graph/gcore/src/types.rs +++ b/node-graph/gcore/src/types.rs @@ -150,9 +150,14 @@ fn migrate_type_descriptor_names<'de, D: serde::Deserializer<'de>>(deserializer: let name = match name.as_str() { "f32" => "f64".to_string(), "graphene_core::transform::Footprint" => "core::option::Option>".to_string(), - "graphene_core::graphic_element::GraphicGroup" => "graphene_core::graphic_element::Instances".to_string(), - "graphene_core::vector::vector_data::VectorData" => "graphene_core::graphic_element::Instances".to_string(), - "graphene_core::raster::image::ImageFrame" => "graphene_core::graphic_element::Instances>".to_string(), + "graphene_core::graphic_element::GraphicGroup" => "graphene_core::instances::Instances".to_string(), + "graphene_core::vector::vector_data::VectorData" => "graphene_core::instances::Instances".to_string(), + "graphene_core::raster::image::ImageFrame" + | "graphene_core::raster::image::ImageFrame" + | "graphene_core::instances::Instances>" + | "graphene_core::instances::Instances>" => { + "graphene_core::instances::Instances>".to_string() + } _ => name, }; diff --git a/node-graph/gstd/src/brush.rs b/node-graph/gstd/src/brush.rs index 91981e45..fa9a9e6b 100644 --- a/node-graph/gstd/src/brush.rs +++ b/node-graph/gstd/src/brush.rs @@ -5,8 +5,8 @@ use graph_craft::proto::FutureWrapperNode; 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::{ImageFrame, ImageFrameTable}; -use graphene_core::raster::{Alpha, Bitmap, BlendMode, Color, Image, Pixel, Sample}; +use graphene_core::raster::image::{Image, ImageFrameTable}; +use graphene_core::raster::{Alpha, Bitmap, BlendMode, Color, Pixel, Sample}; use graphene_core::transform::{Transform, TransformMut}; use graphene_core::value::{ClonedNode, CopiedNode, ValueNode}; use graphene_core::vector::brush_stroke::{BrushStroke, BrushStyle}; @@ -93,14 +93,14 @@ where P: Pixel + Alpha + std::fmt::Debug + dyn_any::StaticType, P::Static: Pixel, BlendFn: for<'any_input> Node<'any_input, (P, P), Output = P>, - GraphicElement: From>, + GraphicElement: From>, { if positions.is_empty() { return target; } - let target_width = target.one_instance().instance.image.width; - let target_height = target.one_instance().instance.image.height; + let target_width = target.one_instance().instance.width; + let target_height = target.one_instance().instance.height; let target_size = DVec2::new(target_width as f64, target_height as f64); let texture_size = DVec2::new(texture.width as f64, texture.height as f64); @@ -125,12 +125,12 @@ where let max_y = (blit_area_offset.y + blit_area_dimensions.y).saturating_sub(1); let max_x = (blit_area_offset.x + blit_area_dimensions.x).saturating_sub(1); assert!(texture_index(max_x, max_y) < texture.data.len()); - assert!(target_index(max_x, max_y) < target.one_instance().instance.image.data.len()); + assert!(target_index(max_x, max_y) < target.one_instance().instance.data.len()); 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.one_instance_mut().instance.image.data[target_index(x + clamp_start.x, y + clamp_start.y)]; + let dst_pixel = &mut target.one_instance_mut().instance.data[target_index(x + clamp_start.x, y + clamp_start.y)]; *dst_pixel = blend_mode.eval((src_pixel, *dst_pixel)); } } @@ -146,7 +146,7 @@ pub async fn create_brush_texture(brush_style: &BrushStyle) -> Image { let blank_texture = empty_image((), transform, Color::TRANSPARENT); let image = crate::raster::blend_image_closure(stamp, blank_texture, |a, b| blend_colors(a, b, BlendMode::Normal, 1.)); - image.one_instance().instance.image.clone() + image.one_instance().instance.clone() } macro_rules! inline_blend_funcs { @@ -286,9 +286,7 @@ async fn brush(_: impl Ctx, image_frame_table: ImageFrameTable, bounds: I let has_erase_strokes = strokes.iter().any(|s| s.style.blend_mode == BlendMode::Erase); if has_erase_strokes { - let opaque_image = ImageFrame { - image: Image::new(bbox.size().x as u32, bbox.size().y as u32, Color::WHITE), - }; + let opaque_image = Image::new(bbox.size().x as u32, bbox.size().y as u32, Color::WHITE); let mut erase_restore_mask = ImageFrameTable::new(opaque_image); *erase_restore_mask.transform_mut() = background_bounds; *erase_restore_mask.one_instance_mut().alpha_blending = Default::default(); diff --git a/node-graph/gstd/src/dehaze.rs b/node-graph/gstd/src/dehaze.rs index 6b1d9c58..eca6f901 100644 --- a/node-graph/gstd/src/dehaze.rs +++ b/node-graph/gstd/src/dehaze.rs @@ -1,6 +1,5 @@ use graph_craft::proto::types::Percentage; -use graphene_core::raster::image::{ImageFrame, ImageFrameTable}; -use graphene_core::raster::Image; +use graphene_core::raster::image::{Image, ImageFrameTable}; use graphene_core::transform::{Transform, TransformMut}; use graphene_core::{Color, Ctx}; @@ -13,10 +12,9 @@ async fn dehaze(_: impl Ctx, image_frame: ImageFrameTable, strength: Perc let image_frame_transform = image_frame.transform(); let image_frame_alpha_blending = image_frame.one_instance().alpha_blending; - let image_frame = image_frame.one_instance().instance; + let image = image_frame.one_instance().instance; // Prepare the image data for processing - let image = &image_frame.image; let image_data = bytemuck::cast_vec(image.data.clone()); let image_buffer = image::Rgba32FImage::from_raw(image.width, image.height, image_data).expect("Failed to convert internal image format into image-rs data type."); let dynamic_image: image::DynamicImage = image_buffer.into(); @@ -34,7 +32,7 @@ async fn dehaze(_: impl Ctx, image_frame: ImageFrameTable, strength: Perc base64_string: None, }; - let mut result = ImageFrameTable::new(ImageFrame { image: dehazed_image }); + let mut result = ImageFrameTable::new(dehazed_image); *result.transform_mut() = image_frame_transform; *result.one_instance_mut().alpha_blending = *image_frame_alpha_blending; diff --git a/node-graph/gstd/src/gpu_nodes.rs b/node-graph/gstd/src/gpu_nodes.rs index 5b4a4468..a89f6448 100644 --- a/node-graph/gstd/src/gpu_nodes.rs +++ b/node-graph/gstd/src/gpu_nodes.rs @@ -4,8 +4,8 @@ use graph_craft::document::value::TaggedValue; use graph_craft::document::*; use graph_craft::proto::*; use graphene_core::application_io::ApplicationIo; -use graphene_core::raster::image::{ImageFrame, ImageFrameTable}; -use graphene_core::raster::{BlendMode, Image, Pixel}; +use graphene_core::raster::image::{Image, ImageFrameTable}; +use graphene_core::raster::{BlendMode, Pixel}; use graphene_core::transform::Transform; use graphene_core::transform::TransformMut; use graphene_core::*; @@ -72,9 +72,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable, node: DocumentNode, 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.image.width, image.image.height, bytemuck::cast_vec(image.image.data.clone())) - .unwrap() - .into(); + 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") { @@ -94,7 +92,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable, node: DocumentNode, .create_compute_pass( &compute_pass_descriptor.pipeline_layout, compute_pass_descriptor.readback_buffer.clone(), - ComputePassDimensions::XY(image.image.width / 12 + 1, image.image.height / 8 + 1), + ComputePassDimensions::XY(image.width / 12 + 1, image.height / 8 + 1), ) .unwrap(); executor.execute_compute_pipeline(compute_pass).unwrap(); @@ -105,7 +103,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable, node: DocumentNode, log::debug!("first color: {:?}", colors[0]); #[cfg(feature = "image-compare")] - let img2: image::DynamicImage = image::Rgba32FImage::from_raw(image.image.width, image.image.height, bytemuck::cast_vec(colors.clone())).unwrap().into(); + 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")] @@ -113,11 +111,11 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable, node: DocumentNode, let new_image = Image { data: colors, - width: image.image.width, - height: image.image.height, + width: image.width, + height: image.height, ..Default::default() }; - let mut result = ImageFrameTable::new(ImageFrame { image: new_image }); + let mut result = ImageFrameTable::new(new_image); *result.transform_mut() = image_frame_table.transform(); *result.one_instance_mut().alpha_blending = *image_frame_table.one_instance().alpha_blending; @@ -136,7 +134,7 @@ impl MapGpuNode { async fn create_compute_pass_descriptor(node: DocumentNode, image: &ImageFrameTable, executor: &&WgpuExecutor) -> Result where - GraphicElement: From>, + GraphicElement: From>, T::Static: Pixel, { let image = image.one_instance().instance; @@ -215,11 +213,11 @@ where .await .unwrap(); - let len: usize = image.image.data.len(); + let len: usize = image.data.len(); let storage_buffer = executor .create_storage_buffer( - image.image.data.clone(), + image.data.clone(), StorageBufferOptions { cpu_writable: false, gpu_writable: true, @@ -234,7 +232,7 @@ where // let surface = unsafe { executor.create_surface(canvas) }.unwrap(); // let surface_id = surface.surface_id; - // let texture = executor.create_texture_buffer(image.image.clone(), TextureBufferOptions::Texture).unwrap(); + // let texture = executor.create_texture_buffer(image.clone(), TextureBufferOptions::Texture).unwrap(); // // executor.create_render_pass(texture, surface).unwrap(); @@ -245,7 +243,7 @@ where // return frame; log::debug!("creating buffer"); - let width_uniform = executor.create_uniform_buffer(image.image.width).unwrap(); + 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(); @@ -289,8 +287,8 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable, backgr let foreground = foreground.one_instance().instance; let background = background.one_instance().instance; - let foreground_size = DVec2::new(foreground.image.width as f64, foreground.image.height as f64); - let background_size = DVec2::new(background.image.width as f64, background.image.height as f64); + 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); @@ -371,16 +369,16 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable, backgr ) .await .unwrap(); - let len = background.image.data.len(); + 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.image.width).unwrap(); + let width_uniform = executor.create_uniform_buffer(background.width).unwrap(); let bg_storage_buffer = executor .create_storage_buffer( - background.image.data.clone(), + background.data.clone(), StorageBufferOptions { cpu_writable: false, gpu_writable: true, @@ -391,7 +389,7 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable, backgr .unwrap(); let fg_storage_buffer = executor .create_storage_buffer( - foreground.image.data.clone(), + foreground.data.clone(), StorageBufferOptions { cpu_writable: false, gpu_writable: true, @@ -400,7 +398,7 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable, backgr }, ) .unwrap(); - let fg_width_uniform = executor.create_uniform_buffer(foreground.image.width).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); @@ -442,7 +440,7 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable, backgr }; log::debug!("created pipeline"); let compute_pass = executor - .create_compute_pass(&pipeline, Some(readback_buffer.clone()), ComputePassDimensions::XY(background.image.width, background.image.height)) + .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"); @@ -452,12 +450,12 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable, backgr let created_image = Image { data: colors, - width: background.image.width, - height: background.image.height, + width: background.width, + height: background.height, ..Default::default() }; - let mut result = ImageFrameTable::new(ImageFrame { image: created_image }); + let mut result = ImageFrameTable::new(created_image); *result.transform_mut() = background_transform; *result.one_instance_mut().alpha_blending = *background_alpha_blending; diff --git a/node-graph/gstd/src/image_color_palette.rs b/node-graph/gstd/src/image_color_palette.rs index 955d5123..9dac3e3b 100644 --- a/node-graph/gstd/src/image_color_palette.rs +++ b/node-graph/gstd/src/image_color_palette.rs @@ -18,7 +18,7 @@ async fn image_color_palette( let image = image.one_instance().instance; - for pixel in image.image.data.iter() { + for pixel in image.data.iter() { let r = pixel.r() * GRID; let g = pixel.g() * GRID; let b = pixel.b() * GRID; @@ -65,20 +65,17 @@ async fn image_color_palette( mod test { use super::*; - use graphene_core::raster::image::{ImageFrame, ImageFrameTable}; - use graphene_core::raster::Image; + use graphene_core::raster::image::{Image, ImageFrameTable}; #[test] fn test_image_color_palette() { let result = image_color_palette( (), - ImageFrameTable::new(ImageFrame { - image: Image { - width: 100, - height: 100, - data: vec![Color::from_rgbaf32(0., 0., 0., 1.).unwrap(); 10000], - base64_string: None, - }, + ImageFrameTable::new(Image { + width: 100, + height: 100, + data: vec![Color::from_rgbaf32(0., 0., 0., 1.).unwrap(); 10000], + base64_string: None, }), 1, ); diff --git a/node-graph/gstd/src/raster.rs b/node-graph/gstd/src/raster.rs index cb629124..ec04071a 100644 --- a/node-graph/gstd/src/raster.rs +++ b/node-graph/gstd/src/raster.rs @@ -1,9 +1,8 @@ use dyn_any::DynAny; use graphene_core::raster::bbox::Bbox; -use graphene_core::raster::image::{ImageFrame, ImageFrameTable}; +use graphene_core::raster::image::{Image, ImageFrameTable}; use graphene_core::raster::{ - Alpha, AlphaMut, Bitmap, BitmapMut, CellularDistanceFunction, CellularReturnType, DomainWarpType, FractalType, Image, Linear, LinearChannel, Luminance, NoiseType, Pixel, RGBMut, RedGreenBlue, - Sample, + Alpha, AlphaMut, Bitmap, BitmapMut, CellularDistanceFunction, CellularReturnType, DomainWarpType, FractalType, Linear, LinearChannel, Luminance, NoiseType, Pixel, RGBMut, RedGreenBlue, Sample, }; use graphene_core::transform::{Transform, TransformMut}; use graphene_core::{AlphaBlending, Color, Ctx, ExtractFootprint, GraphicElement, Node}; @@ -33,10 +32,9 @@ fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: ImageFra let image_frame_transform = image_frame.transform(); let image_frame_alpha_blending = image_frame.one_instance().alpha_blending; - let image_frame = image_frame.one_instance().instance; + let image = image_frame.one_instance().instance; // Resize the image using the image crate - let image = &image_frame.image; let data = bytemuck::cast_vec(image.data.clone()); let footprint = ctx.footprint(); @@ -86,7 +84,7 @@ fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: ImageFra let new_transform = image_frame_transform * DAffine2::from_translation(offset) * DAffine2::from_scale(size); - let mut result = ImageFrameTable::new(ImageFrame { image }); + let mut result = ImageFrameTable::new(image); *result.transform_mut() = new_transform; *result.one_instance_mut().alpha_blending = *image_frame_alpha_blending; @@ -263,7 +261,7 @@ where _P::Static: Pixel, MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'n + Clone, _Fg: Sample + Transform + Clone + Send + 'n, - GraphicElement: From>, + GraphicElement: From>, { let (background, foreground) = images; @@ -330,11 +328,11 @@ fn extend_image_to_bounds(image: ImageFrameTable, bounds: DAffine2) -> Im } let image_instance = image.one_instance().instance; - if image_instance.image.width == 0 || image_instance.image.height == 0 { + if image_instance.width == 0 || image_instance.height == 0 { return empty_image((), bounds, Color::TRANSPARENT); } - let orig_image_scale = DVec2::new(image_instance.image.width as f64, image_instance.image.height as f64); + let orig_image_scale = DVec2::new(image_instance.width as f64, image_instance.height as f64); let layer_to_image_space = DAffine2::from_scale(orig_image_scale) * image.transform().inverse(); let bounds_in_image_space = Bbox::unit().affine_transform(layer_to_image_space * bounds).to_axis_aligned_bbox(); @@ -345,11 +343,11 @@ fn extend_image_to_bounds(image: ImageFrameTable, bounds: DAffine2) -> Im // Copy over original image into enlarged image. let mut new_img = Image::new(new_scale.x as u32, new_scale.y as u32, Color::TRANSPARENT); let offset_in_new_image = (-new_start).as_uvec2(); - for y in 0..image_instance.image.height { - let old_start = y * image_instance.image.width; + for y in 0..image_instance.height { + let old_start = y * image_instance.width; let new_start = (y + offset_in_new_image.y) * new_img.width + offset_in_new_image.x; - let old_row = &image_instance.image.data[old_start as usize..(old_start + image_instance.image.width) as usize]; - let new_row = &mut new_img.data[new_start as usize..(new_start + image_instance.image.width) as usize]; + let old_row = &image_instance.data[old_start as usize..(old_start + image_instance.width) as usize]; + let new_row = &mut new_img.data[new_start as usize..(new_start + image_instance.width) as usize]; new_row.copy_from_slice(old_row); } @@ -357,7 +355,7 @@ fn extend_image_to_bounds(image: ImageFrameTable, bounds: DAffine2) -> Im // 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.transform() * DAffine2::from_scale(1. / orig_image_scale) * DAffine2::from_translation(new_start) * DAffine2::from_scale(new_scale); - let mut result = ImageFrameTable::new(ImageFrame { image: new_img }); + let mut result = ImageFrameTable::new(new_img); *result.transform_mut() = new_texture_to_layer_space; *result.one_instance_mut().alpha_blending = *image.one_instance().alpha_blending; @@ -371,7 +369,7 @@ fn empty_image(_: impl Ctx, transform: DAffine2, color: Color) -> ImageFrameTabl let image = Image::new(width, height, color); - let mut result = ImageFrameTable::new(ImageFrame { image }); + let mut result = ImageFrameTable::new(image); *result.transform_mut() = transform; *result.one_instance_mut().alpha_blending = AlphaBlending::default(); @@ -559,7 +557,7 @@ fn noise_pattern( } } - let mut result = ImageFrameTable::new(ImageFrame { image }); + let mut result = ImageFrameTable::new(image); *result.transform_mut() = DAffine2::from_translation(offset) * DAffine2::from_scale(size); *result.one_instance_mut().alpha_blending = AlphaBlending::default(); @@ -621,7 +619,7 @@ fn noise_pattern( } } - let mut result = ImageFrameTable::new(ImageFrame { image }); + let mut result = ImageFrameTable::new(image); *result.transform_mut() = DAffine2::from_translation(offset) * DAffine2::from_scale(size); *result.one_instance_mut().alpha_blending = AlphaBlending::default(); @@ -669,7 +667,7 @@ fn mandelbrot(ctx: impl ExtractFootprint + Send) -> ImageFrameTable { data, ..Default::default() }; - let mut result = ImageFrameTable::new(ImageFrame { image }); + let mut result = ImageFrameTable::new(image); *result.transform_mut() = DAffine2::from_translation(offset) * DAffine2::from_scale(size); *result.one_instance_mut().alpha_blending = Default::default(); diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index f3e6a507..1b1caecb 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -6,8 +6,7 @@ use graphene_core::application_io::SurfaceHandle; use graphene_core::application_io::{ApplicationIo, ExportFormat, RenderConfig}; #[cfg(target_arch = "wasm32")] use graphene_core::raster::bbox::Bbox; -use graphene_core::raster::image::{ImageFrame, ImageFrameTable}; -use graphene_core::raster::Image; +use graphene_core::raster::image::{Image, ImageFrameTable}; use graphene_core::renderer::RenderMetadata; use graphene_core::renderer::{format_transform_matrix, GraphicElementRendered, ImageRenderMode, RenderParams, RenderSvgSegmentList, SvgRender}; use graphene_core::transform::Footprint; @@ -81,13 +80,11 @@ fn decode_image(_: impl Ctx, data: Arc<[u8]>) -> ImageFrameTable { return ImageFrameTable::empty(); }; let image = image.to_rgba32f(); - let image = ImageFrame { - image: Image { - data: image.chunks(4).map(|pixel| Color::from_unassociated_alpha(pixel[0], pixel[1], pixel[2], pixel[3])).collect(), - width: image.width(), - height: image.height(), - ..Default::default() - }, + let image = Image { + data: image.chunks(4).map(|pixel| Color::from_unassociated_alpha(pixel[0], pixel[1], pixel[2], pixel[3])).collect(), + width: image.width(), + height: image.height(), + ..Default::default() }; ImageFrameTable::new(image) @@ -204,9 +201,7 @@ async fn rasterize HashMap, input: VectorDataTable, params: []), async_node!(graphene_core::ops::IntoNode, input: ImageFrameTable, params: []), async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => ImageFrameTable]), - async_node!(graphene_core::memo::MonitorNode<_, _, _>, input: Context, fn_params: [Context => TextureFrame]), + 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]), @@ -268,7 +268,7 @@ fn node_registry() -> HashMap, input: Context, fn_params: [Context => ShaderInputFrame]), async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => WgpuSurface]), async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => Option]), - async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => TextureFrame]), + async_node!(graphene_core::memo::ImpureMemoNode<_, _, _>, input: Context, fn_params: [Context => ImageTexture]), ]; let mut map: HashMap> = HashMap::new(); for (id, entry) in graphene_core::registry::NODE_REGISTRY.lock().unwrap().iter() { diff --git a/node-graph/wgpu-executor/src/lib.rs b/node-graph/wgpu-executor/src/lib.rs index 41be958a..1f62cdf6 100644 --- a/node-graph/wgpu-executor/src/lib.rs +++ b/node-graph/wgpu-executor/src/lib.rs @@ -6,7 +6,7 @@ pub use executor::GpuExecutor; use dyn_any::{DynAny, StaticType}; use gpu_executor::{ComputePassDimensions, GPUConstant, StorageBufferOptions, TextureBufferOptions, TextureBufferType, ToStorageBuffer, ToUniformBuffer}; -use graphene_core::application_io::{ApplicationIo, EditorApi, SurfaceHandle, TextureFrame}; +use graphene_core::application_io::{ApplicationIo, EditorApi, ImageTexture, SurfaceHandle}; use graphene_core::raster::image::ImageFrameTable; use graphene_core::raster::{Image, SRGBA8}; use graphene_core::transform::{Footprint, Transform}; @@ -913,14 +913,14 @@ async fn render_texture<'a: 'n>( } #[node_macro::node(category(""))] -async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: ImageFrameTable, executor: &'a WgpuExecutor) -> TextureFrame { +async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: ImageFrameTable, executor: &'a WgpuExecutor) -> ImageTexture { // let new_data: Vec = input.image.data.into_iter().map(|c| c.into()).collect(); let input = input.one_instance().instance; - let new_data: Vec = input.image.data.iter().map(|x| (*x).into()).collect(); + let new_data: Vec = input.data.iter().map(|x| (*x).into()).collect(); let new_image = Image { - width: input.image.width, - height: input.image.height, + width: input.width, + height: input.height, data: new_data, base64_string: None, }; @@ -932,9 +932,9 @@ async fn upload_texture<'a: 'n>(_: impl ExtractFootprint + Ctx, input: ImageFram _ => unreachable!("Unsupported ShaderInput type"), }; - TextureFrame { + ImageTexture { texture: texture.into(), - // TODO: Find an alternate way to encode the transform and alpha_blend now that these fields have been moved up out of TextureFrame + // TODO: Find an alternate way to encode the transform and alpha_blend now that these fields have been moved up out of ImageTexture // transform: input.transform, // alpha_blend: Default::default(), }