Bläddra i källkod

Associated with #6012 - Store node position when serializing

David Catuhe 6 år sedan
förälder
incheckning
8792db49c2

+ 38 - 4
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -8,6 +8,7 @@ import { LineContainerComponent } from '../../sharedComponents/lineContainerComp
 import { StringTools } from '../../stringTools';
 import { StringTools } from '../../stringTools';
 import { FileButtonLineComponent } from '../../sharedComponents/fileButtonLineComponent';
 import { FileButtonLineComponent } from '../../sharedComponents/fileButtonLineComponent';
 import { Tools } from 'babylonjs/Misc/tools';
 import { Tools } from 'babylonjs/Misc/tools';
+import { INodeLocationInfo } from '../../nodeLocationInfo';
 require("./propertyTab.scss");
 require("./propertyTab.scss");
 
 
 interface IPropertyTabComponentProps {
 interface IPropertyTabComponentProps {
@@ -34,11 +35,45 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
             let serializationObject = JSON.parse(decoder.decode(data));
             let serializationObject = JSON.parse(decoder.decode(data));
 
 
             this.props.globalState.nodeMaterial!.loadFromSerialization(serializationObject, "");
             this.props.globalState.nodeMaterial!.loadFromSerialization(serializationObject, "");
+
+            // Check for id mapping
+            if (serializationObject.locations && serializationObject.map) {
+                let map: {[key: number]: number} = serializationObject.map;
+                let locations: INodeLocationInfo[] = serializationObject.locations;
+
+                for (var location of locations) {
+                    location.blockId = map[location.blockId];
+                }
+            }
             
             
-            this.props.globalState.onResetRequiredObservable.notifyObservers();
+            this.props.globalState.onResetRequiredObservable.notifyObservers(serializationObject.locations);
         }, undefined, true);
         }, undefined, true);
     }
     }
 
 
