From 5a1503fc98dc742f61aee8c725b318d616288f7a Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Fri, 20 Feb 2026 13:35:12 -0800 Subject: [PATCH] New node: Flatten Raster --- .../libraries/graphic-types/src/graphic.rs | 48 +++++++++++++++++++ node-graph/nodes/graphic/src/graphic.rs | 8 +++- 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/node-graph/libraries/graphic-types/src/graphic.rs b/node-graph/libraries/graphic-types/src/graphic.rs index c535ed46..428affb8 100644 --- a/node-graph/libraries/graphic-types/src/graphic.rs +++ b/node-graph/libraries/graphic-types/src/graphic.rs @@ -156,6 +156,54 @@ pub trait IntoGraphicTable { flatten_table(&mut output, content); output } + + /// Deeply flattens any raster content within a graphic table, discarding non-raster content, and returning a table of only raster elements. + fn into_flattened_raster_table(self) -> Table> + where + Self: std::marker::Sized, + { + let content = self.into_graphic_table(); + + fn flatten_table(output_raster_table: &mut Table>, current_graphic_table: Table) { + for current_graphic_row in current_graphic_table.iter() { + let current_graphic = current_graphic_row.element.clone(); + let source_node_id = *current_graphic_row.source_node_id; + + match current_graphic { + // If we're allowed to recurse, flatten any tables we encounter + Graphic::Graphic(mut current_graphic_table) => { + // Apply the parent graphic's transform to all child elements + for graphic in current_graphic_table.iter_mut() { + *graphic.transform = *current_graphic_row.transform * *graphic.transform; + } + + flatten_table(output_raster_table, current_graphic_table); + } + // Push any leaf RasterCPU elements we encounter + Graphic::RasterCPU(raster_table) => { + for current_raster_row in raster_table.iter() { + output_raster_table.push(TableRow { + element: current_raster_row.element.clone(), + transform: *current_graphic_row.transform * *current_raster_row.transform, + alpha_blending: AlphaBlending { + blend_mode: current_raster_row.alpha_blending.blend_mode, + opacity: current_graphic_row.alpha_blending.opacity * current_raster_row.alpha_blending.opacity, + fill: current_raster_row.alpha_blending.fill, + clip: current_raster_row.alpha_blending.clip, + }, + source_node_id, + }); + } + } + _ => {} + } + } + } + + let mut output = Table::new(); + flatten_table(&mut output, content); + output + } } impl IntoGraphicTable for Table { diff --git a/node-graph/nodes/graphic/src/graphic.rs b/node-graph/nodes/graphic/src/graphic.rs index ad174929..f41d022c 100644 --- a/node-graph/nodes/graphic/src/graphic.rs +++ b/node-graph/nodes/graphic/src/graphic.rs @@ -192,10 +192,16 @@ pub async fn flatten_graphic(_: impl Ctx, content: Table, fully_flatten /// Converts a graphic table into a vector table by deeply flattening any vector content it contains, and discarding any non-vector content. #[node_macro::node(category("Vector"))] -pub async fn flatten_vector(_: impl Ctx, #[implementations(Table, Table)] content: I) -> Table { +pub async fn flatten_vector(_: impl Ctx, #[implementations(Table, Table)] content: T) -> Table { content.into_flattened_vector_table() } +/// Converts a graphic table into a vector table by deeply flattening any vector content it contains, and discarding any non-vector content. +#[node_macro::node(category("Vector"))] +pub async fn flatten_raster(_: impl Ctx, #[implementations(Table, Table>)] content: T) -> Table> { + content.into_flattened_raster_table() +} + /// Returns the value at the specified index in the collection. /// If no value exists at that index, the type's default value is returned. #[node_macro::node(category("General"))]