Improve naming of nodes and 'add' menu styling

This commit is contained in:
Keavon Chambers
2022-12-03 23:29:55 -08:00
parent f9d772070b
commit 951c4b665f
7 changed files with 109 additions and 104 deletions
@@ -40,7 +40,7 @@ pub struct DocumentNodeType {
static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
DocumentNodeType { DocumentNodeType {
name: "Identity", name: "Identity",
category: "Meta", category: "General",
identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Concrete(Cow::Borrowed("Any<'_>"))]), identifier: NodeIdentifier::new("graphene_core::ops::IdNode", &[Type::Concrete(Cow::Borrowed("Any<'_>"))]),
inputs: &[DocumentInputType { inputs: &[DocumentInputType {
name: "In", name: "In",
@@ -82,9 +82,9 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
properties: |_document_node, _node_id| node_properties::string_properties("The output to the graph is rendered in the frame".to_string()), properties: |_document_node, _node_id| node_properties::string_properties("The output to the graph is rendered in the frame".to_string()),
}, },
DocumentNodeType { DocumentNodeType {
name: "Grayscale Image", name: "Grayscale",
category: "Image Color Correction", category: "Image Adjustments",
identifier: NodeIdentifier::new("graphene_std::raster::GrayscaleImageNode", &[]), identifier: NodeIdentifier::new("graphene_std::raster::GrayscaleNode", &[]),
inputs: &[DocumentInputType { inputs: &[DocumentInputType {
name: "Image", name: "Image",
data_type: FrontendGraphDataType::Raster, data_type: FrontendGraphDataType::Raster,
@@ -94,9 +94,9 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
properties: node_properties::no_properties, properties: node_properties::no_properties,
}, },
DocumentNodeType { DocumentNodeType {
name: "Invert Image Color", name: "Invert RGB",
category: "Image Color Correction", category: "Image Adjustments",
identifier: NodeIdentifier::new("graphene_std::raster::InvertImageColorNode", &[]), identifier: NodeIdentifier::new("graphene_std::raster::InvertRGBNode", &[]),
inputs: &[DocumentInputType { inputs: &[DocumentInputType {
name: "Image", name: "Image",
data_type: FrontendGraphDataType::Raster, data_type: FrontendGraphDataType::Raster,
@@ -106,9 +106,9 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
properties: node_properties::no_properties, properties: node_properties::no_properties,
}, },
DocumentNodeType { DocumentNodeType {
name: "Shift Image HSL", name: "Hue/Saturation",
category: "Image Color Correction", category: "Image Adjustments",
identifier: NodeIdentifier::new("graphene_std::raster::ShiftImageHSLNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), identifier: NodeIdentifier::new("graphene_std::raster::HueSaturationNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
inputs: &[ inputs: &[
DocumentInputType { DocumentInputType {
name: "Image", name: "Image",
@@ -126,7 +126,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
default: NodeInput::value(TaggedValue::F64(0.), false), default: NodeInput::value(TaggedValue::F64(0.), false),
}, },
DocumentInputType { DocumentInputType {
name: "Luminance Shift", name: "Lightness Shift",
data_type: FrontendGraphDataType::Number, data_type: FrontendGraphDataType::Number,
default: NodeInput::value(TaggedValue::F64(0.), false), default: NodeInput::value(TaggedValue::F64(0.), false),
}, },
@@ -135,9 +135,9 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
properties: node_properties::adjust_hsl_properties, properties: node_properties::adjust_hsl_properties,
}, },
DocumentNodeType { DocumentNodeType {
name: "Image Contrast and Brightness", name: "Brightness/Contrast",
category: "Image Color Correction", category: "Image Adjustments",
identifier: NodeIdentifier::new("graphene_std::raster::ImageBrightnessAndContrast", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), identifier: NodeIdentifier::new("graphene_std::raster::BrightnessContrastNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
inputs: &[ inputs: &[
DocumentInputType { DocumentInputType {
name: "Image", name: "Image",
@@ -159,9 +159,9 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
properties: node_properties::brighten_image_properties, properties: node_properties::brighten_image_properties,
}, },
DocumentNodeType { DocumentNodeType {
name: "Adjust Image Gamma", name: "Gamma",
category: "Image Color Correction", category: "Image Adjustments",
identifier: NodeIdentifier::new("graphene_std::raster::ImageGammaNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), identifier: NodeIdentifier::new("graphene_std::raster::GammaNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
inputs: &[ inputs: &[
DocumentInputType { DocumentInputType {
name: "Image", name: "Image",
@@ -178,9 +178,9 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
properties: node_properties::adjust_gamma_properties, properties: node_properties::adjust_gamma_properties,
}, },
DocumentNodeType { DocumentNodeType {
name: "Multiply Image Opactiy", name: "Opacity",
category: "Image Color Correction", category: "Image Adjustments",
identifier: NodeIdentifier::new("graphene_std::raster::ImageOpacityNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), identifier: NodeIdentifier::new("graphene_std::raster::OpacityNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
inputs: &[ inputs: &[
DocumentInputType { DocumentInputType {
name: "Image", name: "Image",
@@ -198,8 +198,8 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
}, },
DocumentNodeType { DocumentNodeType {
name: "Posterize", name: "Posterize",
category: "Image Filters", category: "Image Adjustments",
identifier: NodeIdentifier::new("graphene_std::raster::Posterize", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), identifier: NodeIdentifier::new("graphene_std::raster::PosterizeNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
inputs: &[ inputs: &[
DocumentInputType { DocumentInputType {
name: "Image", name: "Image",
@@ -217,7 +217,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
}, },
DocumentNodeType { DocumentNodeType {
name: "Exposure", name: "Exposure",
category: "Image Color Correction", category: "Image Adjustments",
identifier: NodeIdentifier::new("graphene_std::raster::ExposureNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), identifier: NodeIdentifier::new("graphene_std::raster::ExposureNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
inputs: &[ inputs: &[
DocumentInputType { DocumentInputType {
@@ -228,7 +228,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
DocumentInputType { DocumentInputType {
name: "Value", name: "Value",
data_type: FrontendGraphDataType::Number, data_type: FrontendGraphDataType::Number,
default: NodeInput::value(TaggedValue::F64(1.), false), default: NodeInput::value(TaggedValue::F64(0.), false),
}, },
], ],
outputs: &[FrontendGraphDataType::Raster], outputs: &[FrontendGraphDataType::Raster],
@@ -236,7 +236,7 @@ static DOCUMENT_NODE_TYPES: &[DocumentNodeType] = &[
}, },
DocumentNodeType { DocumentNodeType {
name: "Add", name: "Add",
category: "Mathmatics", category: "Math",
identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), identifier: NodeIdentifier::new("graphene_core::ops::AddNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
inputs: &[ inputs: &[
DocumentInputType { DocumentInputType {
@@ -76,12 +76,12 @@ fn number_range_widget(document_node: &DocumentNode, node_id: NodeId, index: usi
pub fn adjust_hsl_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> { pub fn adjust_hsl_properties(document_node: &DocumentNode, node_id: NodeId) -> Vec<LayoutGroup> {
let hue_shift = number_range_widget(document_node, node_id, 1, "Hue Shift", Some(-180.), Some(180.), "°".into(), false); let hue_shift = number_range_widget(document_node, node_id, 1, "Hue Shift", Some(-180.), Some(180.), "°".into(), false);
let saturation_shift = number_range_widget(document_node, node_id, 2, "Saturation Shift", Some(-100.), Some(100.), "%".into(), false); let saturation_shift = number_range_widget(document_node, node_id, 2, "Saturation Shift", Some(-100.), Some(100.), "%".into(), false);
let luminance_shift = number_range_widget(document_node, node_id, 3, "Luminance Shift", Some(-100.), Some(100.), "%".into(), false); let lightness_shift = number_range_widget(document_node, node_id, 3, "Lightness Shift", Some(-100.), Some(100.), "%".into(), false);
vec![ vec![
LayoutGroup::Row { widgets: hue_shift }, LayoutGroup::Row { widgets: hue_shift },
LayoutGroup::Row { widgets: saturation_shift }, LayoutGroup::Row { widgets: saturation_shift },
LayoutGroup::Row { widgets: luminance_shift }, LayoutGroup::Row { widgets: lightness_shift },
] ]
} }
@@ -261,8 +261,8 @@ fn unknown_node_properties(document_node: &DocumentNode) -> Vec<LayoutGroup> {
string_properties(format!("Node '{}' cannot be found in library", document_node.name)) string_properties(format!("Node '{}' cannot be found in library", document_node.name))
} }
pub fn no_properties(document_node: &DocumentNode, _node_id: NodeId) -> Vec<LayoutGroup> { pub fn no_properties(_document_node: &DocumentNode, _node_id: NodeId) -> Vec<LayoutGroup> {
string_properties(format!("The {} node requires no properties.", document_node.name.to_lowercase())) string_properties("Node has no properties")
} }
pub fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId) -> LayoutGroup { pub fn generate_node_properties(document_node: &DocumentNode, node_id: NodeId) -> LayoutGroup {
+6 -1
View File
@@ -19,7 +19,7 @@
<TextInput placeholder="Search Nodes..." :value="searchTerm" @update:value="(val) => (searchTerm = val)" v-focus /> <TextInput placeholder="Search Nodes..." :value="searchTerm" @update:value="(val) => (searchTerm = val)" v-focus />
<LayoutCol v-for="nodeCategory in nodeCategories" :key="nodeCategory[0]"> <LayoutCol v-for="nodeCategory in nodeCategories" :key="nodeCategory[0]">
<TextLabel>{{ nodeCategory[0] }}</TextLabel> <TextLabel>{{ nodeCategory[0] }}</TextLabel>
<TextButton v-for="nodeType in nodeCategory[1]" v-bind:key="String(nodeType)" :label="nodeType.name + ' Node'" :action="() => createNode(nodeType.name)" /> <TextButton v-for="nodeType in nodeCategory[1]" v-bind:key="String(nodeType)" :label="nodeType.name" :action="() => createNode(nodeType.name)" />
</LayoutCol> </LayoutCol>
<TextLabel v-if="nodeCategories.length === 0">No search results :(</TextLabel> <TextLabel v-if="nodeCategories.length === 0">No search results :(</TextLabel>
</LayoutCol> </LayoutCol>
@@ -114,6 +114,11 @@
padding: 5px; padding: 5px;
z-index: 3; z-index: 3;
background-color: var(--color-3-darkgray); background-color: var(--color-3-darkgray);
.text-button + .text-button {
margin-left: 0;
margin-top: 4px;
}
} }
.options-bar { .options-bar {
+4 -4
View File
@@ -55,16 +55,16 @@ impl<N: Node<(), Output = f32>> Node<Color> for HueShiftColorNode<N> {
type Output = Color; type Output = Color;
fn eval(self, color: Color) -> Color { fn eval(self, color: Color) -> Color {
let hue_shift = self.0.eval(()); let hue_shift = self.0.eval(());
let [hue, saturation, luminance, alpha] = color.to_hsla(); let [hue, saturation, lightness, alpha] = color.to_hsla();
Color::from_hsla(hue + hue_shift / 360., saturation, luminance, alpha) Color::from_hsla(hue + hue_shift / 360., saturation, lightness, alpha)
} }
} }
impl<N: Node<(), Output = f32> + Copy> Node<Color> for &HueShiftColorNode<N> { impl<N: Node<(), Output = f32> + Copy> Node<Color> for &HueShiftColorNode<N> {
type Output = Color; type Output = Color;
fn eval(self, color: Color) -> Color { fn eval(self, color: Color) -> Color {
let hue_shift = self.0.eval(()); let hue_shift = self.0.eval(());
let [hue, saturation, luminance, alpha] = color.to_hsla(); let [hue, saturation, lightness, alpha] = color.to_hsla();
Color::from_hsla(hue + hue_shift / 360., saturation, luminance, alpha) Color::from_hsla(hue + hue_shift / 360., saturation, lightness, alpha)
} }
} }
+12 -12
View File
@@ -82,20 +82,20 @@ impl Color {
} }
} }
/// Create a [Color] from a hue, saturation, luminance and alpha (all between 0 and 1) /// Create a [Color] from a hue, saturation, lightness and alpha (all between 0 and 1)
/// ///
/// # Examples /// # Examples
/// ``` /// ```
/// use graphene_core::raster::color::Color; /// use graphene_core::raster::color::Color;
/// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.); /// let color = Color::from_hsla(0.5, 0.2, 0.3, 1.);
/// ``` /// ```
pub fn from_hsla(hue: f32, saturation: f32, luminance: f32, alpha: f32) -> Color { pub fn from_hsla(hue: f32, saturation: f32, lightness: f32, alpha: f32) -> Color {
let temp1 = if luminance < 0.5 { let temp1 = if lightness < 0.5 {
luminance * (saturation + 1.) lightness * (saturation + 1.)
} else { } else {
luminance + saturation - luminance * saturation lightness + saturation - lightness * saturation
}; };
let temp2 = 2. * luminance - temp1; let temp2 = 2. * lightness - temp1;
let mut red = (hue + 1. / 3.).rem_euclid(1.); let mut red = (hue + 1. / 3.).rem_euclid(1.);
let mut green = hue.rem_euclid(1.); let mut green = hue.rem_euclid(1.);
@@ -190,7 +190,7 @@ impl Color {
} }
// https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/ // https://www.niwa.nu/2013/05/math-behind-colorspace-conversions-rgb-hsl/
/// Convert a [Color] to a hue, saturation, luminance and alpha (all between 0 and 1) /// Convert a [Color] to a hue, saturation, lightness and alpha (all between 0 and 1)
/// ///
/// # Examples /// # Examples
/// ``` /// ```
@@ -201,10 +201,10 @@ impl Color {
let min_channel = self.red.min(self.green).min(self.blue); let min_channel = self.red.min(self.green).min(self.blue);
let max_channel = self.red.max(self.green).max(self.blue); let max_channel = self.red.max(self.green).max(self.blue);
let luminance = (min_channel + max_channel) / 2.; let lightness = (min_channel + max_channel) / 2.;
let saturation = if min_channel == max_channel { let saturation = if min_channel == max_channel {
0. 0.
} else if luminance <= 0.5 { } else if lightness <= 0.5 {
(max_channel - min_channel) / (max_channel + min_channel) (max_channel - min_channel) / (max_channel + min_channel)
} else { } else {
(max_channel - min_channel) / (2. - max_channel - min_channel) (max_channel - min_channel) / (2. - max_channel - min_channel)
@@ -218,7 +218,7 @@ impl Color {
} / 6.; } / 6.;
let hue = hue.rem_euclid(1.); let hue = hue.rem_euclid(1.);
[hue, saturation, luminance, self.alpha] [hue, saturation, lightness, self.alpha]
} }
// TODO: Readd formatting // TODO: Readd formatting
@@ -285,8 +285,8 @@ fn hsl_roundtrip() {
(255, 255, 178), (255, 255, 178),
] { ] {
let col = Color::from_rgb8(red, green, blue); let col = Color::from_rgb8(red, green, blue);
let [hue, saturation, luminance, alpha] = col.to_hsla(); let [hue, saturation, lightness, alpha] = col.to_hsla();
let result = Color::from_hsla(hue, saturation, luminance, alpha); let result = Color::from_hsla(hue, saturation, lightness, alpha);
assert!((col.r() - result.r()) < f32::EPSILON * 100.); assert!((col.r() - result.r()) < f32::EPSILON * 100.);
assert!((col.g() - result.g()) < f32::EPSILON * 100.); assert!((col.g() - result.g()) < f32::EPSILON * 100.);
assert!((col.b() - result.b()) < f32::EPSILON * 100.); assert!((col.b() - result.b()) < f32::EPSILON * 100.);
+20 -20
View File
@@ -287,9 +287,9 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
unimplemented!() unimplemented!()
} }
}), }),
(NodeIdentifier::new("graphene_std::raster::GrayscaleImageNode", &[]), |proto_node, stack| { (NodeIdentifier::new("graphene_std::raster::GrayscaleNode", &[]), |proto_node, stack| {
stack.push_fn(move |nodes| { stack.push_fn(move |nodes| {
let node = DynAnyNode::new(graphene_std::raster::GrayscaleImageNode); let node = DynAnyNode::new(graphene_std::raster::GrayscaleNode);
if let ProtoNodeInput::Node(node_id) = proto_node.input { if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap(); let pre_node = nodes.get(node_id as usize).unwrap();
@@ -299,9 +299,9 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
} }
}) })
}), }),
(NodeIdentifier::new("graphene_std::raster::InvertImageColorNode", &[]), |proto_node, stack| { (NodeIdentifier::new("graphene_std::raster::InvertRGBNode", &[]), |proto_node, stack| {
stack.push_fn(move |nodes| { stack.push_fn(move |nodes| {
let node = DynAnyNode::new(graphene_std::raster::InvertImageColorNode); let node = DynAnyNode::new(graphene_std::raster::InvertRGBNode);
if let ProtoNodeInput::Node(node_id) = proto_node.input { if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap(); let pre_node = nodes.get(node_id as usize).unwrap();
@@ -312,15 +312,15 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
}) })
}), }),
( (
NodeIdentifier::new("graphene_std::raster::ShiftImageHSLNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), NodeIdentifier::new("graphene_std::raster::HueSaturationNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
|proto_node, stack| { |proto_node, stack| {
stack.push_fn(move |nodes| { stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("ShiftImageHSLNode Node constructed without inputs") }; let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("HueSaturationNode Node constructed without inputs") };
let hue: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap()); let hue: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let saturation: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[1] as usize).unwrap()); let saturation: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[1] as usize).unwrap());
let luminance: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[2] as usize).unwrap()); let lightness: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[2] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::ShiftImageHSLNode::new(hue, saturation, luminance)); let node = DynAnyNode::new(graphene_std::raster::HueSaturationNode::new(hue, saturation, lightness));
if let ProtoNodeInput::Node(node_id) = proto_node.input { if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap(); let pre_node = nodes.get(node_id as usize).unwrap();
@@ -332,14 +332,14 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
}, },
), ),
( (
NodeIdentifier::new("graphene_std::raster::ImageBrightnessAndContrast", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), NodeIdentifier::new("graphene_std::raster::BrightnessContrastNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
|proto_node, stack| { |proto_node, stack| {
stack.push_fn(move |nodes| { stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("ImageBrightnessAndContrast Node constructed without inputs") }; let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("BrightnessContrastNode Node constructed without inputs") };
let brightness: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap()); let brightness: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let contrast: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[1] as usize).unwrap()); let contrast: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[1] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::ImageBrightnessAndContrast::new(brightness, contrast)); let node = DynAnyNode::new(graphene_std::raster::BrightnessContrastNode::new(brightness, contrast));
if let ProtoNodeInput::Node(node_id) = proto_node.input { if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap(); let pre_node = nodes.get(node_id as usize).unwrap();
@@ -351,12 +351,12 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
}, },
), ),
( (
NodeIdentifier::new("graphene_std::raster::ImageGammaNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), NodeIdentifier::new("graphene_std::raster::GammaNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
|proto_node, stack| { |proto_node, stack| {
stack.push_fn(move |nodes| { stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("ImageGammaNode Node constructed without inputs") }; let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("GammaNode Node constructed without inputs") };
let gamma: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap()); let gamma: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::ImageGammaNode::new(gamma)); let node = DynAnyNode::new(graphene_std::raster::GammaNode::new(gamma));
if let ProtoNodeInput::Node(node_id) = proto_node.input { if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap(); let pre_node = nodes.get(node_id as usize).unwrap();
@@ -368,12 +368,12 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
}, },
), ),
( (
NodeIdentifier::new("graphene_std::raster::ImageOpacityNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), NodeIdentifier::new("graphene_std::raster::OpacityNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
|proto_node, stack| { |proto_node, stack| {
stack.push_fn(move |nodes| { stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("ImageOpacityNode Node constructed without inputs") }; let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("OpacityNode Node constructed without inputs") };
let opacity: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap()); let opacity: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::ImageOpacityNode::new(opacity)); let node = DynAnyNode::new(graphene_std::raster::OpacityNode::new(opacity));
if let ProtoNodeInput::Node(node_id) = proto_node.input { if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap(); let pre_node = nodes.get(node_id as usize).unwrap();
@@ -385,12 +385,12 @@ static NODE_REGISTRY: &[(NodeIdentifier, NodeConstructor)] = &[
}, },
), ),
( (
NodeIdentifier::new("graphene_std::raster::Posterize", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]), NodeIdentifier::new("graphene_std::raster::PosterizeNode", &[Type::Concrete(Cow::Borrowed("&TypeErasedNode"))]),
|proto_node, stack| { |proto_node, stack| {
stack.push_fn(move |nodes| { stack.push_fn(move |nodes| {
let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("Posterize Node constructed without inputs") }; let ConstructionArgs::Nodes(construction_nodes) = proto_node.construction_args else { unreachable!("Posterize node constructed without inputs") };
let value: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap()); let value: DowncastBothNode<_, (), f64> = DowncastBothNode::new(nodes.get(construction_nodes[0] as usize).unwrap());
let node = DynAnyNode::new(graphene_std::raster::Posterize::new(value)); let node = DynAnyNode::new(graphene_std::raster::PosterizeNode::new(value));
if let ProtoNodeInput::Node(node_id) = proto_node.input { if let ProtoNodeInput::Node(node_id) = proto_node.input {
let pre_node = nodes.get(node_id as usize).unwrap(); let pre_node = nodes.get(node_id as usize).unwrap();
+38 -38
View File
@@ -185,15 +185,15 @@ fn grayscale_image(mut image: Image) -> Image {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct GrayscaleImageNode; pub struct GrayscaleNode;
impl Node<Image> for GrayscaleImageNode { impl Node<Image> for GrayscaleNode {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
grayscale_image(image) grayscale_image(image)
} }
} }
impl Node<Image> for &GrayscaleImageNode { impl Node<Image> for &GrayscaleNode {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
grayscale_image(image) grayscale_image(image)
@@ -208,28 +208,28 @@ fn invert_image(mut image: Image) -> Image {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct InvertImageColorNode; pub struct InvertRGBNode;
impl Node<Image> for InvertImageColorNode { impl Node<Image> for InvertRGBNode {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
invert_image(image) invert_image(image)
} }
} }
impl Node<Image> for &InvertImageColorNode { impl Node<Image> for &InvertRGBNode {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
invert_image(image) invert_image(image)
} }
} }
fn shift_image_hsl(mut image: Image, hue_shift: f32, saturation_shift: f32, luminance_shift: f32) -> Image { fn shift_image_hsl(mut image: Image, hue_shift: f32, saturation_shift: f32, lightness_shift: f32) -> Image {
for pixel in &mut image.data { for pixel in &mut image.data {
let [hue, saturation, luminance, alpha] = pixel.to_hsla(); let [hue, saturation, lightness, alpha] = pixel.to_hsla();
*pixel = Color::from_hsla( *pixel = Color::from_hsla(
(hue + hue_shift / 360.) % 1., (hue + hue_shift / 360.) % 1.,
(saturation + saturation_shift / 100.).clamp(0., 1.), (saturation + saturation_shift / 100.).clamp(0., 1.),
(luminance + luminance_shift / 100.).clamp(0., 1.), (lightness + lightness_shift / 100.).clamp(0., 1.),
alpha, alpha,
); );
} }
@@ -237,48 +237,48 @@ fn shift_image_hsl(mut image: Image, hue_shift: f32, saturation_shift: f32, lumi
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct ShiftImageHSLNode<Hue, Sat, Lum> pub struct HueSaturationNode<Hue, Sat, Lit>
where where
Hue: Node<(), Output = f64>, Hue: Node<(), Output = f64>,
Sat: Node<(), Output = f64>, Sat: Node<(), Output = f64>,
Lum: Node<(), Output = f64>, Lit: Node<(), Output = f64>,
{ {
hue: Hue, hue: Hue,
saturation: Sat, saturation: Sat,
luminance: Lum, lightness: Lit,
} }
impl<Hue, Sat, Lum> Node<Image> for ShiftImageHSLNode<Hue, Sat, Lum> impl<Hue, Sat, Lit> Node<Image> for HueSaturationNode<Hue, Sat, Lit>
where where
Hue: Node<(), Output = f64>, Hue: Node<(), Output = f64>,
Sat: Node<(), Output = f64>, Sat: Node<(), Output = f64>,
Lum: Node<(), Output = f64>, Lit: Node<(), Output = f64>,
{ {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
shift_image_hsl(image, self.hue.eval(()) as f32, self.saturation.eval(()) as f32, self.luminance.eval(()) as f32) shift_image_hsl(image, self.hue.eval(()) as f32, self.saturation.eval(()) as f32, self.lightness.eval(()) as f32)
} }
} }
impl<Hue, Sat, Lum> Node<Image> for &ShiftImageHSLNode<Hue, Sat, Lum> impl<Hue, Sat, Lit> Node<Image> for &HueSaturationNode<Hue, Sat, Lit>
where where
Hue: Node<(), Output = f64> + Copy, Hue: Node<(), Output = f64> + Copy,
Sat: Node<(), Output = f64> + Copy, Sat: Node<(), Output = f64> + Copy,
Lum: Node<(), Output = f64> + Copy, Lit: Node<(), Output = f64> + Copy,
{ {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
shift_image_hsl(image, self.hue.eval(()) as f32, self.saturation.eval(()) as f32, self.luminance.eval(()) as f32) shift_image_hsl(image, self.hue.eval(()) as f32, self.saturation.eval(()) as f32, self.lightness.eval(()) as f32)
} }
} }
impl<Hue, Sat, Lum> ShiftImageHSLNode<Hue, Sat, Lum> impl<Hue, Sat, Lit> HueSaturationNode<Hue, Sat, Lit>
where where
Hue: Node<(), Output = f64>, Hue: Node<(), Output = f64>,
Sat: Node<(), Output = f64>, Sat: Node<(), Output = f64>,
Lum: Node<(), Output = f64>, Lit: Node<(), Output = f64>,
{ {
pub fn new(hue: Hue, saturation: Sat, luminance: Lum) -> Self { pub fn new(hue: Hue, saturation: Sat, lightness: Lit) -> Self {
Self { hue, saturation, luminance } Self { hue, saturation, lightness }
} }
} }
@@ -294,7 +294,7 @@ fn adjust_image_brightness_and_contrast(mut image: Image, brightness_shift: f32,
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct ImageBrightnessAndContrast<Brightness, Contrast> pub struct BrightnessContrastNode<Brightness, Contrast>
where where
Brightness: Node<(), Output = f64>, Brightness: Node<(), Output = f64>,
Contrast: Node<(), Output = f64>, Contrast: Node<(), Output = f64>,
@@ -303,7 +303,7 @@ where
contrast: Contrast, contrast: Contrast,
} }
impl<Brightness, Contrast> Node<Image> for ImageBrightnessAndContrast<Brightness, Contrast> impl<Brightness, Contrast> Node<Image> for BrightnessContrastNode<Brightness, Contrast>
where where
Brightness: Node<(), Output = f64>, Brightness: Node<(), Output = f64>,
Contrast: Node<(), Output = f64>, Contrast: Node<(), Output = f64>,
@@ -314,7 +314,7 @@ where
} }
} }
impl<Brightness, Contrast> Node<Image> for &ImageBrightnessAndContrast<Brightness, Contrast> impl<Brightness, Contrast> Node<Image> for &BrightnessContrastNode<Brightness, Contrast>
where where
Brightness: Node<(), Output = f64> + Copy, Brightness: Node<(), Output = f64> + Copy,
Contrast: Node<(), Output = f64> + Copy, Contrast: Node<(), Output = f64> + Copy,
@@ -325,7 +325,7 @@ where
} }
} }
impl<Brightness, Contrast> ImageBrightnessAndContrast<Brightness, Contrast> impl<Brightness, Contrast> BrightnessContrastNode<Brightness, Contrast>
where where
Brightness: Node<(), Output = f64>, Brightness: Node<(), Output = f64>,
Contrast: Node<(), Output = f64>, Contrast: Node<(), Output = f64>,
@@ -346,22 +346,22 @@ fn image_gamma(mut image: Image, gamma: f32) -> Image {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct ImageGammaNode<N: Node<(), Output = f64>>(N); pub struct GammaNode<N: Node<(), Output = f64>>(N);
impl<N: Node<(), Output = f64>> Node<Image> for ImageGammaNode<N> { impl<N: Node<(), Output = f64>> Node<Image> for GammaNode<N> {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
image_gamma(image, self.0.eval(()) as f32) image_gamma(image, self.0.eval(()) as f32)
} }
} }
impl<N: Node<(), Output = f64> + Copy> Node<Image> for &ImageGammaNode<N> { impl<N: Node<(), Output = f64> + Copy> Node<Image> for &GammaNode<N> {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
image_gamma(image, self.0.eval(()) as f32) image_gamma(image, self.0.eval(()) as f32)
} }
} }
impl<N: Node<(), Output = f64> + Copy> ImageGammaNode<N> { impl<N: Node<(), Output = f64> + Copy> GammaNode<N> {
pub fn new(node: N) -> Self { pub fn new(node: N) -> Self {
Self(node) Self(node)
} }
@@ -396,44 +396,44 @@ fn exposure(mut image: Image, exposure: f32) -> Image {
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Posterize<N: Node<(), Output = f64>>(N); pub struct PosterizeNode<N: Node<(), Output = f64>>(N);
impl<N: Node<(), Output = f64>> Node<Image> for Posterize<N> { impl<N: Node<(), Output = f64>> Node<Image> for PosterizeNode<N> {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
posterize(image, self.0.eval(()) as f32) posterize(image, self.0.eval(()) as f32)
} }
} }
impl<N: Node<(), Output = f64> + Copy> Node<Image> for &Posterize<N> { impl<N: Node<(), Output = f64> + Copy> Node<Image> for &PosterizeNode<N> {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
posterize(image, self.0.eval(()) as f32) posterize(image, self.0.eval(()) as f32)
} }
} }
impl<N: Node<(), Output = f64> + Copy> Posterize<N> { impl<N: Node<(), Output = f64> + Copy> PosterizeNode<N> {
pub fn new(node: N) -> Self { pub fn new(node: N) -> Self {
Self(node) Self(node)
} }
} }
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct ImageOpacityNode<N: Node<(), Output = f64>>(N); pub struct OpacityNode<N: Node<(), Output = f64>>(N);
impl<N: Node<(), Output = f64>> Node<Image> for ImageOpacityNode<N> { impl<N: Node<(), Output = f64>> Node<Image> for OpacityNode<N> {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
image_opacity(image, self.0.eval(()) as f32) image_opacity(image, self.0.eval(()) as f32)
} }
} }
impl<N: Node<(), Output = f64> + Copy> Node<Image> for &ImageOpacityNode<N> { impl<N: Node<(), Output = f64> + Copy> Node<Image> for &OpacityNode<N> {
type Output = Image; type Output = Image;
fn eval(self, image: Image) -> Image { fn eval(self, image: Image) -> Image {
image_opacity(image, self.0.eval(()) as f32) image_opacity(image, self.0.eval(()) as f32)
} }
} }
impl<N: Node<(), Output = f64> + Copy> ImageOpacityNode<N> { impl<N: Node<(), Output = f64> + Copy> OpacityNode<N> {
pub fn new(node: N) -> Self { pub fn new(node: N) -> Self {
Self(node) Self(node)
} }