+    save() {
+        let material = this.props.globalState.nodeMaterial;
+        let serializationObject = material.serialize();
+
+        // Store node locations
+        for (var block of material.attachedBlocks) {
+            let node = this.props.globalState.onGetNodeFromBlock(block);
+
+            if (!serializationObject.locations) {
+                serializationObject.locations = [];
+            }
+
+            serializationObject.locations.push({
+                blockId: block.uniqueId,
+                x: node.x,
+                y: node.y
+            });
+        }
+
+        // Output
+        let json = JSON.stringify(serializationObject, undefined, 2);
+        StringTools.DownloadAsFile(json, "nodeMaterial.json");
+    }
+
     render() {
     render() {
         if (this.state.currentNode) {
         if (this.state.currentNode) {
             return (
             return (
@@ -66,7 +101,7 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                     <LineContainerComponent title="GENERAL">
                     <LineContainerComponent title="GENERAL">
                         <ButtonLineComponent label="Reset to default" onClick={() => {
                         <ButtonLineComponent label="Reset to default" onClick={() => {
                             this.props.globalState.nodeMaterial!.setToDefault();
                             this.props.globalState.nodeMaterial!.setToDefault();
-                            this.props.globalState.onResetRequiredObservable.notifyObservers();
+                            this.props.globalState.onResetRequiredObservable.notifyObservers(null);
                         }} />
                         }} />
                     </LineContainerComponent>
                     </LineContainerComponent>
                     <LineContainerComponent title="UI">
                     <LineContainerComponent title="UI">
@@ -80,8 +115,7 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                     <LineContainerComponent title="FILE">                        
                     <LineContainerComponent title="FILE">                        
                         <FileButtonLineComponent label="Load" onClick={(file) => this.load(file)} accept=".json" />
                         <FileButtonLineComponent label="Load" onClick={(file) => this.load(file)} accept=".json" />
                         <ButtonLineComponent label="Save" onClick={() => {
                         <ButtonLineComponent label="Save" onClick={() => {
-                            let json = JSON.stringify(this.props.globalState.nodeMaterial!.serialize(), undefined, 2);
-                            StringTools.DownloadAsFile(json, "nodeMaterial.json");
+                            this.save();
                         }} />
                         }} />
                         <ButtonLineComponent label="Export shaders" onClick={() => {
                         <ButtonLineComponent label="Export shaders" onClick={() => {
                             StringTools.DownloadAsFile(this.props.globalState.nodeMaterial!.compiledShaders, "shaders.txt");
                             StringTools.DownloadAsFile(this.props.globalState.nodeMaterial!.compiledShaders, "shaders.txt");

+ 5 - 1
nodeEditor/src/globalState.ts

@@ -3,6 +3,9 @@ import { Nullable } from "babylonjs/types"
 import { Observable } from 'babylonjs/Misc/observable';
 import { Observable } from 'babylonjs/Misc/observable';
 import { DefaultNodeModel } from './components/diagram/defaultNodeModel';
 import { DefaultNodeModel } from './components/diagram/defaultNodeModel';
 import { LogEntry } from './components/log/logComponent';
 import { LogEntry } from './components/log/logComponent';
+import { NodeMaterialBlock } from 'babylonjs';
+import { NodeModel } from 'storm-react-diagrams';
+import { INodeLocationInfo } from './nodeLocationInfo';
 
 
 export class GlobalState {
 export class GlobalState {
     nodeMaterial: NodeMaterial;
     nodeMaterial: NodeMaterial;
@@ -10,10 +13,11 @@ export class GlobalState {
     hostDocument: HTMLDocument;
     hostDocument: HTMLDocument;
     onSelectionChangedObservable = new Observable<Nullable<DefaultNodeModel>>();
     onSelectionChangedObservable = new Observable<Nullable<DefaultNodeModel>>();
     onRebuildRequiredObservable = new Observable<void>();
     onRebuildRequiredObservable = new Observable<void>();
-    onResetRequiredObservable = new Observable<void>();
+    onResetRequiredObservable = new Observable<Nullable<INodeLocationInfo[]>>();
     onUpdateRequiredObservable = new Observable<void>();
     onUpdateRequiredObservable = new Observable<void>();
     onZoomToFitRequiredObservable = new Observable<void>();
     onZoomToFitRequiredObservable = new Observable<void>();
     onReOrganizedRequiredObservable = new Observable<void>();
     onReOrganizedRequiredObservable = new Observable<void>();
     onLogRequiredObservable = new Observable<LogEntry>();
     onLogRequiredObservable = new Observable<LogEntry>();
     onErrorMessageDialogRequiredObservable = new Observable<string>();
     onErrorMessageDialogRequiredObservable = new Observable<string>();
+    onGetNodeFromBlock: (block: NodeMaterialBlock) => NodeModel;
 }
 }

+ 34 - 15
nodeEditor/src/graphEditor.tsx

@@ -38,6 +38,7 @@ import { RemapNodeModel } from './components/diagram/remap/remapNodeModel';
 import { RemapBlock } from 'babylonjs/Materials/Node/Blocks/remapBlock';
 import { RemapBlock } from 'babylonjs/Materials/Node/Blocks/remapBlock';
 import { GraphHelper } from './graphHelper';
 import { GraphHelper } from './graphHelper';
 import { PreviewManager } from './previewManager';
 import { PreviewManager } from './previewManager';
+import { INodeLocationInfo } from './nodeLocationInfo';
 
 
 require("storm-react-diagrams/dist/style.min.css");
 require("storm-react-diagrams/dist/style.min.css");
 require("./main.scss");
 require("./main.scss");
@@ -164,8 +165,8 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
             this.forceUpdate();
             this.forceUpdate();
         });
         });
 
 
-        this.props.globalState.onResetRequiredObservable.add(() => {
-            this.build();
+        this.props.globalState.onResetRequiredObservable.add((locations) => {
+            this.build(false, locations);
             if (this.props.globalState.nodeMaterial) {
             if (this.props.globalState.nodeMaterial) {
                 this.buildMaterial();
                 this.buildMaterial();
             }
             }
@@ -181,7 +182,11 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
 
 
         this.props.globalState.onReOrganizedRequiredObservable.add(() => {
         this.props.globalState.onReOrganizedRequiredObservable.add(() => {
             this.reOrganize();
             this.reOrganize();
-        })
+        });
+
+        this.props.globalState.onGetNodeFromBlock = (block) => {
+            return this._nodes.filter(n => n.block === block)[0];
+        }
 
 
         this.build(true);
         this.build(true);
     }
     }
@@ -220,9 +225,11 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
         }
         }
     }
     }
 
 
-    build(needToWait = false) {
+    build(needToWait = false, locations: Nullable<INodeLocationInfo[]> = null) {
         // setup the diagram model
         // setup the diagram model
         this._model = new DiagramModel();
         this._model = new DiagramModel();
+        this._nodes = [];
+        this._blocks = [];
 
 
         // Listen to events
         // Listen to events
         this._model.addListener({
         this._model.addListener({
@@ -357,23 +364,35 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
 
 
             this.forceUpdate();
             this.forceUpdate();
 
 
-            this.reOrganize();
+            this.reOrganize(locations);
         }, needToWait ? 500 : 1);
         }, needToWait ? 500 : 1);
     }
     }
 
 
-    reOrganize() {
-        let nodes = GraphHelper.DistributeGraph(this._model);
-        nodes.forEach(node => {
-            for (var nodeName in this._model.nodes) {
-                let modelNode = this._model.nodes[nodeName];
+    reOrganize(locations: Nullable<INodeLocationInfo[]> = null) {
+        if (!locations) {
+            let nodes = GraphHelper.DistributeGraph(this._model);
+            nodes.forEach(node => {
+                for (var nodeName in this._model.nodes) {
+                    let modelNode = this._model.nodes[nodeName];
 
 
-                if (modelNode.id === node.id) {
-                    modelNode.setPosition(node.x - node.width / 2, node.y - node.height / 2);
-                    return;
+                    if (modelNode.id === node.id) {
+                        modelNode.setPosition(node.x - node.width / 2, node.y - node.height / 2);
+                        return;
+                    }
+                }
+            });
+        } else {
+            for (var location of locations) {
+                for (var node of this._nodes) {
+                    if (node.block && node.block.uniqueId === location.blockId) {
+                        node.setPosition(location.x, location.y);
+                        break;
+                    }
                 }
                 }
             }
             }
-        });
-        this.forceUpdate();
+        }
+
+        this._engine.repaintCanvas();
     }
     }
 
 
     onPointerDown(evt: React.PointerEvent<HTMLDivElement>) {
     onPointerDown(evt: React.PointerEvent<HTMLDivElement>) {

+ 5 - 0
nodeEditor/src/nodeLocationInfo.ts

@@ -0,0 +1,5 @@
+export interface INodeLocationInfo {
+    blockId: number;
+    x: number;
+    y: number;
+}

+ 7 - 0
src/Materials/Node/nodeMaterial.ts

@@ -995,6 +995,13 @@ export class NodeMaterial extends PushMaterial {
         for (var outputNodeId of source.outputNodes) {
         for (var outputNodeId of source.outputNodes) {
             this.addOutputNode(map[outputNodeId]);
             this.addOutputNode(map[outputNodeId]);
         }
         }
+
+        // Store map for external uses
+        source.map = {};
+
+        for (var key in map) {
+            source.map[key] = map[key].uniqueId;
+        }
     }
     }
 
 
     /**
     /**