Browse Source

Merge branch 'export-frames' of git://github.com/belfortk/Babylon.js

David Catuhe 5 years ago
parent
commit
4c12381972

+ 3 - 1
dist/preview release/what's new.md

@@ -14,6 +14,7 @@
 - Simplified code contributions by fully automating the dev setup with gitpod ([nisarhassan12](https://github.com/nisarhassan12))
 - Add a `CascadedShadowMap.IsSupported` method and log an error instead of throwing an exception when CSM is not supported ([Popov72](https://github.com/Popov72))
 
+
 ### Engine
 
 - Allow logging of shader code when a compilation error occurs ([Popov72](https://github.com/Popov72))
@@ -21,7 +22,8 @@
 
 ### NME
 
-- NME Frames are now resizable from the corners ([Kyle Belfort](https://github.com/belfortk)
+- Frames are now resizable from the corners ([Kyle Belfort](https://github.com/belfortk)
+- Can now rename and re-order frame inputs and outputs ([Kyle Belfort](https://github.com/belfortk)
 
 ### Inspector
 

+ 15 - 5
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -16,6 +16,7 @@ import { GraphFrame } from '../../diagram/graphFrame';
 import { TextLineComponent } from '../../sharedComponents/textLineComponent';
 import { Engine } from 'babylonjs/Engines/engine';
 import { FramePropertyTabComponent } from '../../diagram/properties/framePropertyComponent';
+import { NodePortPropertyTabComponent } from '../../diagram/properties/nodePortPropertyComponent';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes';
 import { Color3LineComponent } from '../../sharedComponents/color3LineComponent';
@@ -25,29 +26,32 @@ import { Vector2LineComponent } from '../../sharedComponents/vector2LineComponen
 import { Vector3LineComponent } from '../../sharedComponents/vector3LineComponent';
 import { Vector4LineComponent } from '../../sharedComponents/vector4LineComponent';
 import { Observer } from 'babylonjs/Misc/observable';
+import { NodePort } from '../../diagram/nodePort';
 require("./propertyTab.scss");
 
 interface IPropertyTabComponentProps {
     globalState: GlobalState;
 }
 
-export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<GraphNode>, currentFrame: Nullable<GraphFrame> }> {
+export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<GraphNode>, currentFrame: Nullable<GraphFrame>, currentNodePort: Nullable<NodePort> }> {
     private _onBuiltObserver: Nullable<Observer<void>>;
 
     constructor(props: IPropertyTabComponentProps) {
         super(props)
 
-        this.state = { currentNode: null, currentFrame: null };
+        this.state = { currentNode: null, currentFrame: null, currentNodePort: null };
     }
 
     componentDidMount() {
         this.props.globalState.onSelectionChangedObservable.add(selection => {
             if (selection instanceof GraphNode) {
-                this.setState({ currentNode: selection, currentFrame: null });
+                this.setState({ currentNode: selection, currentFrame: null, currentNodePort: null });
             } else if (selection instanceof GraphFrame) {
-                this.setState({ currentNode: null, currentFrame: selection });
+                this.setState({ currentNode: null, currentFrame: selection, currentNodePort: null });
+            } else if(selection instanceof NodePort) {
+                this.setState({ currentNode: null, currentFrame: null, currentNodePort: selection });
             } else {
-                this.setState({ currentNode: null, currentFrame: null });
+                this.setState({ currentNode: null, currentFrame: null, currentNodePort: null });
             }
         });
 
@@ -171,6 +175,12 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
             );
         }
 
+        if (this.state.currentNodePort) {
+            return (
+                <NodePortPropertyTabComponent globalState={this.props.globalState} nodePort={this.state.currentNodePort}/>
+            );
+        }
+
         let gridSize = DataStorage.ReadNumber("GridSize", 20);
 
         return (

+ 0 - 4
nodeEditor/src/diagram/graphCanvas.scss

@@ -221,10 +221,6 @@
                   border-color: white;
                 }
             }
-            
-            .handle{
-                z-index: 20;
-            }
 
             .right-handle {
                 grid-area: 1 / 2 / 3 / 2;

+ 30 - 3
nodeEditor/src/diagram/graphCanvas.tsx

@@ -45,13 +45,13 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
     private _zoom = 1;
     private _selectedNodes: GraphNode[] = [];
     private _selectedLink: Nullable<NodeLink> = null;
+    private _selectedPort: Nullable<NodePort> = null;
     private _candidateLink: Nullable<NodeLink> = null;
     private _candidatePort: Nullable<NodePort> = null;
     private _gridSize = 20;
     private _selectionBox: Nullable<HTMLDivElement> = null;   
     private _selectedFrame: Nullable<GraphFrame> = null;   
-    private _frameCandidate: Nullable<HTMLDivElement> = null;  
-
+    private _frameCandidate: Nullable<HTMLDivElement> = null;
     private _frames: GraphFrame[] = [];
 
     private _altKeyIsPressed = false;
@@ -132,6 +132,10 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
         return this._selectedFrame;
     }
 
+    public get selectedPort() {
+        return this._selectedPort;
+    }
+
     public get canvasContainer() {
         return this._graphCanvas;
     }
@@ -161,16 +165,19 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
                 this._selectedNodes = [];
                 this._selectedLink = null;
                 this._selectedFrame = null;
+                this._selectedPort = null;
             } else {
                 if (selection instanceof NodeLink) {
                     this._selectedNodes = [];
                     this._selectedFrame = null;
                     this._selectedLink = selection;
+                    this._selectedPort = null;
                 } else if (selection instanceof GraphFrame) {
                     this._selectedNodes = [];
                     this._selectedFrame = selection;
                     this._selectedLink = null;
-                } else{
+                    this._selectedPort = null;
+                } else if (selection instanceof GraphNode){
                     if (this._ctrlKeyIsPressed) {
                         if (this._selectedNodes.indexOf(selection) === -1) {
                             this._selectedNodes.push(selection);
@@ -179,6 +186,12 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
                         this._selectedNodes = [selection];
                     }
                 }
+                else {
+                    this._selectedNodes = [];
+                    this._selectedFrame = null;
+                    this._selectedLink = null;
+                    this._selectedPort = selection;
+                }
             }
         });
 
@@ -186,6 +199,16 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
             this._candidatePort = port;
         });
 
+        props.globalState.onFramePortMoveUpObserver.add((nodePort: NodePort) => {
+            const frame = this._frames.find(frame => frame.id === nodePort.frameId);
+            frame?.moveFramePortUp(nodePort);
+        });
+
+        props.globalState.onFramePortMoveDownObserver.add((nodePort: NodePort) => {
+            const frame = this._frames.find(frame => frame.id === nodePort.frameId);
+            frame?.moveFramePortDown(nodePort);
+        })
+
         props.globalState.onGridSizeChanged.add(() => {
             this.gridSize = DataStorage.ReadNumber("GridSize", 20);
         });
@@ -584,6 +607,10 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
             if (this._candidateLinkedHasMoved) {
                 this.processCandidatePort();          
                 this.props.globalState.onCandidateLinkMoved.notifyObservers(null);
+            } else { // is a click event on NodePort
+                if(this._candidateLink.portA.frameId !== null) { //only on Frame Ports
+                    this.props.globalState.onSelectionChangedObservable.notifyObservers(this._candidateLink.portA);
+                }
             }
             this._candidateLink.dispose();
             this._candidateLink = null;

+ 65 - 12
nodeEditor/src/diagram/graphFrame.ts

@@ -23,6 +23,7 @@ enum ResizingDirection {
 export class GraphFrame {
     private readonly CollapsedWidth = 200;
     private static _FrameCounter = 0;
+    private static _FramePortCounter = 0;
     private _name: string;
     private _color: Color3;
     private _x = 0;
@@ -45,10 +46,10 @@ export class GraphFrame {
     private _ownerCanvas: GraphCanvasComponent;
     private _mouseStartPointX: Nullable<number> = null;
     private _mouseStartPointY: Nullable<number> = null;
-    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame>>>;
+    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame | NodePort>>>;
     private _isCollapsed = false;
-    private _ports: NodePort[] = [];
-    private _controlledPorts: NodePort[] = [];
+    private _ports: NodePort[] = []; // Ports on Outside of Frame
+    private _controlledPorts: NodePort[] = []; // Ports on Nodes that are shown on outside of frame
     private _id: number;
     private _comments: string;
     private _frameIsResizing: boolean;
@@ -72,7 +73,7 @@ export class GraphFrame {
     }
 
     private _createInputPort(port: NodePort, node: GraphNode) {
-        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._inputPortContainer, null, this._ownerCanvas.globalState)
+        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._inputPortContainer, null, this._ownerCanvas.globalState, true, this.id, GraphFrame._FramePortCounter++)
         this._ports.push(localPort);
 
         port.delegatedPort = localPort;
@@ -105,7 +106,7 @@ export class GraphFrame {
 
                                 if (!portAdded) {
                                     portAdded = true;
-                                    localPort = NodePort.CreatePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState);
+                                    localPort = NodePort.CreatePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState, false, this.id, GraphFrame._FramePortCounter++);
                                     this._ports.push(localPort);
                                 } else {
                                     localPort = this._ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
@@ -113,11 +114,11 @@ export class GraphFrame {
 
                                 port.delegatedPort = localPort;
                                 this._controlledPorts.push(port);
-                                link.isVisible = true;
+                                link.isVisible = false;
                             }
                         }
                     } else {
-                        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState)
+                        let localPort = NodePort.CreatePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState, false, this.id, GraphFrame._FramePortCounter++)
                         this._ports.push(localPort);
                         port.delegatedPort = localPort;
                         this._controlledPorts.push(port);
@@ -180,6 +181,10 @@ export class GraphFrame {
         return this._nodes;
     }
 
+    public get ports(){
+        return this._ports;
+    }
+
     public get name() {
         return this._name;
     }
@@ -498,11 +503,6 @@ export class GraphFrame {
         this.x = newX;
         this.y = newY;
 
-        console.log("move():");
-        console.log("oldX: ", oldX);
-        console.log("oldY: ", oldY);
-        console.log("newX: ", newX);
-        console.log("newY: ", oldY);
         for (var selectedNode of this._nodes) {
             selectedNode.x += this.x - oldX;
             selectedNode.y += this.y - oldY;
@@ -549,6 +549,59 @@ export class GraphFrame {
         evt.stopPropagation();
     }
 
+    public moveFramePortUp(nodePort: NodePort){
+        if(nodePort.isInput) {
+            if(this._inputPortContainer.children.length < 2) {
+                return;
+            }
+            const elementsArray = Array.from(this._inputPortContainer.childNodes);
+            this._moveFramePortUp(elementsArray, nodePort);
+        } else {
+            if(this._outputPortContainer.children.length < 2) {
+                return;
+            }
+            const elementsArray = Array.from(this._outputPortContainer.childNodes);
+            this._moveFramePortUp(elementsArray, nodePort);
+        }
+
+    }
+
+    private _moveFramePortUp(elementsArray: ChildNode[], nodePort: NodePort) {
+        const indexInContainer = (elementsArray as HTMLElement[]).findIndex(elem => elem.dataset.framePortId === `${nodePort.framePortId}`)
+        if(indexInContainer === 0){
+            return;
+        }
+        const secondPort = elementsArray[indexInContainer];
+        const firstPort =  elementsArray[indexInContainer -1];
+        firstPort.parentElement?.insertBefore(secondPort, firstPort);
+    }
+    
+    public moveFramePortDown(nodePort: NodePort){
+        if(nodePort.isInput) {
+            if(this._inputPortContainer.children.length < 2) {
+                return;
+            }
+            const elementsArray = Array.from(this._inputPortContainer.childNodes);
+            this._moveFramePortDown(elementsArray, nodePort);
+        } else {
+            if(this._outputPortContainer.children.length < 2) {
+                return;
+            }
+            const elementsArray = Array.from(this._outputPortContainer.childNodes);
+            this._moveFramePortDown(elementsArray, nodePort);
+        }
+    }
+
+    private _moveFramePortDown(elementsArray: ChildNode[], nodePort: NodePort) {
+        const indexInContainer = (elementsArray as HTMLElement[]).findIndex(elem => elem.dataset.framePortId === `${nodePort.framePortId}`)
+        if(indexInContainer === elementsArray.length -1){
+            return;
+        }
+        const firstPort = elementsArray[indexInContainer];
+        const secondPort =  elementsArray[indexInContainer + 1];
+        firstPort.parentElement?.insertBefore(secondPort, firstPort);
+    }
+
     private initResizing = (evt: PointerEvent) => {
         evt.stopPropagation();
         this._mouseStartPointX = evt.clientX;

+ 3 - 3
nodeEditor/src/diagram/graphNode.ts

@@ -31,7 +31,7 @@ export class GraphNode {
     private _mouseStartPointX: Nullable<number> = null;
     private _mouseStartPointY: Nullable<number> = null    
     private _globalState: GlobalState;
-    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame>>>;   
+    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame | NodePort>>>;   
     private _onSelectionBoxMovedObserver: Nullable<Observer<ClientRect | DOMRect>>;  
     private _onFrameCreatedObserver: Nullable<Observer<GraphFrame>>;  
     private _onUpdateRequiredObserver: Nullable<Observer<void>>;  
@@ -407,11 +407,11 @@ export class GraphNode {
 
         // Connections
         for (var input of this.block.inputs) {
-            this._inputPorts.push(NodePort.CreatePortElement(input,  this, this._inputsContainer, this._displayManager, this._globalState));
+            this._inputPorts.push(NodePort.CreatePortElement(input,  this, this._inputsContainer, this._displayManager, this._globalState, true, null, undefined));
         }
 
         for (var output of this.block.outputs) {
-            this._outputPorts.push(NodePort.CreatePortElement(output,  this, this._outputsContainer, this._displayManager, this._globalState));
+            this._outputPorts.push(NodePort.CreatePortElement(output,  this, this._outputsContainer, this._displayManager, this._globalState, false, null, undefined));
         }
 
         this.refresh();

+ 1 - 1
nodeEditor/src/diagram/nodeLink.ts

@@ -13,7 +13,7 @@ export class NodeLink {
     private _nodeB?: GraphNode;
     private _path: SVGPathElement;
     private _selectionPath: SVGPathElement;
-    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame>>>;
+    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphNode | NodeLink | GraphFrame | NodePort>>>;
     private _isVisible = true;
 
     public onDisposedObservable = new Observable<NodeLink>();

+ 38 - 5
nodeEditor/src/diagram/nodePort.ts

@@ -8,12 +8,15 @@ import { Vector2 } from 'babylonjs/Maths/math.vector';
 import { IDisplayManager } from './display/displayManager';
 import { GraphNode } from './graphNode';
 
-
 export class NodePort {
     private _element: HTMLDivElement;
     private _img: HTMLImageElement;
     private _globalState: GlobalState;
     private _onCandidateLinkMovedObserver: Nullable<Observer<Nullable<Vector2>>>;
+    private _portLabel: Element;
+    private _frameId: Nullable<number>
+    private _isInput: boolean;
+    private _framePortId: Nullable<number>;
 
     public delegatedPort: Nullable<NodePort> = null;
 
@@ -25,6 +28,26 @@ export class NodePort {
         return this._element;
     }
 
+    public get frameId() {
+        return this._frameId;
+    }
+
+    public get isInput() {
+        return this._isInput;
+    }
+
+    public get portLabel() {
+        return this._portLabel.innerHTML;
+    }
+
+    public get framePortId() {
+        return this._framePortId;
+    }
+
+    public set portLabel(newLabel: string) {
+        this._portLabel.innerHTML = newLabel;
+    }
+
     public refresh() {
         this._element.style.background = BlockTools.GetColorFromConnectionNodeType(this.connectionPoint.type);
         switch (this.connectionPoint.type) {
@@ -49,12 +72,19 @@ export class NodePort {
         }
     }
 
-    public constructor(portContainer: HTMLElement, public connectionPoint: NodeMaterialConnectionPoint, public node: GraphNode, globalState: GlobalState) {
+    public constructor(portContainer: HTMLElement, public connectionPoint: NodeMaterialConnectionPoint, public node: GraphNode, globalState: GlobalState, isInput: boolean, frameId: Nullable<number>, framePortId: number | undefined) {
         this._element = portContainer.ownerDocument!.createElement("div");
-        this._element.classList.add("port");     
+        this._element.classList.add("port");
         portContainer.appendChild(this._element);
         this._globalState = globalState;
 
+        this._portLabel = portContainer.children[0];
+        this._frameId = frameId
+        this._isInput = isInput;
+        if(framePortId !== undefined) {
+            this._framePortId = framePortId;
+        }
+
         this._img = portContainer.ownerDocument!.createElement("img");
         this._element.appendChild(this._img );
 
@@ -83,11 +113,14 @@ export class NodePort {
     }
 
     public static CreatePortElement(connectionPoint: NodeMaterialConnectionPoint, node: GraphNode, root: HTMLElement, 
-            displayManager: Nullable<IDisplayManager>, globalState: GlobalState) {
+            displayManager: Nullable<IDisplayManager>, globalState: GlobalState, isInput: boolean,  frameId: Nullable<number> = null, framePortId: number | undefined) {
         let portContainer = root.ownerDocument!.createElement("div");
         let block = connectionPoint.ownerBlock;
 
         portContainer.classList.add("portLine");
+        if(framePortId !== null) {
+            portContainer.dataset.framePortId = `${framePortId}`;
+        }
         root.appendChild(portContainer);
 
         if (!displayManager || displayManager.shouldDisplayPortLabels(block)) {
@@ -97,6 +130,6 @@ export class NodePort {
             portContainer.appendChild(portLabel);
         }
     
-        return new NodePort(portContainer, connectionPoint, node, globalState);
+        return new NodePort(portContainer, connectionPoint, node, globalState, isInput, frameId, framePortId);
     }
 }

+ 1 - 3
nodeEditor/src/diagram/properties/framePropertyComponent.tsx

@@ -46,9 +46,7 @@ export class FramePropertyTabComponent extends React.Component<IFramePropertyTab
                 <LineContainerComponent title="GENERAL">
                     <TextInputLineComponent globalState={this.props.globalState} label="Name" propertyName="name" target={this.props.frame} />
                     <Color3LineComponent globalState={this.props.globalState} label="Color" target={this.props.frame} propertyName="color"></Color3LineComponent>
-                    <TextInputLineComponent globalState={this.props.globalState} label="Comments" propertyName="comments" target={this.props.frame}
-                    />
-
+                    <TextInputLineComponent globalState={this.props.globalState} label="Comments" propertyName="comments" target={this.props.frame}/>
                     {
                         !this.props.frame.isCollapsed &&
                         <ButtonLineComponent label="Collapse" onClick={() => {

+ 44 - 0
nodeEditor/src/diagram/properties/nodePortPropertyComponent.tsx

@@ -0,0 +1,44 @@
+
+import * as React from "react";
+import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
+import { GlobalState } from '../../globalState';
+import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
+import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
+import { NodePort } from '../nodePort';
+
+export interface INodePortPropertyTabComponentProps {
+    globalState: GlobalState
+    nodePort: NodePort;
+}
+
+export class NodePortPropertyTabComponent extends React.Component<INodePortPropertyTabComponentProps> {
+
+    constructor(props: INodePortPropertyTabComponentProps) {
+        super(props)
+    }
+
+    render() {      
+        return (
+            <div id="propertyTab">
+            <div id="header">
+                <img id="logo" src="https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" />
+                <div id="title">
+                    NODE MATERIAL EDITOR
+                </div>
+            </div>
+            <div>
+                <LineContainerComponent title="GENERAL">
+                    <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portLabel" target={this.props.nodePort}/>
+                    <ButtonLineComponent label="Move Node Up" onClick={() => {
+                                this.props.globalState.onFramePortMoveUpObserver.notifyObservers(this.props.nodePort);
+                            }} />
+
+                    <ButtonLineComponent label="Move Node Down" onClick={() => {
+                                this.props.globalState.onFramePortMoveDownObserver.notifyObservers(this.props.nodePort);
+                            }} />
+                </LineContainerComponent>
+            </div>
+        </div>
+        );
+    }
+}

+ 3 - 1
nodeEditor/src/globalState.ts

@@ -17,7 +17,7 @@ export class GlobalState {
     hostElement: HTMLElement;
     hostDocument: HTMLDocument;
     hostWindow: Window;
-    onSelectionChangedObservable = new Observable<Nullable<GraphNode | NodeLink | GraphFrame>>();
+    onSelectionChangedObservable = new Observable<Nullable<GraphNode | NodeLink | GraphFrame | NodePort>>();
     onRebuildRequiredObservable = new Observable<void>();
     onBuiltObservable = new Observable<void>();
     onResetRequiredObservable = new Observable<void>();
@@ -37,6 +37,8 @@ export class GlobalState {
     onSelectionBoxMoved = new Observable<ClientRect | DOMRect>();
     onFrameCreated = new Observable<GraphFrame>();
     onCandidatePortSelected = new Observable<Nullable<NodePort>>();
+    onFramePortMoveUpObserver = new Observable<NodePort>();
+    onFramePortMoveDownObserver = new Observable<NodePort>();
     onGetNodeFromBlock: (block: NodeMaterialBlock) => GraphNode;
     onGridSizeChanged = new Observable<void>();
     previewMeshType: PreviewMeshType;