mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2025-09-02 19:27:26 +00:00
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:
parent
a29802de36
commit
ac9fb2b02d
33 changed files with 811 additions and 529 deletions
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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 = ℑ
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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) };
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue