Instance tables refactor part 2: move the transform and alpha_blending fields up a level (#2249)

* Fix domain data structure field plural naming

* Rename method one_item to one_instance

Rename method one_item to one_instance

* Move the Instance<T> methods over to providing an Instance<T>/InstanceMut<T>

Move the Instance<T> methods over to providing an Instance<T>/InstanceMut<T>

* Add transform and alpha_blending fields to Instances<T>

* Finish the refactor (Brush tool is broken though)

* Add test for brush node

* Fix brush node

* Fix default empty images being 1x1 instead of 0x0 as they should be

* Fix tests

* Fix path transform

* Add correct upgrading to move the transform/blending up a level

---------

Co-authored-by: hypercube <0hypercube@gmail.com>
This commit is contained in:
Keavon Chambers
2025-03-02 01:26:36 -08:00
parent 4ff2bdb04f
commit f1160e1ca6
33 changed files with 1099 additions and 984 deletions

View File

@@ -6,6 +6,8 @@ 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::transform::Transform;
use graphene_core::transform::TransformMut;
use graphene_core::*;
use wgpu_executor::{Bindgroup, PipelineLayout, Shader, ShaderIO, ShaderInput, WgpuExecutor, WgpuShaderInput};
@@ -64,7 +66,7 @@ impl Clone for ComputePass {
#[node_macro::old_node_impl(MapGpuNode)]
async fn map_gpu<'a: 'input>(image: ImageFrameTable<Color>, node: DocumentNode, editor_api: &'a graphene_core::application_io::EditorApi<WasmApplicationIo>) -> ImageFrameTable<Color> {
let image_frame_table = &image;
let image = image.one_item();
let image = image.one_instance().instance;
log::debug!("Executing gpu node");
let executor = &editor_api.application_io.as_ref().and_then(|io| io.gpu_executor()).unwrap();
@@ -81,7 +83,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable<Color>, node: DocumentNode,
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 ImageFrameTable::default();
return ImageFrameTable::empty();
};
self.cache.lock().as_mut().unwrap().insert(name, compute_pass_descriptor.clone());
log::error!("created compute pass");
@@ -109,18 +111,17 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable<Color>, node: DocumentNode,
#[cfg(feature = "image-compare")]
log::debug!("score: {:?}", score.score);
let result = ImageFrame {
image: Image {
data: colors,
width: image.image.width,
height: image.image.height,
..Default::default()
},
transform: image.transform,
alpha_blending: image.alpha_blending,
let new_image = Image {
data: colors,
width: image.image.width,
height: image.image.height,
..Default::default()
};
let mut result = ImageFrameTable::new(ImageFrame { image: new_image });
*result.transform_mut() = image_frame_table.transform();
*result.one_instance_mut().alpha_blending = *image_frame_table.one_instance().alpha_blending;
ImageFrameTable::new(result)
result
}
impl<Node, EditorApi> MapGpuNode<Node, EditorApi> {
@@ -138,7 +139,7 @@ where
GraphicElement: From<ImageFrame<T>>,
T::Static: Pixel,
{
let image = image.one_item();
let image = image.one_instance().instance;
let compiler = graph_craft::graphene_compiler::Compiler {};
let inner_network = NodeNetwork::value_network(node);
@@ -280,14 +281,19 @@ where
#[node_macro::node(category("Debug: GPU"))]
async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, background: ImageFrameTable<Color>, blend_mode: BlendMode, opacity: f64) -> ImageFrameTable<Color> {
let foreground = foreground.one_item();
let background = background.one_item();
let foreground_transform = foreground.transform();
let background_transform = background.transform();
let background_alpha_blending = background.one_instance().alpha_blending;
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);
// 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 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();
@@ -334,7 +340,7 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
let proto_networks: Result<Vec<_>, _> = compiler.compile(network.clone()).collect();
let Ok(proto_networks_result) = proto_networks else {
log::error!("Error compiling network in 'blend_gpu_image()");
return ImageFrameTable::default();
return ImageFrameTable::empty();
};
let proto_networks = proto_networks_result;
log::debug!("compiling shader");
@@ -444,16 +450,16 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
let result = executor.read_output_buffer(readback_buffer).await.unwrap();
let colors = bytemuck::pod_collect_to_vec::<u8, Color>(result.as_slice());
let result = ImageFrame {
image: Image {
data: colors,
width: background.image.width,
height: background.image.height,
..Default::default()
},
transform: background.transform,
alpha_blending: background.alpha_blending,
let created_image = Image {
data: colors,
width: background.image.width,
height: background.image.height,
..Default::default()
};
ImageFrameTable::new(result)
let mut result = ImageFrameTable::new(ImageFrame { image: created_image });
*result.transform_mut() = background_transform;
*result.one_instance_mut().alpha_blending = *background_alpha_blending;
result
}