Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,18 @@ fn static_nodes() -> Vec<DocumentNodeType> {
properties: |_document_node, _node_id, _context| node_properties::string_properties("Creates an embedded image with the given transform"),
},
DocumentNodeType {
name: "Blend Node",
name: "Mask",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_std::raster::MaskImageNode<_>"),
inputs: vec![
DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true),
DocumentInputType::value("Stencil", TaggedValue::ImageFrame(ImageFrame::empty()), true),
],
outputs: vec![DocumentOutputType::new("Image", FrontendGraphDataType::Raster)],
properties: node_properties::mask_properties,
},
DocumentNodeType {
name: "Blend",
category: "Image Adjustments",
identifier: NodeImplementation::proto("graphene_core::raster::BlendNode<_, _, _, _>"),
inputs: vec![
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -477,6 +477,12 @@ pub fn blend_properties(document_node: &DocumentNode, node_id: NodeId, _context:
vec![backdrop, blend_mode, LayoutGroup::Row { widgets: opacity }]
}

pub fn mask_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let mask = color_widget(document_node, node_id, 1, "Stencil", ColorInput::default(), true);

vec![mask]
}

pub fn luminance_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec<LayoutGroup> {
let luminance_calc = luminance_calculation(document_node, node_id, 1, "Luminance Calc", true);

Expand Down
2 changes: 1 addition & 1 deletion node-graph/compilation-client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ fn main() {
nodes: [(
0,
DocumentNode {
name: "Inc Node".into(),
name: "Inc".into(),
inputs: vec![NodeInput::Network(concrete!(u32))],
implementation: DocumentNodeImplementation::Network(add_network()),
metadata: DocumentNodeMetadata::default(),
Expand Down
2 changes: 1 addition & 1 deletion node-graph/gcore/src/raster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ mod image {
&mut self.image.data[y * (self.image.width as usize) + x]
}

/// Clamps the provided point to (0, 0) (ImageSize) and returns the closest pixel
/// Clamps the provided point to ((0, 0), (ImageSize.x, ImageSize.y)) and returns the closest pixel
pub fn sample(&self, position: DVec2) -> Color {
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;
Expand Down
2 changes: 1 addition & 1 deletion node-graph/gstd/src/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ fn map_gpu_single_image(input: Image, node: String) -> Image {
nodes: [(
0,
DocumentNode {
name: "Image filter Node".into(),
name: "Image Filter".into(),
inputs: vec![NodeInput::Network(concrete!(Color))],
implementation: DocumentNodeImplementation::Unresolved(identifier),
metadata: DocumentNodeMetadata::default(),
Expand Down
34 changes: 34 additions & 0 deletions node-graph/gstd/src/raster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,40 @@ fn compute_transformed_bounding_box(transform: DAffine2) -> Bbox {
}
}

#[derive(Debug, Clone, Copy)]
pub struct MaskImageNode<Mask> {
mask: Mask,
}

#[node_macro::node_fn(MaskImageNode)]
fn mask_image(mut image: ImageFrame, mask: ImageFrame) -> ImageFrame {
let image_size = DVec2::new(image.image.width as f64, image.image.height as f64);
let mask_size = DVec2::new(mask.image.width as f64, mask.image.height as f64);

if mask_size == DVec2::ZERO {
return image;
}

// Transforms a point from the background image to the forground image
let bg_to_fg = DAffine2::from_scale(mask_size) * mask.transform.inverse() * image.transform * DAffine2::from_scale(1. / image_size);

for y in 0..image.image.height {
for x in 0..image.image.width {
let image_point = DVec2::new(x as f64, y as f64);
let mut mask_point = bg_to_fg.transform_point2(image_point);
mask_point = mask_point.clamp(DVec2::ZERO, mask_size);

let image_pixel = image.get_mut(x as usize, y as usize);
let mask_pixel = mask.sample(mask_point);
let alpha = image_pixel.a() * mask_pixel.r();

*image_pixel = Color::from_rgbaf32(image_pixel.r(), image_pixel.g(), image_pixel.b(), alpha).unwrap();
}
}

image
}

#[derive(Debug, Clone, Copy)]
pub struct BlendImageNode<Background, MapFn> {
background: Background,
Expand Down
1 change: 1 addition & 0 deletions node-graph/interpreted-executor/src/node_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ fn node_registry() -> HashMap<NodeIdentifier, HashMap<NodeIOTypes, NodeConstruct
register_node!(graphene_core::ops::AddParameterNode<_>, input: &f64, params: [&f64]),
register_node!(graphene_core::ops::SomeNode, input: ImageFrame, params: []),
register_node!(graphene_std::raster::DownscaleNode, input: ImageFrame, params: []),
register_node!(graphene_std::raster::MaskImageNode<_>, input: ImageFrame, params: [ImageFrame]),
#[cfg(feature = "gpu")]
register_node!(graphene_std::executor::MapGpuSingleImageNode<_>, input: Image, params: [String]),
vec![(
Expand Down