Update Imaginate to output bitmap data to the graph via Image Frame node (#1001)

* Multiple node outputs

* Add new nodes

* gcore use std by default to allow for testing

* Allow multiple node outputs

* Multiple outputs to frontend

* Add ImageFrameNode to node registry

* Minor cleanup

* Basic transform implementation

* Add some logging to image encoding

* Fix ImageFrameNode

* Add transform input to Imaginate node (#1014)

* Add transform input to imaginate node

* Force the resolution to be edited with no transform

* Add transform to imaginate generation

* Fix compilation

---------

Co-authored-by: Keavon Chambers <keavon@keavon.com>

* Add labels to node outputs

* Fix seed; disable mask when transform is disconnected; add Imaginate tooltips

* Rename 'Input Multiple' node to 'Input'

* Code review

* Replicate to Svelte

* Show only the primary input chain in the Properties panel

---------

Co-authored-by: Dennis Kobert <dennis@kobert.dev>
Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
0HyperCube
2023-02-11 00:56:31 -08:00
committed by GitHub
co-authored by Keavon Chambers Dennis Kobert
parent 70f4d60e66
commit e14618b234
35 changed files with 1172 additions and 553 deletions
@@ -92,12 +92,15 @@
}
function resolveLink(link: FrontendNodeLink, containerBounds: HTMLDivElement): { nodePrimaryOutput: HTMLDivElement | undefined; nodePrimaryInput: HTMLDivElement | undefined } {
const connectorIndex = Number(link.linkEndInputIndex);
const outputIndex = Number(link.linkStartOutputIndex);
const inputIndex = Number(link.linkEndInputIndex);
const nodePrimaryOutput = (containerBounds.querySelector(`[data-node="${String(link.linkStart)}"] [data-port="output"]`) || undefined) as HTMLDivElement | undefined;
const nodeOutputConnectors = containerBounds.querySelectorAll(`[data-node="${String(link.linkStart)}"] [data-port="output"]`) || undefined;
const nodeInputConnectors = containerBounds.querySelectorAll(`[data-node="${String(link.linkEnd)}"] [data-port="input"]`) || undefined;
const nodePrimaryInput = nodeInputConnectors?.[connectorIndex] as HTMLDivElement | undefined;
const nodePrimaryOutput = nodeOutputConnectors?.[outputIndex] as HTMLDivElement | undefined;
const nodePrimaryInput = nodeInputConnectors?.[inputIndex] as HTMLDivElement | undefined;
return { nodePrimaryOutput, nodePrimaryInput };
}
@@ -263,8 +266,8 @@
const inputIndexInt = BigInt(inputIndex);
const links = $nodeGraph.links;
const linkIndex = links.findIndex((value) => value.linkEnd === nodeIdInt && value.linkEndInputIndex === inputIndexInt);
const queryString = `[data-node="${String(links[linkIndex].linkStart)}"] [data-port="output"]`;
linkInProgressFromConnector = (nodesContainer.querySelector(queryString) || undefined) as HTMLDivElement | undefined;
const nodeOutputConnectors = nodesContainer.querySelectorAll(`[data-node="${String(links[linkIndex].linkStart)}"] [data-port="output"]`) || undefined;
linkInProgressFromConnector = nodeOutputConnectors?.[Number(links[linkIndex].linkEndInputIndex)] as HTMLDivElement | undefined;
const nodeInputConnectors = nodesContainer.querySelectorAll(`[data-node="${String(links[linkIndex].linkEnd)}"] [data-port="input"]`) || undefined;
linkInProgressToConnector = nodeInputConnectors?.[Number(links[linkIndex].linkEndInputIndex)] as HTMLDivElement | undefined;
disconnecting = { nodeId: nodeIdInt, inputIndex, linkIndex };
@@ -359,13 +362,16 @@
if (outputNode && inputNode && outputConnectedNodeID && inputConnectedNodeID) {
const inputNodeInPorts = Array.from(inputNode.querySelectorAll(`[data-port="input"]`));
const outputNodeInPorts = Array.from(outputNode.querySelectorAll(`[data-port="output"]`));
const inputNodeConnectionIndexSearch = inputNodeInPorts.indexOf(linkInProgressToConnector);
const outputNodeConnectionIndexSearch = outputNodeInPorts.indexOf(linkInProgressFromConnector);
const inputNodeConnectionIndex = inputNodeConnectionIndexSearch > -1 ? inputNodeConnectionIndexSearch : undefined;
const outputNodeConnectionIndex = outputNodeConnectionIndexSearch > -1 ? outputNodeConnectionIndexSearch : undefined;
if (inputNodeConnectionIndex !== undefined) {
// const oneBasedIndex = inputNodeConnectionIndex + 1;
editor.instance.connectNodesByLink(BigInt(outputConnectedNodeID), BigInt(inputConnectedNodeID), inputNodeConnectionIndex);
if (inputNodeConnectionIndex !== undefined && outputNodeConnectionIndex !== undefined) {
editor.instance.connectNodesByLink(BigInt(outputConnectedNodeID), outputNodeConnectionIndex, BigInt(inputConnectedNodeID), inputNodeConnectionIndex);
}
}
} else if (draggingNodes) {
@@ -411,8 +417,8 @@
});
// If the node has been dragged on top of the link then connect it into the middle.
if (link) {
editor.instance.connectNodesByLink(link.linkStart, selectedNodeId, 0);
editor.instance.connectNodesByLink(selectedNodeId, link.linkEnd, Number(link.linkEndInputIndex));
editor.instance.connectNodesByLink(link.linkStart, 0, selectedNodeId, 0);
editor.instance.connectNodesByLink(selectedNodeId, 0, link.linkEnd, Number(link.linkEndInputIndex));
editor.instance.shiftNode(selectedNodeId);
}
}
@@ -482,10 +488,11 @@
{/if}
<div class="nodes" style:transform={`scale(${transform.scale}) translate(${transform.x}px, ${transform.y}px)`} style:transform-origin={`0 0`} bind:this={nodesContainer}>
{#each $nodeGraph.nodes as node (String(node.id))}
{@const exposedInputsOutputs = [...node.exposedInputs, ...node.outputs.slice(1)]}
<div
class="node"
class:selected={selected.includes(node.id)}
class:output={node.output}
class:previewed={node.previewed}
class:disabled={node.disabled}
style:--offset-left={(node.position?.x || 0) + (selected.includes(node.id) ? draggingNodes?.roundX || 0 : 0)}
style:--offset-top={(node.position?.y || 0) + (selected.includes(node.id) ? draggingNodes?.roundY || 0 : 0)}
@@ -508,9 +515,9 @@
<div
class="output port"
data-port="output"
data-datatype={node.outputs[0]}
style:--data-color={`var(--color-data-${node.outputs[0]})`}
style:--data-color-dim={`var(--color-data-${node.outputs[0]}-dim)`}
data-datatype={node.outputs[0].dataType}
style:--data-color={`var(--color-data-${node.outputs[0].dataType})`}
style:--data-color-dim={`var(--color-data-${node.outputs[0].dataType}-dim)`}
>
<div />
</div>
@@ -519,22 +526,34 @@
<IconLabel icon={nodeIcon(node.displayName)} />
<TextLabel>{node.displayName}</TextLabel>
</div>
{#if node.exposedInputs.length > 0}
<div class="arguments">
{#each node.exposedInputs as argument, index (index)}
<div class="argument">
{#if exposedInputsOutputs.length > 0}
<div class="parameters">
{#each exposedInputsOutputs as parameter, index (index)}
<div class="parameter">
<div class="ports">
<div
class="input port"
data-port="input"
data-datatype={argument.dataType}
style:--data-color={`var(--color-data-${argument.dataType})`}
style:--data-color-dim={`var(--color-data-${argument.dataType}-dim)`}
>
<div />
</div>
{#if index < node.exposedInputs.length}
<div
class="input port"
data-port="input"
data-datatype={parameter.dataType}
style:--data-color={`var(--color-data-${parameter.dataType})`}
style:--data-color-dim={`var(--color-data-${parameter.dataType}-dim)`}
>
<div />
</div>
{:else}
<div
class="output port"
data-port="output"
data-datatype={parameter.dataType}
style:--data-color={`var(--color-data-${parameter.dataType})`}
style:--data-color-dim={`var(--color-data-${parameter.dataType}-dim)`}
>
<div />
</div>
{/if}
</div>
<TextLabel>{argument.name}</TextLabel>
<TextLabel class={index < node.exposedInputs.length ? "name" : "output"}>{parameter.name}</TextLabel>
</div>
{/each}
</div>
@@ -656,7 +675,7 @@
}
}
&.output {
&.previewed {
outline: 3px solid var(--color-data-vector);
}
@@ -679,20 +698,28 @@
}
}
.arguments {
.parameters {
display: flex;
flex-direction: column;
width: 100%;
position: relative;
.argument {
.parameter {
position: relative;
display: flex;
align-items: center;
height: 24px;
width: 100%;
width: calc(100% - 24px * 2);
margin-left: 24px;
margin-right: 24px;
.text-label {
width: 100%;
&.output {
text-align: right;
}
}
}
// Squares to cover up the rounded corners of the primary area and make them have a straight edge
@@ -83,6 +83,12 @@ export class NodeGraphInput {
readonly name!: string;
}
export class NodeGraphOutput {
readonly dataType!: FrontendGraphDataType;
readonly name!: string;
}
export class FrontendNode {
readonly id!: bigint;
@@ -92,12 +98,12 @@ export class FrontendNode {
readonly exposedInputs!: NodeGraphInput[];
readonly outputs!: FrontendGraphDataType[];
readonly outputs!: NodeGraphOutput[];
@TupleToVec2
readonly position!: XY | undefined;
readonly output!: boolean;
readonly previewed!: boolean;
readonly disabled!: boolean;
}
@@ -105,6 +111,8 @@ export class FrontendNode {
export class FrontendNodeLink {
readonly linkStart!: bigint;
readonly linkStartOutputIndex!: bigint;
readonly linkEnd!: bigint;
readonly linkEndInputIndex!: bigint;