Skip to content

Commit

Permalink
Replace terminology "primary" with "call argument" and "parameter" wi…
Browse files Browse the repository at this point in the history
…th "secondary input"
  • Loading branch information
Keavon committed Sep 26, 2024
1 parent f8c7ada commit c738b4a
Show file tree
Hide file tree
Showing 15 changed files with 142 additions and 128 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2495,17 +2495,17 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {

let NodeMetadata { display_name, category, fields } = metadata;
let Some(implementations) = &node_registry.get(&id) else { continue };
let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.input.clone()).collect();
let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect();
let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() });
let mut input_type = &first_node_io.input;
let mut input_type = &first_node_io.call_argument;
if valid_inputs.len() > 1 {
input_type = &const { generic!(T) };
}
let output_type = &first_node_io.output;
let output_type = &first_node_io.return_value;

let inputs = fields
.iter()
.zip(first_node_io.parameters.iter())
.zip(first_node_io.inputs.iter())
.enumerate()
.map(|(index, (field, ty))| {
let exposed = if index == 0 { *ty != fn_type!(()) } else { field.exposed };
Expand All @@ -2526,7 +2526,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
let properties = match properties_overrides.get(id.as_str()) {
Some(properties_function) => *properties_function,
None => {
let field_types: Vec<_> = fields.iter().zip(first_node_io.parameters.iter()).map(|(field, ty)| (field.clone(), ty.clone())).collect();
let field_types: Vec<_> = fields.iter().zip(first_node_io.inputs.iter()).map(|(field, ty)| (field.clone(), ty.clone())).collect();
let properties = move |document_node: &DocumentNode, node_id: NodeId, context: &mut NodePropertiesContext| {
let rows: Vec<_> = field_types
.iter()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ impl NodeNetworkInterface {
}
}
DocumentNodeImplementation::ProtoNode(_) => {
// If a node has manual composition, then offset the input index by 1 since the proto node also includes the type of the parameter passed through manual composition.
// If a node has manual composition, then offset the input index by 1 since the proto node also includes the type of the input passed through manual composition.
let manual_composition_offset = if node.manual_composition.is_some() { 1 } else { 0 };
self.resolved_types
.types
Expand Down Expand Up @@ -552,7 +552,7 @@ impl NodeNetworkInterface {

let skip_footprint = if node.manual_composition.is_some() { 1 } else { 0 };

let Some(input_type) = std::iter::once(node_types.input.clone()).chain(node_types.parameters.clone()).nth(input_index + skip_footprint) else {
let Some(input_type) = std::iter::once(node_types.call_argument.clone()).chain(node_types.inputs.clone()).nth(input_index + skip_footprint) else {
log::error!("Could not get type");
return (concrete!(()), TypeSource::Error("could not get the protonode's input"));
};
Expand Down Expand Up @@ -678,7 +678,7 @@ impl NodeNetworkInterface {
let node_id_path = &[network_path, &[*node_id]].concat();
let primary_output_type = self.resolved_types.types.get(node_id_path).map(|ty| (ty.output.clone(), TypeSource::Compiled)).or_else(|| {
let node_types = random_protonode_implementation(protonode)?;
Some((node_types.output.clone(), TypeSource::RandomProtonodeImplementation))
Some((node_types.return_value.clone(), TypeSource::RandomProtonodeImplementation))
});

output_types.push(primary_output_type);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ pub fn get_blend_mode(layer: LayerNodeIdentifier, network_interface: &NodeNetwor
/// Get the current opacity of a layer from the closest Opacity node.
/// This may differ from the actual opacity contained within the data type reaching this layer, because that actual opacity may be:
/// - Multiplied with additional opacity nodes earlier in the chain
/// - Set by an Opacity node with an exposed parameter value driven by another node
/// - Set by an Opacity node with an exposed input value driven by another node
/// - Already factored into the pixel alpha channel of an image
/// - The default value of 100% if no Opacity node is present, but this function returns None in that case
///
Expand Down
2 changes: 1 addition & 1 deletion editor/src/messages/tool/tool_messages/brush_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,7 +330,7 @@ impl Fsm for BrushToolFsmState {

let layer_document_scale = document.metadata().transform_to_document(parent) * tool_data.transform;

// TODO: Also scale it based on the input image ('Background' parameter).
// TODO: Also scale it based on the input image ('Background' input).
// TODO: Resizing the input image results in a different brush size from the chosen diameter.
let layer_scale = 0.0001_f64 // Safety against division by zero
.max((layer_document_scale.matrix2 * glam::DVec2::X).length())
Expand Down
54 changes: 27 additions & 27 deletions frontend/src/components/views/Graph.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -280,20 +280,20 @@
editor.handle.createNode(nodeType, $nodeGraph.contextMenuInformation.contextMenuCoordinates.x, $nodeGraph.contextMenuInformation.contextMenuCoordinates.y);
}
function nodeBorderMask(nodeWidth: number, primaryInputExists: boolean, parameters: number, primaryOutputExists: boolean, exposedOutputs: number): string {
const nodeHeight = Math.max(1 + parameters, 1 + exposedOutputs) * 24;
function nodeBorderMask(nodeWidth: number, primaryInputExists: boolean, exposedSecondaryInputs: number, primaryOutputExists: boolean, exposedSecondaryOutputs: number): string {
const nodeHeight = Math.max(1 + exposedSecondaryInputs, 1 + exposedSecondaryOutputs) * 24;
const boxes: { x: number; y: number; width: number; height: number }[] = [];
// Primary input
if (primaryInputExists) boxes.push({ x: -8, y: 4, width: 16, height: 16 });
// Parameter inputs
for (let i = 0; i < parameters; i++) boxes.push({ x: -8, y: 4 + (i + 1) * 24, width: 16, height: 16 });
// Secondary inputs
for (let i = 0; i < exposedSecondaryInputs; i++) boxes.push({ x: -8, y: 4 + (i + 1) * 24, width: 16, height: 16 });
// Primary output
if (primaryOutputExists) boxes.push({ x: nodeWidth - 8, y: 4, width: 16, height: 16 });
// Exposed outputs
for (let i = 0; i < exposedOutputs; i++) boxes.push({ x: nodeWidth - 8, y: 4 + (i + 1) * 24, width: 16, height: 16 });
for (let i = 0; i < exposedSecondaryOutputs; i++) boxes.push({ x: nodeWidth - 8, y: 4 + (i + 1) * 24, width: 16, height: 16 });
return borderMask(boxes, nodeWidth, nodeHeight);
}
Expand Down Expand Up @@ -704,17 +704,17 @@
<span class="node-error hover" transition:fade={FADE_TRANSITION} data-node-error>{node.errors}</span>
{/if}
<!-- Primary row -->
<div class="primary" class:in-selected-network={$nodeGraph.inSelectedNetwork} class:no-parameter-section={exposedInputsOutputs.length === 0}>
<div class="primary" class:in-selected-network={$nodeGraph.inSelectedNetwork} class:no-secondary-section={exposedInputsOutputs.length === 0}>
<IconLabel icon={nodeIcon(node.reference)} />
<!-- TODO: Allow the user to edit the name, just like in the Layers panel -->
<TextLabel tooltip={editor.handle.inDevelopmentMode() ? `Node ID: ${node.id}` : undefined}>{node.displayName}</TextLabel>
</div>
<!-- Parameter rows -->
<!-- Secondary rows -->
{#if exposedInputsOutputs.length > 0}
<div class="parameters" class:in-selected-network={$nodeGraph.inSelectedNetwork}>
{#each exposedInputsOutputs as parameter, index}
<div class={`parameter expanded ${index < node.exposedInputs.length ? "input" : "output"}`}>
<TextLabel tooltip={parameter.name}>{parameter.name}</TextLabel>
<div class="secondary" class:in-selected-network={$nodeGraph.inSelectedNetwork}>
{#each exposedInputsOutputs as secondary, index}
<div class={`secondary-row expanded ${index < node.exposedInputs.length ? "input" : "output"}`}>
<TextLabel tooltip={secondary.name}>{secondary.name}</TextLabel>
</div>
{/each}
</div>
Expand All @@ -740,20 +740,20 @@
{/if}
</svg>
{/if}
{#each node.exposedInputs as parameter, index}
{#each node.exposedInputs as secondary, index}
{#if index < node.exposedInputs.length}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 8 8"
class="port"
data-port="input"
data-datatype={parameter.dataType}
style:--data-color={`var(--color-data-${parameter.dataType.toLowerCase()})`}
style:--data-color-dim={`var(--color-data-${parameter.dataType.toLowerCase()}-dim)`}
data-datatype={secondary.dataType}
style:--data-color={`var(--color-data-${secondary.dataType.toLowerCase()})`}
style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`}
bind:this={inputs[nodeIndex + 1][index + (node.primaryInput ? 1 : 0)]}
>
<title>{`${dataTypeTooltip(parameter)}\n${inputConnectedToText(parameter)}`}</title>
{#if parameter.connectedTo !== undefined}
<title>{`${dataTypeTooltip(secondary)}\n${inputConnectedToText(secondary)}`}</title>
{#if secondary.connectedTo !== undefined}
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
{:else}
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" />
Expand Down Expand Up @@ -783,19 +783,19 @@
{/if}
</svg>
{/if}
{#each node.exposedOutputs as parameter, outputIndex}
{#each node.exposedOutputs as secondary, outputIndex}
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 8 8"
class="port"
data-port="output"
data-datatype={parameter.dataType}
style:--data-color={`var(--color-data-${parameter.dataType.toLowerCase()})`}
style:--data-color-dim={`var(--color-data-${parameter.dataType.toLowerCase()}-dim)`}
data-datatype={secondary.dataType}
style:--data-color={`var(--color-data-${secondary.dataType.toLowerCase()})`}
style:--data-color-dim={`var(--color-data-${secondary.dataType.toLowerCase()}-dim)`}
bind:this={outputs[nodeIndex + 1][outputIndex + (node.primaryOutput ? 1 : 0)]}
>
<title>{`${dataTypeTooltip(parameter)}\n${outputConnectedToText(parameter)}`}</title>
{#if parameter.connectedTo !== undefined}
<title>{`${dataTypeTooltip(secondary)}\n${outputConnectedToText(secondary)}`}</title>
{#if secondary.connectedTo !== undefined}
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color)" />
{:else}
<path d="M0,6.306A1.474,1.474,0,0,0,2.356,7.724L7.028,5.248c1.3-.687,1.3-1.809,0-2.5L2.356.276A1.474,1.474,0,0,0,0,1.694Z" fill="var(--data-color-dim)" />
Expand Down Expand Up @@ -1300,7 +1300,7 @@
}
}
.parameters {
.secondary {
background: rgba(var(--color-f-white-rgb), 0.1);
&.in-selected-network {
Expand Down Expand Up @@ -1332,7 +1332,7 @@
border-radius: 2px 2px 0 0;
background: rgba(var(--color-f-white-rgb), 0.05);
&.no-parameter-section {
&.no-secondary-section {
border-radius: 2px;
}
Expand All @@ -1347,13 +1347,13 @@
}
}
.parameters {
.secondary {
display: flex;
flex-direction: column;
width: 100%;
position: relative;
.parameter {
.secondary-row {
position: relative;
display: flex;
align-items: center;
Expand Down
10 changes: 5 additions & 5 deletions node-graph/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ The `graphene_core::value::CopiedNode` is a node that, when evaluated, copies `1

## Creating a new node

Instead of manually implementing the `Node` trait with complex generics, one can use the `node` macro, which can be applied to a function like `opacity`. This will generate the struct, implementation, node_registry entry, doucment node definition and properties panel entries:
Instead of manually implementing the `Node` trait with complex generics, one can use the `node` macro, which can be applied to a function like `opacity`. This will generate the struct, implementation, node_registry entry, document node definition and properties panel entries:

```rs
#[node_macro::node(category("Raster: Adjustments"))]
Expand All @@ -115,10 +115,10 @@ The macro invocation can be extended with additional attributes. The currently s
## Executing a document `NodeNetwork`

When the document graph is executed, the following steps occur:
- The `NodeNetwork` is flattened using `NodeNetwork::flatten`. This involves removing any `DocumentNodeImplementation::Network` - which allow for nested document node networks (not currently exposed in the UI). Instead, all of the inner nodes are moved into a single node graph.
- The `NodeNetwork` is converted into a proto-graph, which separates out the primary input from the secondary inputs. The secondary inputs are stored as a list of node ids in the `ConstructionArgs` struct in the `ProtoNode`. Converting a document graph into a proto graph is done with `NodeNetwork::into_proto_networks`.
- The `NodeNetwork` is flattened using `NodeNetwork::flatten`. This involves removing any `DocumentNodeImplementation::Network` - which allow for nested document node networks. Instead, all of the inner nodes are moved into a single node graph.
- The `NodeNetwork` is converted into a proto-graph. Each node's inputs are stored as a list of node IDs in the `ConstructionArgs` struct in the `ProtoNode`. Converting a document graph into a proto graph is done with `NodeNetwork::into_proto_networks`.
- The newly created `ProtoNode`s are then converted into the corresponding constructor functions using the mapping defined in `node-graph/interpreted-executor/src/node_registry.rs`. This is done by `BorrowTree::push_node`.
- The constructor functions are run with the `ConstructionArgs` enum. Constructors generally evaluate the result of these secondary inputs e.g. if you have a `Pi` node that is used as the second input to an `Add` node, the `Add` node's constructor will evaluate the `Pi` node. This is visible if you place a log statement in the `Pi` node's implementation.
- The constructor functions are run with the `ConstructionArgs` enum. Constructors generally evaluate the result of these inputs, e.g. if you have a `Pi` node that is used as the second input to an `Add` node, the `Add` node's constructor will evaluate the `Pi` node. This is visible if you place a log statement in the `Pi` node's implementation.
- The resolved functions are stored in a `BorrowTree`, which allows previous proto-nodes to be referenced as inputs by later nodes. The `BorrowTree` ensures nodes can't be removed while being referenced by other nodes.

The definition for the constructor of a node that applies the opacity transformation to each pixel of an image:
Expand All @@ -141,7 +141,7 @@ The definition for the constructor of a node that applies the opacity transforma
any.into_type_erased()
})
},
// Defines the input, output, and parameters (where each parameter is a function taking in some input and returning another input).
// Defines the call argument, return value, and inputs.
NodeIOTypes::new(concrete!(Image<Color>), concrete!(Image<Color>), vec![fn_type!((), f64))]),
),
```
Expand Down
16 changes: 8 additions & 8 deletions node-graph/gcore/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,24 +96,24 @@ where
core::any::type_name::<Self::Output>()
}
#[cfg(feature = "alloc")]
fn to_node_io(&self, parameters: Vec<Type>) -> NodeIOTypes {
fn to_node_io(&self, inputs: Vec<Type>) -> NodeIOTypes {
NodeIOTypes {
input: concrete!(<Input as StaticTypeSized>::Static),
output: concrete!(<Self::Output as StaticTypeSized>::Static),
parameters,
call_argument: concrete!(<Input as StaticTypeSized>::Static),
return_value: concrete!(<Self::Output as StaticTypeSized>::Static),
inputs,
}
}
#[cfg(feature = "alloc")]
fn to_async_node_io(&self, parameters: Vec<Type>) -> NodeIOTypes
fn to_async_node_io(&self, inputs: Vec<Type>) -> NodeIOTypes
where
<Self::Output as Future>::Output: StaticTypeSized,
Self::Output: Future,
{
NodeIOTypes {
input: concrete!(<Input as StaticTypeSized>::Static),
call_argument: concrete!(<Input as StaticTypeSized>::Static),
// TODO return actual future type
output: concrete!(<<Self::Output as Future>::Output as StaticTypeSized>::Static),
parameters,
return_value: concrete!(<<Self::Output as Future>::Output as StaticTypeSized>::Static),
inputs,
}
}
}
Expand Down
22 changes: 11 additions & 11 deletions node-graph/gcore/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ macro_rules! fn_type {

#[derive(Clone, PartialEq, Eq, Hash, Default)]
pub struct NodeIOTypes {
pub input: Type,
pub output: Type,
pub parameters: Vec<Type>,
pub call_argument: Type,
pub return_value: Type,
pub inputs: Vec<Type>,
}

impl NodeIOTypes {
pub const fn new(input: Type, output: Type, parameters: Vec<Type>) -> Self {
Self { input, output, parameters }
pub const fn new(call_argument: Type, return_value: Type, inputs: Vec<Type>) -> Self {
Self { call_argument, return_value, inputs }
}

pub const fn empty() -> Self {
Expand All @@ -96,23 +96,23 @@ impl NodeIOTypes {
align: 0,
};
Self {
input: Type::Concrete(tds1),
output: Type::Concrete(tds2),
parameters: Vec::new(),
call_argument: Type::Concrete(tds1),
return_value: Type::Concrete(tds2),
inputs: Vec::new(),
}
}

pub fn ty(&self) -> Type {
Type::Fn(Box::new(self.input.clone()), Box::new(self.output.clone()))
Type::Fn(Box::new(self.call_argument.clone()), Box::new(self.return_value.clone()))
}
}

impl core::fmt::Debug for NodeIOTypes {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_fmt(format_args!(
"node({}) -> {}",
[&self.input].into_iter().chain(&self.parameters).map(|input| input.to_string()).collect::<Vec<_>>().join(", "),
self.output
[&self.call_argument].into_iter().chain(&self.inputs).map(|input| input.to_string()).collect::<Vec<_>>().join(", "),
self.return_value
))
}
}
Expand Down
Loading

0 comments on commit c738b4a

Please sign in to comment.