Improve instancing nodes (make them output group data, add 'Instance Repeat', fix Flatten Vector Elements click targets, and more) (#2610)

* Improve instancing nodes (make them output group data, add 'Instance Repeat', fix Flatten Vector Elements click targets, and more)

* Fix test?

* Fix more tests?

* Fix moar test??

* Clean up instance method naming
This commit is contained in:
Keavon Chambers 2025-04-22 17:55:57 -07:00 committed by GitHub
parent a29802de36
commit ac9fb2b02d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 811 additions and 529 deletions

View file

@ -15,7 +15,7 @@ use graphene_core::{Ctx, GraphicElement, Node};
#[node_macro::node(category("Debug"))]
fn vector_points(_: impl Ctx, vector_data: VectorDataTable) -> Vec<DVec2> {
let vector_data = vector_data.one_instance().instance;
let vector_data = vector_data.one_instance_ref().instance;
vector_data.point_domain.positions().to_vec()
}
@ -96,8 +96,8 @@ where
return target;
}
let target_width = target.one_instance().instance.width;
let target_height = target.one_instance().instance.height;
let target_width = target.one_instance_ref().instance.width;
let target_height = target.one_instance_ref().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);
@ -122,7 +122,7 @@ 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.data.len());
assert!(target_index(max_x, max_y) < target.one_instance_ref().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 {
@ -143,7 +143,7 @@ pub async fn create_brush_texture(brush_style: &BrushStyle) -> Image<Color> {
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.clone()
image.one_instance_ref().instance.clone()
}
macro_rules! inline_blend_funcs {
@ -220,7 +220,7 @@ async fn brush(_: impl Ctx, image_frame_table: ImageFrameTable<Color>, bounds: I
let mut background_bounds = bbox.to_transform();
// If the bounds are empty (no size on images or det(transform) = 0), keep the target bounds
let bounds_empty = bounds.instances().all(|bounds| bounds.instance.width() == 0 || bounds.instance.height() == 0);
let bounds_empty = bounds.instance_ref_iter().all(|bounds| bounds.instance.width() == 0 || bounds.instance.height() == 0);
if bounds.transform().matrix2.determinant() != 0. && !bounds_empty {
background_bounds = bounds.transform();
}

View file

@ -9,9 +9,9 @@ use std::cmp::{max, min};
#[node_macro::node(category("Raster"))]
async fn dehaze(_: impl Ctx, image_frame: ImageFrameTable<Color>, strength: Percentage) -> ImageFrameTable<Color> {
let image_frame_transform = image_frame.transform();
let image_frame_alpha_blending = image_frame.one_instance().alpha_blending;
let image_frame_alpha_blending = image_frame.one_instance_ref().alpha_blending;
let image = image_frame.one_instance().instance;
let image = image_frame.one_instance_ref().instance;
// Prepare the image data for processing
let image_data = bytemuck::cast_vec(image.data.clone());

View file

@ -62,7 +62,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_instance().instance;
let image = image.one_instance_ref().instance;
log::debug!("Executing gpu node");
let executor = &editor_api.application_io.as_ref().and_then(|io| io.gpu_executor()).unwrap();
@ -113,7 +113,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable<Color>, node: DocumentNode,
};
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;
*result.one_instance_mut().alpha_blending = *image_frame_table.one_instance_ref().alpha_blending;
result
}
@ -133,7 +133,7 @@ where
GraphicElement: From<Image<T>>,
T::Static: Pixel,
{
let image = image.one_instance().instance;
let image = image.one_instance_ref().instance;
let compiler = graph_craft::graphene_compiler::Compiler {};
let inner_network = NodeNetwork::value_network(node);
@ -278,10 +278,10 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable<Color>, backgr
let foreground_transform = foreground.transform();
let background_transform = background.transform();
let background_alpha_blending = background.one_instance().alpha_blending;
let background_alpha_blending = background.one_instance_ref().alpha_blending;
let foreground = foreground.one_instance().instance;
let background = background.one_instance().instance;
let foreground = foreground.one_instance_ref().instance;
let background = background.one_instance_ref().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);

View file

@ -16,7 +16,7 @@ async fn image_color_palette(
let mut histogram: Vec<usize> = vec![0; (bins + 1.) as usize];
let mut colors: Vec<Vec<Color>> = vec![vec![]; (bins + 1.) as usize];
let image = image.one_instance().instance;
let image = image.one_instance_ref().instance;
for pixel in image.data.iter() {
let r = pixel.r() * GRID;

View file

@ -29,9 +29,9 @@ impl From<std::io::Error> for Error {
#[node_macro::node(category("Debug: Raster"))]
fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: ImageFrameTable<Color>) -> ImageFrameTable<Color> {
let image_frame_transform = image_frame.transform();
let image_frame_alpha_blending = image_frame.one_instance().alpha_blending;
let image_frame_alpha_blending = image_frame.one_instance_ref().alpha_blending;
let image = image_frame.one_instance().instance;
let image = image_frame.one_instance_ref().instance;
// Resize the image using the image crate
let data = bytemuck::cast_vec(image.data.clone());
@ -325,7 +325,7 @@ fn extend_image_to_bounds(image: ImageFrameTable<Color>, bounds: DAffine2) -> Im
return image;
}
let image_instance = image.one_instance().instance;
let image_instance = image.one_instance_ref().instance;
if image_instance.width == 0 || image_instance.height == 0 {
return empty_image((), bounds, Color::TRANSPARENT);
}
@ -355,7 +355,7 @@ fn extend_image_to_bounds(image: ImageFrameTable<Color>, bounds: DAffine2) -> Im
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;
*result.one_instance_mut().alpha_blending = *image.one_instance_ref().alpha_blending;
result
}

View file

@ -14,11 +14,11 @@ use std::ops::Mul;
async fn boolean_operation(_: impl Ctx, group_of_paths: GraphicGroupTable, operation: BooleanOperation) -> VectorDataTable {
fn flatten_vector_data(graphic_group_table: &GraphicGroupTable) -> Vec<VectorDataTable> {
graphic_group_table
.instances()
.instance_ref_iter()
.map(|element| match element.instance.clone() {
GraphicElement::VectorData(mut vector_data) => {
// Apply the parent group's transform to each element of vector data
for sub_vector_data in vector_data.instances_mut() {
for sub_vector_data in vector_data.instance_mut_iter() {
*sub_vector_data.transform = *element.transform * *sub_vector_data.transform;
}
@ -28,12 +28,12 @@ async fn boolean_operation(_: impl Ctx, group_of_paths: GraphicGroupTable, opera
// Apply the parent group's transform to each element of raster data
match &mut image {
graphene_core::RasterFrame::ImageFrame(image) => {
for instance in image.instances_mut() {
for instance in image.instance_mut_iter() {
*instance.transform = *element.transform * *instance.transform;
}
}
graphene_core::RasterFrame::TextureFrame(image) => {
for instance in image.instances_mut() {
for instance in image.instance_mut_iter() {
*instance.transform = *element.transform * *instance.transform;
}
}
@ -50,7 +50,7 @@ async fn boolean_operation(_: impl Ctx, group_of_paths: GraphicGroupTable, opera
}
GraphicElement::GraphicGroup(mut graphic_group) => {
// Apply the parent group's transform to each element of inner group
for sub_element in graphic_group.instances_mut() {
for sub_element in graphic_group.instance_mut_iter() {
*sub_element.transform = *element.transform * *sub_element.transform;
}
@ -72,7 +72,7 @@ async fn boolean_operation(_: impl Ctx, group_of_paths: GraphicGroupTable, opera
let result = result.one_instance_mut().instance;
let upper_path_string = to_path(result, DAffine2::IDENTITY);
let lower_path_string = to_path(lower_vector_data.one_instance().instance, transform_of_lower_into_space_of_upper);
let lower_path_string = to_path(lower_vector_data.one_instance_ref().instance, transform_of_lower_into_space_of_upper);
#[allow(unused_unsafe)]
let boolean_operation_string = unsafe { boolean_subtract(upper_path_string, lower_path_string) };
@ -105,7 +105,7 @@ async fn boolean_operation(_: impl Ctx, group_of_paths: GraphicGroupTable, opera
let result_vector_data = result_vector_data_table.one_instance_mut().instance;
let upper_path_string = to_path(result_vector_data, DAffine2::IDENTITY);
let lower_path_string = to_path(lower_vector_data.one_instance().instance, transform_of_lower_into_space_of_upper);
let lower_path_string = to_path(lower_vector_data.one_instance_ref().instance, transform_of_lower_into_space_of_upper);
#[allow(unused_unsafe)]
let boolean_operation_string = unsafe { boolean_union(upper_path_string, lower_path_string) };
@ -136,7 +136,7 @@ async fn boolean_operation(_: impl Ctx, group_of_paths: GraphicGroupTable, opera
let result = result.one_instance_mut().instance;
let upper_path_string = to_path(result, DAffine2::IDENTITY);
let lower_path_string = to_path(lower_vector_data.one_instance().instance, transform_of_lower_into_space_of_upper);
let lower_path_string = to_path(lower_vector_data.one_instance_ref().instance, transform_of_lower_into_space_of_upper);
#[allow(unused_unsafe)]
let boolean_operation_string = unsafe { boolean_intersect(upper_path_string, lower_path_string) };
@ -160,12 +160,12 @@ async fn boolean_operation(_: impl Ctx, group_of_paths: GraphicGroupTable, opera
// Find where all vector data intersect at least once
while let Some(lower_vector_data) = second_vector_data {
let all_other_vector_data = boolean_operation_on_vector_data(&vector_data_table.iter().filter(|v| v != &lower_vector_data).cloned().collect::<Vec<_>>(), BooleanOperation::Union);
let all_other_vector_data_instance = all_other_vector_data.one_instance();
let all_other_vector_data_instance = all_other_vector_data.one_instance_ref();
let transform_of_lower_into_space_of_upper = all_other_vector_data.transform().inverse() * lower_vector_data.transform();
let upper_path_string = to_path(all_other_vector_data_instance.instance, DAffine2::IDENTITY);
let lower_path_string = to_path(lower_vector_data.one_instance().instance, transform_of_lower_into_space_of_upper);
let lower_path_string = to_path(lower_vector_data.one_instance_ref().instance, transform_of_lower_into_space_of_upper);
#[allow(unused_unsafe)]
let boolean_intersection_string = unsafe { boolean_intersect(upper_path_string, lower_path_string) };

View file

@ -187,7 +187,7 @@ where
..Default::default()
};
for instance in data.instances_mut() {
for instance in data.instance_mut_iter() {
*instance.transform = DAffine2::from_translation(-aabb.start) * *instance.transform;
}
data.render_svg(&mut render, &render_params);