Prechádzať zdrojové kódy

Update Node material editor + add link from node material itself

David Catuhe 6 rokov pred
rodič
commit
ed65c5927b
41 zmenil súbory, kde vykonal 2186 pridanie a 2010 odobranie
  1. 19 0
      Playground/babylon.d.txt
  2. 19 0
      dist/preview release/babylon.d.ts
  3. 1 1
      dist/preview release/babylon.js
  4. 88 42
      dist/preview release/babylon.max.js
  5. 1 1
      dist/preview release/babylon.max.js.map
  6. 38 0
      dist/preview release/babylon.module.d.ts
  7. 19 0
      dist/preview release/documentation.d.ts
  8. 2 2
      dist/preview release/inspector/babylon.inspector.bundle.js
  9. 57 7
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  10. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  11. 14 0
      dist/preview release/inspector/babylon.inspector.d.ts
  12. 34 0
      dist/preview release/inspector/babylon.inspector.module.d.ts
  13. 147 114
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  14. 7 7
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  15. 461 286
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  16. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  17. 328 263
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  18. 38 0
      dist/preview release/viewer/babylon.module.d.ts
  19. 7 7
      dist/preview release/viewer/babylon.viewer.js
  20. 1 1
      dist/preview release/viewer/babylon.viewer.max.js
  21. 12 0
      inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx
  22. 42 0
      inspector/src/components/actionTabs/tabs/propertyGrids/materials/nodeMaterialPropertyGridComponent.tsx
  23. 0 162
      nodeEditor/src/components/customDiragramNodes/generic/genericNodeWidget.tsx
  24. 37 0
      nodeEditor/src/components/diagram/diagram.scss
  25. 14 9
      nodeEditor/src/components/customDiragramNodes/generic/genericNodeFactory.tsx
  26. 0 0
      nodeEditor/src/components/diagram/generic/genericNodeModel.ts
  27. 117 0
      nodeEditor/src/components/diagram/generic/genericNodeWidget.tsx
  28. 0 0
      nodeEditor/src/components/diagram/generic/genericPortModel.ts
  29. 113 166
      nodeEditor/src/components/graphEditor.tsx
  30. 21 888
      nodeEditor/src/components/main.scss
  31. 123 0
      nodeEditor/src/components/nodeList/nodeList.scss
  32. 71 0
      nodeEditor/src/components/nodeList/nodeListComponent.tsx
  33. 56 0
      nodeEditor/src/components/propertyTab/properties/texturePropertyTabComponent.tsx
  34. 19 0
      nodeEditor/src/components/propertyTab/properties/vector2PropertyTabComponent.tsx
  35. 120 0
      nodeEditor/src/components/propertyTab/propertyTab.scss
  36. 50 0
      nodeEditor/src/components/propertyTab/propertyTabComponent.tsx
  37. 8 4
      nodeEditor/src/globalState.ts
  38. 8 8
      nodeEditor/src/nodeEditor.ts
  39. 2 25
      nodeEditor/src/sharedComponents/lineContainerComponent.tsx
  40. 25 15
      nodeEditor/src/sharedComponents/popup.ts
  41. 65 0
      src/Materials/Node/nodeMaterial.ts

+ 19 - 0
Playground/babylon.d.txt

@@ -49429,6 +49429,13 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    /**
+     * Interface used to configure the node material editor
+     */
+    export interface INodeMaterialEditorOptions {
+        /** Define the URl to load Node Editor resources */
+        editorURL?: string;
+    }
     /** @hidden */
     export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         /** BONES */
@@ -49481,6 +49488,10 @@ declare module BABYLON {
         private _cachedWorldViewProjectionMatrix;
         private _textureConnectionPoints;
         private _optimizers;
+        static EditorURL: string;
+        private BJSNODEMATERIALEDITOR;
+        /** Get the inspector from bundle or global */
+        private _getGlobalNodeMaterialEditor;
         /**
         * Defines the maximum number of lights that can be used in the material
         */
@@ -49620,6 +49631,14 @@ declare module BABYLON {
          * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
          */
         dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, notBoundToMesh?: boolean): void;
+        /** Creates the node editor window. */
+        private _createNodeEditor;
+        /**
+         * Launch the node material editor
+         * @param config Define the configuration of the editor
+         * @return a promise fulfilled when the node editor is visible
+         */
+        edit(config?: INodeMaterialEditorOptions): Promise<void>;
     }
 }
 declare module BABYLON {

+ 19 - 0
dist/preview release/babylon.d.ts

@@ -50210,6 +50210,13 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    /**
+     * Interface used to configure the node material editor
+     */
+    export interface INodeMaterialEditorOptions {
+        /** Define the URl to load Node Editor resources */
+        editorURL?: string;
+    }
     /** @hidden */
     export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         /** BONES */
@@ -50262,6 +50269,10 @@ declare module BABYLON {
         private _cachedWorldViewProjectionMatrix;
         private _textureConnectionPoints;
         private _optimizers;
+        static EditorURL: string;
+        private BJSNODEMATERIALEDITOR;
+        /** Get the inspector from bundle or global */
+        private _getGlobalNodeMaterialEditor;
         /**
         * Defines the maximum number of lights that can be used in the material
         */
@@ -50403,6 +50414,14 @@ declare module BABYLON {
          * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
          */
         dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, notBoundToMesh?: boolean): void;
+        /** Creates the node editor window. */
+        private _createNodeEditor;
+        /**
+         * Launch the node material editor
+         * @param config Define the configuration of the editor
+         * @return a promise fulfilled when the node editor is visible
+         */
+        edit(config?: INodeMaterialEditorOptions): Promise<void>;
     }
 }
 declare module BABYLON {

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/babylon.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 88 - 42
dist/preview release/babylon.max.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/babylon.max.js.map


+ 38 - 0
dist/preview release/babylon.module.d.ts

@@ -52444,6 +52444,13 @@ declare module "babylonjs/Materials/Node/nodeMaterial" {
     import { NodeMaterialOptimizer } from "babylonjs/Materials/Node/Optimizers/nodeMaterialOptimizer";
     import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from "babylonjs/Materials/imageProcessingConfiguration";
     import { Nullable } from "babylonjs/types";
+    /**
+     * Interface used to configure the node material editor
+     */
+    export interface INodeMaterialEditorOptions {
+        /** Define the URl to load Node Editor resources */
+        editorURL?: string;
+    }
     /** @hidden */
     export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         /** BONES */
@@ -52496,6 +52503,10 @@ declare module "babylonjs/Materials/Node/nodeMaterial" {
         private _cachedWorldViewProjectionMatrix;
         private _textureConnectionPoints;
         private _optimizers;
+        static EditorURL: string;
+        private BJSNODEMATERIALEDITOR;
+        /** Get the inspector from bundle or global */
+        private _getGlobalNodeMaterialEditor;
         /**
         * Defines the maximum number of lights that can be used in the material
         */
@@ -52637,6 +52648,14 @@ declare module "babylonjs/Materials/Node/nodeMaterial" {
          * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
          */
         dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, notBoundToMesh?: boolean): void;
+        /** Creates the node editor window. */
+        private _createNodeEditor;
+        /**
+         * Launch the node material editor
+         * @param config Define the configuration of the editor
+         * @return a promise fulfilled when the node editor is visible
+         */
+        edit(config?: INodeMaterialEditorOptions): Promise<void>;
     }
 }
 declare module "babylonjs/Materials/Node/nodeMaterialBlock" {
@@ -112211,6 +112230,13 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    /**
+     * Interface used to configure the node material editor
+     */
+    export interface INodeMaterialEditorOptions {
+        /** Define the URl to load Node Editor resources */
+        editorURL?: string;
+    }
     /** @hidden */
     export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         /** BONES */
@@ -112263,6 +112289,10 @@ declare module BABYLON {
         private _cachedWorldViewProjectionMatrix;
         private _textureConnectionPoints;
         private _optimizers;
+        static EditorURL: string;
+        private BJSNODEMATERIALEDITOR;
+        /** Get the inspector from bundle or global */
+        private _getGlobalNodeMaterialEditor;
         /**
         * Defines the maximum number of lights that can be used in the material
         */
@@ -112404,6 +112434,14 @@ declare module BABYLON {
          * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
          */
         dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, notBoundToMesh?: boolean): void;
+        /** Creates the node editor window. */
+        private _createNodeEditor;
+        /**
+         * Launch the node material editor
+         * @param config Define the configuration of the editor
+         * @return a promise fulfilled when the node editor is visible
+         */
+        edit(config?: INodeMaterialEditorOptions): Promise<void>;
     }
 }
 declare module BABYLON {

+ 19 - 0
dist/preview release/documentation.d.ts

@@ -50210,6 +50210,13 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    /**
+     * Interface used to configure the node material editor
+     */
+    export interface INodeMaterialEditorOptions {
+        /** Define the URl to load Node Editor resources */
+        editorURL?: string;
+    }
     /** @hidden */
     export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         /** BONES */
@@ -50262,6 +50269,10 @@ declare module BABYLON {
         private _cachedWorldViewProjectionMatrix;
         private _textureConnectionPoints;
         private _optimizers;
+        static EditorURL: string;
+        private BJSNODEMATERIALEDITOR;
+        /** Get the inspector from bundle or global */
+        private _getGlobalNodeMaterialEditor;
         /**
         * Defines the maximum number of lights that can be used in the material
         */
@@ -50403,6 +50414,14 @@ declare module BABYLON {
          * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
          */
         dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, notBoundToMesh?: boolean): void;
+        /** Creates the node editor window. */
+        private _createNodeEditor;
+        /**
+         * Launch the node material editor
+         * @param config Define the configuration of the editor
+         * @return a promise fulfilled when the node editor is visible
+         */
+        edit(config?: INodeMaterialEditorOptions): Promise<void>;
     }
 }
 declare module BABYLON {

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 2 - 2
dist/preview release/inspector/babylon.inspector.bundle.js


+ 57 - 7
dist/preview release/inspector/babylon.inspector.bundle.max.js

@@ -7,7 +7,7 @@
 		exports["babylonjs-inspector"] = factory(require("babylonjs-gui"), require("babylonjs-loaders"), require("babylonjs-serializers"), require("babylonjs"));
 	else
 		root["INSPECTOR"] = factory(root["BABYLON"]["GUI"], root["BABYLON"], root["BABYLON"], root["BABYLON"]);
-})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_controls_control__, __WEBPACK_EXTERNAL_MODULE_babylonjs_loaders_glTF_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_serializers_glTF_2_0_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
+})((typeof self !== "undefined" ? self : typeof global !== "undefined" ? global : this), function(__WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_controls_image__, __WEBPACK_EXTERNAL_MODULE_babylonjs_loaders_glTF_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_serializers_glTF_2_0_index__, __WEBPACK_EXTERNAL_MODULE_babylonjs_Misc_observable__) {
 return /******/ (function(modules) { // webpackBootstrap
 /******/ 	// The module cache
 /******/ 	var installedModules = {};
@@ -35088,6 +35088,8 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _propertyGrids_lights_directionalLightPropertyGridComponent__WEBPACK_IMPORTED_MODULE_41__ = __webpack_require__(/*! ./propertyGrids/lights/directionalLightPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/lights/directionalLightPropertyGridComponent.tsx");
 /* harmony import */ var _propertyGrids_lights_spotLightPropertyGridComponent__WEBPACK_IMPORTED_MODULE_42__ = __webpack_require__(/*! ./propertyGrids/lights/spotLightPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/lights/spotLightPropertyGridComponent.tsx");
 /* harmony import */ var _propertyGrids_postProcesses_lensRenderingPipelinePropertyGridComponent__WEBPACK_IMPORTED_MODULE_43__ = __webpack_require__(/*! ./propertyGrids/postProcesses/lensRenderingPipelinePropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/postProcesses/lensRenderingPipelinePropertyGridComponent.tsx");
+/* harmony import */ var _propertyGrids_materials_nodeMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_44__ = __webpack_require__(/*! ./propertyGrids/materials/nodeMaterialPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/materials/nodeMaterialPropertyGridComponent.tsx");
+
 
 
 
@@ -35201,6 +35203,10 @@ var PropertyGridTabComponent = /** @class */ (function (_super) {
                 var material = entity;
                 return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_propertyGrids_materials_standardMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_4__["StandardMaterialPropertyGridComponent"], { globalState: this.props.globalState, material: material, lockObject: this._lockObject, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
             }
+            if (className === "NodeMaterial") {
+                var material = entity;
+                return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_propertyGrids_materials_nodeMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_44__["NodeMaterialPropertyGridComponent"], { globalState: this.props.globalState, material: material, lockObject: this._lockObject, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
+            }
             if (className === "PBRMaterial") {
                 var material = entity;
                 return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_propertyGrids_materials_pbrMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_6__["PBRMaterialPropertyGridComponent"], { globalState: this.props.globalState, material: material, lockObject: this._lockObject, onSelectionChangedObservable: this.props.onSelectionChangedObservable, onPropertyChangedObservable: this.props.onPropertyChangedObservable }));
@@ -36039,7 +36045,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lineContainerComponent */ "./components/actionTabs/lineContainerComponent.tsx");
 /* harmony import */ var _lines_textLineComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lines/textLineComponent */ "./components/actionTabs/lines/textLineComponent.tsx");
-/* harmony import */ var babylonjs_gui_2D_controls_control__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs-gui/2D/controls/control */ "babylonjs-gui/2D/controls/control");
+/* harmony import */ var babylonjs_gui_2D_controls_control__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs-gui/2D/controls/control */ "babylonjs-gui/2D/controls/image");
 /* harmony import */ var babylonjs_gui_2D_controls_control__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_gui_2D_controls_control__WEBPACK_IMPORTED_MODULE_4__);
 /* harmony import */ var _lines_sliderLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/sliderLineComponent */ "./components/actionTabs/lines/sliderLineComponent.tsx");
 /* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
@@ -36340,7 +36346,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _commonControlPropertyGridComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./commonControlPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx");
 /* harmony import */ var _lineContainerComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../../lineContainerComponent */ "./components/actionTabs/lineContainerComponent.tsx");
-/* harmony import */ var babylonjs_gui_2D_controls_image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs-gui/2D/controls/image */ "babylonjs-gui/2D/controls/control");
+/* harmony import */ var babylonjs_gui_2D_controls_image__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! babylonjs-gui/2D/controls/image */ "babylonjs-gui/2D/controls/image");
 /* harmony import */ var babylonjs_gui_2D_controls_image__WEBPACK_IMPORTED_MODULE_4___default = /*#__PURE__*/__webpack_require__.n(babylonjs_gui_2D_controls_image__WEBPACK_IMPORTED_MODULE_4__);
 /* harmony import */ var _lines_floatLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/floatLineComponent */ "./components/actionTabs/lines/floatLineComponent.tsx");
 /* harmony import */ var _lines_checkBoxLineComponent__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../../lines/checkBoxLineComponent */ "./components/actionTabs/lines/checkBoxLineComponent.tsx");
@@ -36754,7 +36760,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
 /* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
 /* harmony import */ var _commonControlPropertyGridComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./commonControlPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/gui/commonControlPropertyGridComponent.tsx");
-/* harmony import */ var babylonjs_gui_2D_controls_textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs-gui/2D/controls/textBlock */ "babylonjs-gui/2D/controls/control");
+/* harmony import */ var babylonjs_gui_2D_controls_textBlock__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! babylonjs-gui/2D/controls/textBlock */ "babylonjs-gui/2D/controls/image");
 /* harmony import */ var babylonjs_gui_2D_controls_textBlock__WEBPACK_IMPORTED_MODULE_3___default = /*#__PURE__*/__webpack_require__.n(babylonjs_gui_2D_controls_textBlock__WEBPACK_IMPORTED_MODULE_3__);
 /* harmony import */ var _lineContainerComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../lineContainerComponent */ "./components/actionTabs/lineContainerComponent.tsx");
 /* harmony import */ var _lines_textInputLineComponent__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../../lines/textInputLineComponent */ "./components/actionTabs/lines/textInputLineComponent.tsx");
@@ -37374,6 +37380,50 @@ var MaterialPropertyGridComponent = /** @class */ (function (_super) {
 
 /***/ }),
 
+/***/ "./components/actionTabs/tabs/propertyGrids/materials/nodeMaterialPropertyGridComponent.tsx":
+/*!**************************************************************************************************!*\
+  !*** ./components/actionTabs/tabs/propertyGrids/materials/nodeMaterialPropertyGridComponent.tsx ***!
+  \**************************************************************************************************/
+/*! exports provided: NodeMaterialPropertyGridComponent */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "NodeMaterialPropertyGridComponent", function() { return NodeMaterialPropertyGridComponent; });
+/* harmony import */ var tslib__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tslib */ "../../node_modules/tslib/tslib.es6.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! react */ "../../node_modules/react/index.js");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
+/* harmony import */ var _lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../../lineContainerComponent */ "./components/actionTabs/lineContainerComponent.tsx");
+/* harmony import */ var _commonMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./commonMaterialPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/materials/commonMaterialPropertyGridComponent.tsx");
+/* harmony import */ var _lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../../lines/buttonLineComponent */ "./components/actionTabs/lines/buttonLineComponent.tsx");
+
+
+
+
+
+var NodeMaterialPropertyGridComponent = /** @class */ (function (_super) {
+    tslib__WEBPACK_IMPORTED_MODULE_0__["__extends"](NodeMaterialPropertyGridComponent, _super);
+    function NodeMaterialPropertyGridComponent(props) {
+        return _super.call(this, props) || this;
+    }
+    NodeMaterialPropertyGridComponent.prototype.edit = function () {
+        this.props.material.edit();
+    };
+    NodeMaterialPropertyGridComponent.prototype.render = function () {
+        var _this = this;
+        var material = this.props.material;
+        return (react__WEBPACK_IMPORTED_MODULE_1__["createElement"]("div", { className: "pane" },
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_commonMaterialPropertyGridComponent__WEBPACK_IMPORTED_MODULE_3__["CommonMaterialPropertyGridComponent"], { globalState: this.props.globalState, lockObject: this.props.lockObject, material: material, onPropertyChangedObservable: this.props.onPropertyChangedObservable }),
+            react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lineContainerComponent__WEBPACK_IMPORTED_MODULE_2__["LineContainerComponent"], { globalState: this.props.globalState, title: "EDITOR" },
+                react__WEBPACK_IMPORTED_MODULE_1__["createElement"](_lines_buttonLineComponent__WEBPACK_IMPORTED_MODULE_4__["ButtonLineComponent"], { label: "Edit", onClick: function () { return _this.edit(); } }))));
+    };
+    return NodeMaterialPropertyGridComponent;
+}(react__WEBPACK_IMPORTED_MODULE_1__["Component"]));
+
+
+
+/***/ }),
+
 /***/ "./components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx":
 /*!*************************************************************************************************!*\
   !*** ./components/actionTabs/tabs/propertyGrids/materials/pbrMaterialPropertyGridComponent.tsx ***!
@@ -37834,7 +37884,7 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _lines_optionsLineComponent__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ../../../lines/optionsLineComponent */ "./components/actionTabs/lines/optionsLineComponent.tsx");
 /* harmony import */ var _lines_fileButtonLineComponent__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ../../../lines/fileButtonLineComponent */ "./components/actionTabs/lines/fileButtonLineComponent.tsx");
 /* harmony import */ var _lines_valueLineComponent__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ../../../lines/valueLineComponent */ "./components/actionTabs/lines/valueLineComponent.tsx");
-/* harmony import */ var babylonjs_gui_2D_adtInstrumentation__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! babylonjs-gui/2D/adtInstrumentation */ "babylonjs-gui/2D/controls/control");
+/* harmony import */ var babylonjs_gui_2D_adtInstrumentation__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! babylonjs-gui/2D/adtInstrumentation */ "babylonjs-gui/2D/controls/image");
 /* harmony import */ var babylonjs_gui_2D_adtInstrumentation__WEBPACK_IMPORTED_MODULE_12___default = /*#__PURE__*/__webpack_require__.n(babylonjs_gui_2D_adtInstrumentation__WEBPACK_IMPORTED_MODULE_12__);
 /* harmony import */ var _customPropertyGridComponent__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ../customPropertyGridComponent */ "./components/actionTabs/tabs/propertyGrids/customPropertyGridComponent.tsx");
 
@@ -42377,14 +42427,14 @@ var Tools = /** @class */ (function () {
 
 /***/ }),
 
-/***/ "babylonjs-gui/2D/controls/control":
+/***/ "babylonjs-gui/2D/controls/image":
 /*!************************************************************************************************************************!*\
   !*** external {"root":["BABYLON","GUI"],"commonjs":"babylonjs-gui","commonjs2":"babylonjs-gui","amd":"babylonjs-gui"} ***!
   \************************************************************************************************************************/
 /*! no static exports found */
 /***/ (function(module, exports) {
 
-module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_controls_control__;
+module.exports = __WEBPACK_EXTERNAL_MODULE_babylonjs_gui_2D_controls_image__;
 
 /***/ }),
 

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 14 - 0
dist/preview release/inspector/babylon.inspector.d.ts

@@ -1216,6 +1216,20 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    interface INodeMaterialPropertyGridComponentProps {
+        globalState: GlobalState;
+        material: BABYLON.NodeMaterial;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class NodeMaterialPropertyGridComponent extends React.Component<INodeMaterialPropertyGridComponentProps> {
+        constructor(props: INodeMaterialPropertyGridComponentProps);
+        edit(): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     export class PropertyGridTabComponent extends PaneComponent {
         private _timerIntervalId;
         private _lockObject;

+ 34 - 0
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -1592,6 +1592,26 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/pos
         render(): JSX.Element;
     }
 }
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/materials/nodeMaterialPropertyGridComponent" {
+    import * as React from "react";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+    import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
+    import { LockObject } from "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/lockObject";
+    import { GlobalState } from "babylonjs-inspector/components/globalState";
+    interface INodeMaterialPropertyGridComponentProps {
+        globalState: GlobalState;
+        material: NodeMaterial;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: Observable<any>;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class NodeMaterialPropertyGridComponent extends React.Component<INodeMaterialPropertyGridComponentProps> {
+        constructor(props: INodeMaterialPropertyGridComponentProps);
+        edit(): void;
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGridTabComponent" {
     import { PaneComponent, IPaneComponentProps } from "babylonjs-inspector/components/actionTabs/paneComponent";
     export class PropertyGridTabComponent extends PaneComponent {
@@ -3416,6 +3436,20 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    interface INodeMaterialPropertyGridComponentProps {
+        globalState: GlobalState;
+        material: BABYLON.NodeMaterial;
+        lockObject: LockObject;
+        onSelectionChangedObservable?: BABYLON.Observable<any>;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class NodeMaterialPropertyGridComponent extends React.Component<INodeMaterialPropertyGridComponentProps> {
+        constructor(props: INodeMaterialPropertyGridComponentProps);
+        edit(): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     export class PropertyGridTabComponent extends PaneComponent {
         private _timerIntervalId;
         private _lockObject;

+ 147 - 114
dist/preview release/nodeEditor/babylon.nodeEditor.d.ts

@@ -1,11 +1,5 @@
 /// <reference types="react" />
 declare module NODEEDITOR {
-    export class GlobalState {
-        nodeMaterial?: BABYLON.NodeMaterial;
-        hostDocument?: BABYLON.Nullable<Document>;
-    }
-}
-declare module NODEEDITOR {
     /**
      * Port model for the generic node
      */
@@ -77,6 +71,13 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    export class GlobalState {
+        nodeMaterial?: BABYLON.NodeMaterial;
+        hostDocument?: BABYLON.Nullable<Document>;
+        onSelectionChangedObservable: BABYLON.Observable<BABYLON.Nullable<GenericNodeModel>>;
+    }
+}
+declare module NODEEDITOR {
     interface ITextureLineComponentProps {
         texture: BABYLON.BaseTexture;
         width: number;
@@ -106,6 +107,91 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    /**
+     * GenericNodeWidgetProps
+     */
+    export interface GenericNodeWidgetProps {
+        node: BABYLON.Nullable<GenericNodeModel>;
+        globalState: GlobalState;
+    }
+    /**
+     * GenericNodeWidgetState
+     */
+    export interface GenericNodeWidgetState {
+    }
+    /**
+     * Used to display a node block for the node editor
+     */
+    export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
+        /**
+         * Creates a GenericNodeWidget
+         * @param props
+         */
+        constructor(props: GenericNodeWidgetProps);
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * Node factory which creates editor nodes
+     */
+    export class GenericNodeFactory extends SRD.AbstractNodeFactory {
+        private _globalState;
+        /**
+         * Constructs a GenericNodeFactory
+         */
+        constructor(globalState: GlobalState);
+        /**
+         * Generates a node widget
+         * @param diagramEngine diagram engine
+         * @param node node to generate
+         * @returns node widget jsx
+         */
+        generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element;
+        /**
+         * Gets a new instance of a node model
+         * @returns generic node model
+         */
+        getNewInstance(): GenericNodeModel;
+    }
+}
+declare module NODEEDITOR {
+    interface ILineContainerComponentProps {
+        title: string;
+        children: any[] | any;
+        closed?: boolean;
+    }
+    export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
+        isExpanded: boolean;
+    }> {
+        private static _InMemoryStorage;
+        constructor(props: ILineContainerComponentProps);
+        switchExpandedState(): void;
+        renderHeader(): JSX.Element;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    export interface IButtonLineComponentProps {
+        label: string;
+        onClick: () => void;
+    }
+    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface INodeListComponentProps {
+        globalState: GlobalState;
+        onAddValueNode: (b: string) => void;
+        onAddNodeFromClass: (ObjectClass: typeof BABYLON.NodeMaterialBlock) => void;
+    }
+    export class NodeListComponent extends React.Component<INodeListComponentProps> {
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     interface IFileButtonLineComponentProps {
         label: string;
         onClick: (file: File) => void;
@@ -118,6 +204,20 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    interface ITexturePropertyTabComponentProps {
+        globalState: GlobalState;
+        node: GenericNodeModel;
+    }
+    export class TexturePropertyTabComponent extends React.Component<ITexturePropertyTabComponentProps> {
+        /**
+         * Replaces the texture of the node
+         * @param file the file of the texture to use
+         */
+        replaceTexture(file: File): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     interface INumericInputComponentProps {
         label: string;
         value: number;
@@ -177,114 +277,23 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
-    interface IVector3LineComponentProps {
-        label: string;
-        target: any;
-        propertyName: string;
-        step?: number;
-        onChange?: (newvalue: BABYLON.Vector3) => void;
-        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
-    }
-    export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
-        isExpanded: boolean;
-        value: BABYLON.Vector3;
-    }> {
-        static defaultProps: {
-            step: number;
-        };
-        private _localChange;
-        constructor(props: IVector3LineComponentProps);
-        shouldComponentUpdate(nextProps: IVector3LineComponentProps, nextState: {
-            isExpanded: boolean;
-            value: BABYLON.Vector3;
-        }): boolean;
-        switchExpandState(): void;
-        raiseOnPropertyChanged(previousValue: BABYLON.Vector3): void;
-        updateVector3(): void;
-        updateStateX(value: number): void;
-        updateStateY(value: number): void;
-        updateStateZ(value: number): void;
-        render(): JSX.Element;
-    }
-}
-declare module NODEEDITOR {
-    /**
-     * GenericNodeWidgetProps
-     */
-    export interface GenericNodeWidgetProps {
-        node: BABYLON.Nullable<GenericNodeModel>;
-    }
-    /**
-     * GenericNodeWidgetState
-     */
-    export interface GenericNodeWidgetState {
+    interface IVector2PropertyTabComponentProps {
+        globalState: GlobalState;
+        node: GenericNodeModel;
     }
-    /**
-     * Used to display a node block for the node editor
-     */
-    export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
-        /**
-         * Creates a GenericNodeWidget
-         * @param props
-         */
-        constructor(props: GenericNodeWidgetProps);
-        /**
-         * Replaces the texture of the node
-         * @param file the file of the texture to use
-         */
-        replaceTexture(file: File): void;
+    export class Vector2PropertyTabComponent extends React.Component<IVector2PropertyTabComponentProps> {
         render(): JSX.Element;
     }
 }
 declare module NODEEDITOR {
-    /**
-     * Node factory which creates editor nodes
-     */
-    export class GenericNodeFactory extends SRD.AbstractNodeFactory {
-        /**
-         * Constructs a GenericNodeFactory
-         */
-        constructor();
-        /**
-         * Generates a node widget
-         * @param diagramEngine diagram engine
-         * @param node node to generate
-         * @returns node widget jsx
-         */
-        generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element;
-        /**
-         * Gets a new instance of a node model
-         * @returns generic node model
-         */
-        getNewInstance(): GenericNodeModel;
-    }
-}
-declare module NODEEDITOR {
-    interface ILineContainerComponentProps {
-        globalState?: any;
-        title: string;
-        children: any[] | any;
-        closed?: boolean;
+    interface IPropertyTabComponentProps {
+        globalState: GlobalState;
     }
-    export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
-        isExpanded: boolean;
-        isHighlighted: boolean;
+    export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, {
+        currentNode: BABYLON.Nullable<GenericNodeModel>;
     }> {
-        private static _InMemoryStorage;
-        constructor(props: ILineContainerComponentProps);
-        switchExpandedState(): void;
-        componentDidMount(): void;
-        renderHeader(): JSX.Element;
-        render(): JSX.Element;
-    }
-}
-declare module NODEEDITOR {
-    export interface IButtonLineComponentProps {
-        label: string;
-        onClick: () => void;
-    }
-    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
-        constructor(props: IButtonLineComponentProps);
+        constructor(props: IPropertyTabComponentProps);
+        componentWillMount(): void;
         render(): JSX.Element;
     }
 }
@@ -313,13 +322,6 @@ declare module NODEEDITOR {
         constructor(props: IGraphEditorProps);
         addNodeFromClass(ObjectClass: typeof BABYLON.NodeMaterialBlock): GenericNodeModel;
         addValueNode(type: string, column?: number, connection?: BABYLON.NodeMaterialConnectionPoint): GenericNodeModel;
-        allBlocks: {
-            Fragment: (typeof BABYLON.AlphaTestBlock | typeof BABYLON.FragmentOutputBlock | typeof BABYLON.ImageProcessingBlock | typeof BABYLON.RGBAMergerBlock | typeof BABYLON.RGBASplitterBlock | typeof BABYLON.TextureBlock)[];
-            Vertex: (typeof BABYLON.BonesBlock | typeof BABYLON.InstancesBlock | typeof BABYLON.MorphTargetsBlock | typeof BABYLON.VertexOutputBlock)[];
-            Dual: (typeof BABYLON.FogBlock)[];
-            Other: (typeof BABYLON.AddBlock | typeof BABYLON.ClampBlock | typeof BABYLON.MatrixMultiplicationBlock | typeof BABYLON.MultiplyBlock | typeof BABYLON.Vector2TransformBlock | typeof BABYLON.Vector3TransformBlock | typeof BABYLON.Vector4TransformBlock)[];
-            Value: string[];
-        };
         render(): JSX.Element;
     }
 }
@@ -350,4 +352,35 @@ declare module NODEEDITOR {
          */
         static Show(options: INodeEditorOptions): void;
     }
+}
+declare module NODEEDITOR {
+    interface IVector3LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        step?: number;
+        onChange?: (newvalue: BABYLON.Vector3) => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
+        isExpanded: boolean;
+        value: BABYLON.Vector3;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: IVector3LineComponentProps);
+        shouldComponentUpdate(nextProps: IVector3LineComponentProps, nextState: {
+            isExpanded: boolean;
+            value: BABYLON.Vector3;
+        }): boolean;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Vector3): void;
+        updateVector3(): void;
+        updateStateX(value: number): void;
+        updateStateY(value: number): void;
+        updateStateZ(value: number): void;
+        render(): JSX.Element;
+    }
 }

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 7 - 7
dist/preview release/nodeEditor/babylon.nodeEditor.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 461 - 286
dist/preview release/nodeEditor/babylon.nodeEditor.max.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


+ 328 - 263
dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts

@@ -1,17 +1,9 @@
 /// <reference types="react" />
-declare module "babylonjs-node-editor/globalState" {
-    import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
-    import { Nullable } from "babylonjs/types";
-    export class GlobalState {
-        nodeMaterial?: NodeMaterial;
-        hostDocument?: Nullable<Document>;
-    }
-}
-declare module "babylonjs-node-editor/components/customDiragramNodes/generic/genericPortModel" {
+declare module "babylonjs-node-editor/components/diagram/generic/genericPortModel" {
     import { LinkModel, PortModel } from "storm-react-diagrams";
     import { Nullable } from 'babylonjs/types';
     import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
-    import { GenericNodeModel } from "babylonjs-node-editor/components/customDiragramNodes/generic/genericNodeModel";
+    import { GenericNodeModel } from "babylonjs-node-editor/components/diagram/generic/genericNodeModel";
     /**
      * Port model for the generic node
      */
@@ -38,13 +30,13 @@ declare module "babylonjs-node-editor/components/customDiragramNodes/generic/gen
         } | null;
     }
 }
-declare module "babylonjs-node-editor/components/customDiragramNodes/generic/genericNodeModel" {
+declare module "babylonjs-node-editor/components/diagram/generic/genericNodeModel" {
     import { NodeModel } from "storm-react-diagrams";
     import { Nullable } from 'babylonjs/types';
     import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
     import { Texture } from 'babylonjs/Materials/Textures/texture';
     import { Vector2, Vector3, Vector4, Matrix } from 'babylonjs/Maths/math';
-    import { GenericPortModel } from "babylonjs-node-editor/components/customDiragramNodes/generic/genericPortModel";
+    import { GenericPortModel } from "babylonjs-node-editor/components/diagram/generic/genericPortModel";
     /**
      * Generic node model which stores information about a node editor block
      */
@@ -88,6 +80,17 @@ declare module "babylonjs-node-editor/components/customDiragramNodes/generic/gen
         constructor();
     }
 }
+declare module "babylonjs-node-editor/globalState" {
+    import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+    import { Nullable } from "babylonjs/types";
+    import { Observable } from 'babylonjs/Misc/observable';
+    import { GenericNodeModel } from "babylonjs-node-editor/components/diagram/generic/genericNodeModel";
+    export class GlobalState {
+        nodeMaterial?: NodeMaterial;
+        hostDocument?: Nullable<Document>;
+        onSelectionChangedObservable: Observable<Nullable<GenericNodeModel>>;
+    }
+}
 declare module "babylonjs-node-editor/sharedComponents/textureLineComponent" {
     import * as React from "react";
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
@@ -119,6 +122,103 @@ declare module "babylonjs-node-editor/sharedComponents/textureLineComponent" {
         render(): JSX.Element;
     }
 }
+declare module "babylonjs-node-editor/components/diagram/generic/genericNodeWidget" {
+    import * as React from "react";
+    import { GenericNodeModel } from "babylonjs-node-editor/components/diagram/generic/genericNodeModel";
+    import { Nullable } from 'babylonjs/types';
+    import { GlobalState } from "babylonjs-node-editor/globalState";
+    /**
+     * GenericNodeWidgetProps
+     */
+    export interface GenericNodeWidgetProps {
+        node: Nullable<GenericNodeModel>;
+        globalState: GlobalState;
+    }
+    /**
+     * GenericNodeWidgetState
+     */
+    export interface GenericNodeWidgetState {
+    }
+    /**
+     * Used to display a node block for the node editor
+     */
+    export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
+        /**
+         * Creates a GenericNodeWidget
+         * @param props
+         */
+        constructor(props: GenericNodeWidgetProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-node-editor/components/diagram/generic/genericNodeFactory" {
+    import * as SRD from "storm-react-diagrams";
+    import { GenericNodeModel } from "babylonjs-node-editor/components/diagram/generic/genericNodeModel";
+    import { GlobalState } from "babylonjs-node-editor/globalState";
+    /**
+     * Node factory which creates editor nodes
+     */
+    export class GenericNodeFactory extends SRD.AbstractNodeFactory {
+        private _globalState;
+        /**
+         * Constructs a GenericNodeFactory
+         */
+        constructor(globalState: GlobalState);
+        /**
+         * Generates a node widget
+         * @param diagramEngine diagram engine
+         * @param node node to generate
+         * @returns node widget jsx
+         */
+        generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element;
+        /**
+         * Gets a new instance of a node model
+         * @returns generic node model
+         */
+        getNewInstance(): GenericNodeModel;
+    }
+}
+declare module "babylonjs-node-editor/sharedComponents/lineContainerComponent" {
+    import * as React from "react";
+    interface ILineContainerComponentProps {
+        title: string;
+        children: any[] | any;
+        closed?: boolean;
+    }
+    export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
+        isExpanded: boolean;
+    }> {
+        private static _InMemoryStorage;
+        constructor(props: ILineContainerComponentProps);
+        switchExpandedState(): void;
+        renderHeader(): JSX.Element;
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-node-editor/sharedComponents/buttonLineComponent" {
+    import * as React from "react";
+    export interface IButtonLineComponentProps {
+        label: string;
+        onClick: () => void;
+    }
+    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-node-editor/components/nodeList/nodeListComponent" {
+    import * as React from "react";
+    import { GlobalState } from "babylonjs-node-editor/globalState";
+    import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
+    interface INodeListComponentProps {
+        globalState: GlobalState;
+        onAddValueNode: (b: string) => void;
+        onAddNodeFromClass: (ObjectClass: typeof NodeMaterialBlock) => void;
+    }
+    export class NodeListComponent extends React.Component<INodeListComponentProps> {
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-node-editor/sharedComponents/fileButtonLineComponent" {
     import * as React from "react";
     interface IFileButtonLineComponentProps {
@@ -132,6 +232,23 @@ declare module "babylonjs-node-editor/sharedComponents/fileButtonLineComponent"
         render(): JSX.Element;
     }
 }
+declare module "babylonjs-node-editor/components/propertyTab/properties/texturePropertyTabComponent" {
+    import * as React from "react";
+    import { GlobalState } from "babylonjs-node-editor/globalState";
+    import { GenericNodeModel } from "babylonjs-node-editor/components/diagram/generic/genericNodeModel";
+    interface ITexturePropertyTabComponentProps {
+        globalState: GlobalState;
+        node: GenericNodeModel;
+    }
+    export class TexturePropertyTabComponent extends React.Component<ITexturePropertyTabComponentProps> {
+        /**
+         * Replaces the texture of the node
+         * @param file the file of the texture to use
+         */
+        replaceTexture(file: File): void;
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-node-editor/sharedComponents/numericInputComponent" {
     import * as React from "react";
     interface INumericInputComponentProps {
@@ -196,153 +313,40 @@ declare module "babylonjs-node-editor/sharedComponents/vector2LineComponent" {
         render(): JSX.Element;
     }
 }
-declare module "babylonjs-node-editor/sharedComponents/vector3LineComponent" {
+declare module "babylonjs-node-editor/components/propertyTab/properties/vector2PropertyTabComponent" {
     import * as React from "react";
-    import { Vector3 } from "babylonjs/Maths/math";
-    import { Observable } from "babylonjs/Misc/observable";
-    import { PropertyChangedEvent } from "babylonjs-node-editor/sharedComponents/propertyChangedEvent";
-    interface IVector3LineComponentProps {
-        label: string;
-        target: any;
-        propertyName: string;
-        step?: number;
-        onChange?: (newvalue: Vector3) => void;
-        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    import { GlobalState } from "babylonjs-node-editor/globalState";
+    import { GenericNodeModel } from "babylonjs-node-editor/components/diagram/generic/genericNodeModel";
+    interface IVector2PropertyTabComponentProps {
+        globalState: GlobalState;
+        node: GenericNodeModel;
     }
-    export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
-        isExpanded: boolean;
-        value: Vector3;
-    }> {
-        static defaultProps: {
-            step: number;
-        };
-        private _localChange;
-        constructor(props: IVector3LineComponentProps);
-        shouldComponentUpdate(nextProps: IVector3LineComponentProps, nextState: {
-            isExpanded: boolean;
-            value: Vector3;
-        }): boolean;
-        switchExpandState(): void;
-        raiseOnPropertyChanged(previousValue: Vector3): void;
-        updateVector3(): void;
-        updateStateX(value: number): void;
-        updateStateY(value: number): void;
-        updateStateZ(value: number): void;
+    export class Vector2PropertyTabComponent extends React.Component<IVector2PropertyTabComponentProps> {
         render(): JSX.Element;
     }
 }
-declare module "babylonjs-node-editor/components/customDiragramNodes/generic/genericNodeWidget" {
+declare module "babylonjs-node-editor/components/propertyTab/propertyTabComponent" {
     import * as React from "react";
-    import { GenericNodeModel } from "babylonjs-node-editor/components/customDiragramNodes/generic/genericNodeModel";
+    import { GlobalState } from "babylonjs-node-editor/globalState";
     import { Nullable } from 'babylonjs/types';
-    /**
-     * GenericNodeWidgetProps
-     */
-    export interface GenericNodeWidgetProps {
-        node: Nullable<GenericNodeModel>;
-    }
-    /**
-     * GenericNodeWidgetState
-     */
-    export interface GenericNodeWidgetState {
-    }
-    /**
-     * Used to display a node block for the node editor
-     */
-    export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
-        /**
-         * Creates a GenericNodeWidget
-         * @param props
-         */
-        constructor(props: GenericNodeWidgetProps);
-        /**
-         * Replaces the texture of the node
-         * @param file the file of the texture to use
-         */
-        replaceTexture(file: File): void;
-        render(): JSX.Element;
-    }
-}
-declare module "babylonjs-node-editor/components/customDiragramNodes/generic/genericNodeFactory" {
-    import * as SRD from "storm-react-diagrams";
-    import { GenericNodeModel } from "babylonjs-node-editor/components/customDiragramNodes/generic/genericNodeModel";
-    /**
-     * Node factory which creates editor nodes
-     */
-    export class GenericNodeFactory extends SRD.AbstractNodeFactory {
-        /**
-         * Constructs a GenericNodeFactory
-         */
-        constructor();
-        /**
-         * Generates a node widget
-         * @param diagramEngine diagram engine
-         * @param node node to generate
-         * @returns node widget jsx
-         */
-        generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element;
-        /**
-         * Gets a new instance of a node model
-         * @returns generic node model
-         */
-        getNewInstance(): GenericNodeModel;
-    }
-}
-declare module "babylonjs-node-editor/sharedComponents/lineContainerComponent" {
-    import * as React from "react";
-    interface ILineContainerComponentProps {
-        globalState?: any;
-        title: string;
-        children: any[] | any;
-        closed?: boolean;
+    import { GenericNodeModel } from "babylonjs-node-editor/components/diagram/generic/genericNodeModel";
+    interface IPropertyTabComponentProps {
+        globalState: GlobalState;
     }
-    export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
-        isExpanded: boolean;
-        isHighlighted: boolean;
+    export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, {
+        currentNode: Nullable<GenericNodeModel>;
     }> {
-        private static _InMemoryStorage;
-        constructor(props: ILineContainerComponentProps);
-        switchExpandedState(): void;
-        componentDidMount(): void;
-        renderHeader(): JSX.Element;
-        render(): JSX.Element;
-    }
-}
-declare module "babylonjs-node-editor/sharedComponents/buttonLineComponent" {
-    import * as React from "react";
-    export interface IButtonLineComponentProps {
-        label: string;
-        onClick: () => void;
-    }
-    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
-        constructor(props: IButtonLineComponentProps);
+        constructor(props: IPropertyTabComponentProps);
+        componentWillMount(): void;
         render(): JSX.Element;
     }
 }
 declare module "babylonjs-node-editor/components/graphEditor" {
     import * as React from "react";
     import { GlobalState } from "babylonjs-node-editor/globalState";
-    import { GenericNodeModel } from "babylonjs-node-editor/components/customDiragramNodes/generic/genericNodeModel";
+    import { GenericNodeModel } from "babylonjs-node-editor/components/diagram/generic/genericNodeModel";
     import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
     import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
-    import { AlphaTestBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/alphaTestBlock';
-    import { FragmentOutputBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock';
-    import { ImageProcessingBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock';
-    import { RGBAMergerBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/rgbaMergerBlock';
-    import { RGBASplitterBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/rgbaSplitterBlock';
-    import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/textureBlock';
-    import { BonesBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/bonesBlock';
-    import { InstancesBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/instancesBlock';
-    import { MorphTargetsBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/morphTargetsBlock';
-    import { VertexOutputBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/vertexOutputBlock';
-    import { FogBlock } from 'babylonjs/Materials/Node/Blocks/Dual/fogBlock';
-    import { AddBlock } from 'babylonjs/Materials/Node/Blocks/addBlock';
-    import { ClampBlock } from 'babylonjs/Materials/Node/Blocks/clampBlock';
-    import { MatrixMultiplicationBlock } from 'babylonjs/Materials/Node/Blocks/matrixMultiplicationBlock';
-    import { MultiplyBlock } from 'babylonjs/Materials/Node/Blocks/multiplyBlock';
-    import { Vector2TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector2TransformBlock';
-    import { Vector3TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector3TransformBlock';
-    import { Vector4TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector4TransformBlock';
     interface IGraphEditorProps {
         globalState: GlobalState;
     }
@@ -367,13 +371,6 @@ declare module "babylonjs-node-editor/components/graphEditor" {
         constructor(props: IGraphEditorProps);
         addNodeFromClass(ObjectClass: typeof NodeMaterialBlock): GenericNodeModel;
         addValueNode(type: string, column?: number, connection?: NodeMaterialConnectionPoint): GenericNodeModel;
-        allBlocks: {
-            Fragment: (typeof AlphaTestBlock | typeof FragmentOutputBlock | typeof ImageProcessingBlock | typeof RGBAMergerBlock | typeof RGBASplitterBlock | typeof TextureBlock)[];
-            Vertex: (typeof BonesBlock | typeof InstancesBlock | typeof MorphTargetsBlock | typeof VertexOutputBlock)[];
-            Dual: (typeof FogBlock)[];
-            Other: (typeof AddBlock | typeof ClampBlock | typeof MatrixMultiplicationBlock | typeof MultiplyBlock | typeof Vector2TransformBlock | typeof Vector3TransformBlock | typeof Vector4TransformBlock)[];
-            Value: string[];
-        };
         render(): JSX.Element;
     }
 }
@@ -412,17 +409,46 @@ declare module "babylonjs-node-editor/index" {
 declare module "babylonjs-node-editor/legacy/legacy" {
     export * from "babylonjs-node-editor/index";
 }
+declare module "babylonjs-node-editor/sharedComponents/vector3LineComponent" {
+    import * as React from "react";
+    import { Vector3 } from "babylonjs/Maths/math";
+    import { Observable } from "babylonjs/Misc/observable";
+    import { PropertyChangedEvent } from "babylonjs-node-editor/sharedComponents/propertyChangedEvent";
+    interface IVector3LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        step?: number;
+        onChange?: (newvalue: Vector3) => void;
+        onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    }
+    export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
+        isExpanded: boolean;
+        value: Vector3;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: IVector3LineComponentProps);
+        shouldComponentUpdate(nextProps: IVector3LineComponentProps, nextState: {
+            isExpanded: boolean;
+            value: Vector3;
+        }): boolean;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: Vector3): void;
+        updateVector3(): void;
+        updateStateX(value: number): void;
+        updateStateY(value: number): void;
+        updateStateZ(value: number): void;
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-node-editor" {
     export * from "babylonjs-node-editor/legacy/legacy";
 }
 /// <reference types="react" />
 declare module NODEEDITOR {
-    export class GlobalState {
-        nodeMaterial?: BABYLON.NodeMaterial;
-        hostDocument?: BABYLON.Nullable<Document>;
-    }
-}
-declare module NODEEDITOR {
     /**
      * Port model for the generic node
      */
@@ -494,6 +520,13 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    export class GlobalState {
+        nodeMaterial?: BABYLON.NodeMaterial;
+        hostDocument?: BABYLON.Nullable<Document>;
+        onSelectionChangedObservable: BABYLON.Observable<BABYLON.Nullable<GenericNodeModel>>;
+    }
+}
+declare module NODEEDITOR {
     interface ITextureLineComponentProps {
         texture: BABYLON.BaseTexture;
         width: number;
@@ -523,6 +556,91 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    /**
+     * GenericNodeWidgetProps
+     */
+    export interface GenericNodeWidgetProps {
+        node: BABYLON.Nullable<GenericNodeModel>;
+        globalState: GlobalState;
+    }
+    /**
+     * GenericNodeWidgetState
+     */
+    export interface GenericNodeWidgetState {
+    }
+    /**
+     * Used to display a node block for the node editor
+     */
+    export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
+        /**
+         * Creates a GenericNodeWidget
+         * @param props
+         */
+        constructor(props: GenericNodeWidgetProps);
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    /**
+     * Node factory which creates editor nodes
+     */
+    export class GenericNodeFactory extends SRD.AbstractNodeFactory {
+        private _globalState;
+        /**
+         * Constructs a GenericNodeFactory
+         */
+        constructor(globalState: GlobalState);
+        /**
+         * Generates a node widget
+         * @param diagramEngine diagram engine
+         * @param node node to generate
+         * @returns node widget jsx
+         */
+        generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element;
+        /**
+         * Gets a new instance of a node model
+         * @returns generic node model
+         */
+        getNewInstance(): GenericNodeModel;
+    }
+}
+declare module NODEEDITOR {
+    interface ILineContainerComponentProps {
+        title: string;
+        children: any[] | any;
+        closed?: boolean;
+    }
+    export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
+        isExpanded: boolean;
+    }> {
+        private static _InMemoryStorage;
+        constructor(props: ILineContainerComponentProps);
+        switchExpandedState(): void;
+        renderHeader(): JSX.Element;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    export interface IButtonLineComponentProps {
+        label: string;
+        onClick: () => void;
+    }
+    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
+        constructor(props: IButtonLineComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
+    interface INodeListComponentProps {
+        globalState: GlobalState;
+        onAddValueNode: (b: string) => void;
+        onAddNodeFromClass: (ObjectClass: typeof BABYLON.NodeMaterialBlock) => void;
+    }
+    export class NodeListComponent extends React.Component<INodeListComponentProps> {
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     interface IFileButtonLineComponentProps {
         label: string;
         onClick: (file: File) => void;
@@ -535,6 +653,20 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    interface ITexturePropertyTabComponentProps {
+        globalState: GlobalState;
+        node: GenericNodeModel;
+    }
+    export class TexturePropertyTabComponent extends React.Component<ITexturePropertyTabComponentProps> {
+        /**
+         * Replaces the texture of the node
+         * @param file the file of the texture to use
+         */
+        replaceTexture(file: File): void;
+        render(): JSX.Element;
+    }
+}
+declare module NODEEDITOR {
     interface INumericInputComponentProps {
         label: string;
         value: number;
@@ -594,114 +726,23 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
-    interface IVector3LineComponentProps {
-        label: string;
-        target: any;
-        propertyName: string;
-        step?: number;
-        onChange?: (newvalue: BABYLON.Vector3) => void;
-        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
-    }
-    export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
-        isExpanded: boolean;
-        value: BABYLON.Vector3;
-    }> {
-        static defaultProps: {
-            step: number;
-        };
-        private _localChange;
-        constructor(props: IVector3LineComponentProps);
-        shouldComponentUpdate(nextProps: IVector3LineComponentProps, nextState: {
-            isExpanded: boolean;
-            value: BABYLON.Vector3;
-        }): boolean;
-        switchExpandState(): void;
-        raiseOnPropertyChanged(previousValue: BABYLON.Vector3): void;
-        updateVector3(): void;
-        updateStateX(value: number): void;
-        updateStateY(value: number): void;
-        updateStateZ(value: number): void;
-        render(): JSX.Element;
-    }
-}
-declare module NODEEDITOR {
-    /**
-     * GenericNodeWidgetProps
-     */
-    export interface GenericNodeWidgetProps {
-        node: BABYLON.Nullable<GenericNodeModel>;
-    }
-    /**
-     * GenericNodeWidgetState
-     */
-    export interface GenericNodeWidgetState {
+    interface IVector2PropertyTabComponentProps {
+        globalState: GlobalState;
+        node: GenericNodeModel;
     }
-    /**
-     * Used to display a node block for the node editor
-     */
-    export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
-        /**
-         * Creates a GenericNodeWidget
-         * @param props
-         */
-        constructor(props: GenericNodeWidgetProps);
-        /**
-         * Replaces the texture of the node
-         * @param file the file of the texture to use
-         */
-        replaceTexture(file: File): void;
+    export class Vector2PropertyTabComponent extends React.Component<IVector2PropertyTabComponentProps> {
         render(): JSX.Element;
     }
 }
 declare module NODEEDITOR {
-    /**
-     * Node factory which creates editor nodes
-     */
-    export class GenericNodeFactory extends SRD.AbstractNodeFactory {
-        /**
-         * Constructs a GenericNodeFactory
-         */
-        constructor();
-        /**
-         * Generates a node widget
-         * @param diagramEngine diagram engine
-         * @param node node to generate
-         * @returns node widget jsx
-         */
-        generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element;
-        /**
-         * Gets a new instance of a node model
-         * @returns generic node model
-         */
-        getNewInstance(): GenericNodeModel;
-    }
-}
-declare module NODEEDITOR {
-    interface ILineContainerComponentProps {
-        globalState?: any;
-        title: string;
-        children: any[] | any;
-        closed?: boolean;
+    interface IPropertyTabComponentProps {
+        globalState: GlobalState;
     }
-    export class LineContainerComponent extends React.Component<ILineContainerComponentProps, {
-        isExpanded: boolean;
-        isHighlighted: boolean;
+    export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, {
+        currentNode: BABYLON.Nullable<GenericNodeModel>;
     }> {
-        private static _InMemoryStorage;
-        constructor(props: ILineContainerComponentProps);
-        switchExpandedState(): void;
-        componentDidMount(): void;
-        renderHeader(): JSX.Element;
-        render(): JSX.Element;
-    }
-}
-declare module NODEEDITOR {
-    export interface IButtonLineComponentProps {
-        label: string;
-        onClick: () => void;
-    }
-    export class ButtonLineComponent extends React.Component<IButtonLineComponentProps> {
-        constructor(props: IButtonLineComponentProps);
+        constructor(props: IPropertyTabComponentProps);
+        componentWillMount(): void;
         render(): JSX.Element;
     }
 }
@@ -730,13 +771,6 @@ declare module NODEEDITOR {
         constructor(props: IGraphEditorProps);
         addNodeFromClass(ObjectClass: typeof BABYLON.NodeMaterialBlock): GenericNodeModel;
         addValueNode(type: string, column?: number, connection?: BABYLON.NodeMaterialConnectionPoint): GenericNodeModel;
-        allBlocks: {
-            Fragment: (typeof BABYLON.AlphaTestBlock | typeof BABYLON.FragmentOutputBlock | typeof BABYLON.ImageProcessingBlock | typeof BABYLON.RGBAMergerBlock | typeof BABYLON.RGBASplitterBlock | typeof BABYLON.TextureBlock)[];
-            Vertex: (typeof BABYLON.BonesBlock | typeof BABYLON.InstancesBlock | typeof BABYLON.MorphTargetsBlock | typeof BABYLON.VertexOutputBlock)[];
-            Dual: (typeof BABYLON.FogBlock)[];
-            Other: (typeof BABYLON.AddBlock | typeof BABYLON.ClampBlock | typeof BABYLON.MatrixMultiplicationBlock | typeof BABYLON.MultiplyBlock | typeof BABYLON.Vector2TransformBlock | typeof BABYLON.Vector3TransformBlock | typeof BABYLON.Vector4TransformBlock)[];
-            Value: string[];
-        };
         render(): JSX.Element;
     }
 }
@@ -767,4 +801,35 @@ declare module NODEEDITOR {
          */
         static Show(options: INodeEditorOptions): void;
     }
+}
+declare module NODEEDITOR {
+    interface IVector3LineComponentProps {
+        label: string;
+        target: any;
+        propertyName: string;
+        step?: number;
+        onChange?: (newvalue: BABYLON.Vector3) => void;
+        onPropertyChangedObservable?: BABYLON.Observable<PropertyChangedEvent>;
+    }
+    export class Vector3LineComponent extends React.Component<IVector3LineComponentProps, {
+        isExpanded: boolean;
+        value: BABYLON.Vector3;
+    }> {
+        static defaultProps: {
+            step: number;
+        };
+        private _localChange;
+        constructor(props: IVector3LineComponentProps);
+        shouldComponentUpdate(nextProps: IVector3LineComponentProps, nextState: {
+            isExpanded: boolean;
+            value: BABYLON.Vector3;
+        }): boolean;
+        switchExpandState(): void;
+        raiseOnPropertyChanged(previousValue: BABYLON.Vector3): void;
+        updateVector3(): void;
+        updateStateX(value: number): void;
+        updateStateY(value: number): void;
+        updateStateZ(value: number): void;
+        render(): JSX.Element;
+    }
 }

+ 38 - 0
dist/preview release/viewer/babylon.module.d.ts

@@ -52444,6 +52444,13 @@ declare module "babylonjs/Materials/Node/nodeMaterial" {
     import { NodeMaterialOptimizer } from "babylonjs/Materials/Node/Optimizers/nodeMaterialOptimizer";
     import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from "babylonjs/Materials/imageProcessingConfiguration";
     import { Nullable } from "babylonjs/types";
+    /**
+     * Interface used to configure the node material editor
+     */
+    export interface INodeMaterialEditorOptions {
+        /** Define the URl to load Node Editor resources */
+        editorURL?: string;
+    }
     /** @hidden */
     export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         /** BONES */
@@ -52496,6 +52503,10 @@ declare module "babylonjs/Materials/Node/nodeMaterial" {
         private _cachedWorldViewProjectionMatrix;
         private _textureConnectionPoints;
         private _optimizers;
+        static EditorURL: string;
+        private BJSNODEMATERIALEDITOR;
+        /** Get the inspector from bundle or global */
+        private _getGlobalNodeMaterialEditor;
         /**
         * Defines the maximum number of lights that can be used in the material
         */
@@ -52637,6 +52648,14 @@ declare module "babylonjs/Materials/Node/nodeMaterial" {
          * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
          */
         dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, notBoundToMesh?: boolean): void;
+        /** Creates the node editor window. */
+        private _createNodeEditor;
+        /**
+         * Launch the node material editor
+         * @param config Define the configuration of the editor
+         * @return a promise fulfilled when the node editor is visible
+         */
+        edit(config?: INodeMaterialEditorOptions): Promise<void>;
     }
 }
 declare module "babylonjs/Materials/Node/nodeMaterialBlock" {
@@ -112211,6 +112230,13 @@ declare module BABYLON {
     }
 }
 declare module BABYLON {
+    /**
+     * Interface used to configure the node material editor
+     */
+    export interface INodeMaterialEditorOptions {
+        /** Define the URl to load Node Editor resources */
+        editorURL?: string;
+    }
     /** @hidden */
     export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
         /** BONES */
@@ -112263,6 +112289,10 @@ declare module BABYLON {
         private _cachedWorldViewProjectionMatrix;
         private _textureConnectionPoints;
         private _optimizers;
+        static EditorURL: string;
+        private BJSNODEMATERIALEDITOR;
+        /** Get the inspector from bundle or global */
+        private _getGlobalNodeMaterialEditor;
         /**
         * Defines the maximum number of lights that can be used in the material
         */
@@ -112404,6 +112434,14 @@ declare module BABYLON {
          * @param notBoundToMesh specifies if the material that is being disposed is known to be not bound to any mesh
          */
         dispose(forceDisposeEffect?: boolean, forceDisposeTextures?: boolean, notBoundToMesh?: boolean): void;
+        /** Creates the node editor window. */
+        private _createNodeEditor;
+        /**
+         * Launch the node material editor
+         * @param config Define the configuration of the editor
+         * @return a promise fulfilled when the node editor is visible
+         */
+        edit(config?: INodeMaterialEditorOptions): Promise<void>;
     }
 }
 declare module BABYLON {

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 7 - 7
dist/preview release/viewer/babylon.viewer.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


+ 12 - 0
inspector/src/components/actionTabs/tabs/propertyGridTabComponent.tsx

@@ -85,6 +85,8 @@ import { SpotLight } from 'babylonjs/Lights/spotLight';
 import { SpotLightPropertyGridComponent } from './propertyGrids/lights/spotLightPropertyGridComponent';
 import { LensRenderingPipeline } from 'babylonjs/PostProcesses/RenderPipeline/Pipelines/lensRenderingPipeline';
 import { LensRenderingPipelinePropertyGridComponent } from './propertyGrids/postProcesses/lensRenderingPipelinePropertyGridComponent';
+import { NodeMaterial } from 'babylonjs/Materials/Node/nodeMaterial';
+import { NodeMaterialPropertyGridComponent } from './propertyGrids/materials/nodeMaterialPropertyGridComponent';
 
 export class PropertyGridTabComponent extends PaneComponent {
     private _timerIntervalId: number;
@@ -213,6 +215,16 @@ export class PropertyGridTabComponent extends PaneComponent {
                     onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
             }
 
+            if (className === "NodeMaterial") {
+                const material = entity as NodeMaterial;
+                return (<NodeMaterialPropertyGridComponent
+                    globalState={this.props.globalState}
+                    material={material}
+                    lockObject={this._lockObject}
+                    onSelectionChangedObservable={this.props.onSelectionChangedObservable}
+                    onPropertyChangedObservable={this.props.onPropertyChangedObservable} />);
+            }
+
             if (className === "PBRMaterial") {
                 const material = entity as PBRMaterial;
                 return (<PBRMaterialPropertyGridComponent

+ 42 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/materials/nodeMaterialPropertyGridComponent.tsx

@@ -0,0 +1,42 @@
+import * as React from "react";
+
+import { Observable } from "babylonjs/Misc/observable";
+import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial";
+
+import { PropertyChangedEvent } from "../../../../propertyChangedEvent";
+import { LineContainerComponent } from "../../../lineContainerComponent";
+import { CommonMaterialPropertyGridComponent } from "./commonMaterialPropertyGridComponent";
+import { LockObject } from "../lockObject";
+import { GlobalState } from '../../../../globalState';
+import { ButtonLineComponent } from '../../../lines/buttonLineComponent';
+
+interface INodeMaterialPropertyGridComponentProps {
+    globalState: GlobalState;
+    material: NodeMaterial;
+    lockObject: LockObject;
+    onSelectionChangedObservable?: Observable<any>;
+    onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+}
+
+export class NodeMaterialPropertyGridComponent extends React.Component<INodeMaterialPropertyGridComponentProps> {
+    constructor(props: INodeMaterialPropertyGridComponentProps) {
+        super(props);
+    }
+
+    edit() {
+        this.props.material.edit();
+    }
+
+    render() {
+        const material = this.props.material;
+
+        return (
+            <div className="pane">
+                <CommonMaterialPropertyGridComponent globalState={this.props.globalState} lockObject={this.props.lockObject} material={material} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                <LineContainerComponent globalState={this.props.globalState} title="EDITOR">
+                    <ButtonLineComponent label="Edit" onClick={() => this.edit()} />
+                </LineContainerComponent>
+            </div>
+        );
+    }
+}

+ 0 - 162
nodeEditor/src/components/customDiragramNodes/generic/genericNodeWidget.tsx

@@ -1,162 +0,0 @@
-import * as React from "react";
-import { PortWidget } from "storm-react-diagrams";
-import { GenericNodeModel } from './genericNodeModel';
-import { GenericPortModel } from './genericPortModel';
-import {TextureLineComponent} from "../../../sharedComponents/textureLineComponent"
-import {FileButtonLineComponent} from "../../../sharedComponents/fileButtonLineComponent"
-import { Vector2LineComponent } from '../../../sharedComponents/vector2LineComponent';
-import { Vector3LineComponent } from '../../../sharedComponents/vector3LineComponent';
-import { Nullable } from 'babylonjs/types';
-import { Texture } from 'babylonjs/Materials/Textures/texture';
-import { Engine } from 'babylonjs/Engines/engine';
-import { Tools } from 'babylonjs/Misc/tools';
-
-/**
- * GenericNodeWidgetProps
- */
-export interface GenericNodeWidgetProps {
-	node: Nullable<GenericNodeModel>;
-}
-
-/**
- * GenericNodeWidgetState
- */
-export interface GenericNodeWidgetState {}
-
-/**
- * Used to display a node block for the node editor
- */
-export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
-	/**
-	 * Creates a GenericNodeWidget
-	 * @param props 
-	 */
-	constructor(props: GenericNodeWidgetProps) {
-		super(props);
-		this.state = {}
-	}
-
-	/**
-	 * Replaces the texture of the node
-	 * @param file the file of the texture to use
-	 */
-	replaceTexture(file: File) {
-		if(!this.props.node){
-			return;
-		}
-
-		let texture = this.props.node.texture as Texture;
-		if(!texture){
-			this.props.node.texture = new Texture(null, Engine.LastCreatedScene)
-			texture = this.props.node.texture;
-		}
-
-        Tools.ReadFile(file, (data) => {
-            var blob = new Blob([data], { type: "octet/stream" });
-            var url = URL.createObjectURL(blob);
-
-            if (texture.isCube) {
-                let extension: string | undefined = undefined;
-                if (file.name.toLowerCase().indexOf(".dds") > 0) {
-                    extension = ".dds";
-                } else if (file.name.toLowerCase().indexOf(".env") > 0) {
-                    extension = ".env";
-                }
-
-                (texture as Texture).updateURL(url, extension, () => this.forceUpdate());
-            } else {
-                (texture as Texture).updateURL(url, null, () => this.forceUpdate());
-            }
-			(this.refs.textureView as TextureLineComponent).updatePreview()
-        }, undefined, true);
-    }
-
-	render() {
-		var headers = new Array<JSX.Element>()
-		var inputPorts = new Array<JSX.Element>()
-		var outputPorts = new Array<JSX.Element>()
-		var value = <div></div>
-		if(this.props.node){
-			// Header labels
-			this.props.node.headerLabels.forEach((h, i)=>{
-				headers.push(<div style={{fontWeight: "bold", borderBottomStyle: "solid"}} key={i}>{h.text}</div>)
-			})
-
-			// Input/Output ports
-			for(var key in this.props.node.ports){
-				var port = this.props.node.ports[key] as GenericPortModel;
-				if(port.position == "input"){
-					var control = <div></div>
-
-					// Color of the connection
-					var color = "black"
-					if(port.connection){
-						if(port.connection.isAttribute){
-							color = "red"
-						}else if(port.connection.isUniform){
-							color = "brown"
-						}
-						else if(port.connection.isVarying){
-							color = "purple"
-						}
-					}
-
-					inputPorts.push(
-						<div key={key} style={{paddingBottom: "8px"}}>
-							<div style={{display: "inline-block", borderStyle: "solid", marginBottom: "-4px", position: "absolute", left: "-17px", background: "#777777"}}>
-								<PortWidget key={key} name={port.name} node={this.props.node} />
-							</div>
-							<div style={{display: "inline-block", color: color}}>
-								{port.name} 
-							</div>
-							{control}
-						</div>
-					)
-				}else{
-					outputPorts.push(
-						<div key={key} style={{paddingBottom: "8px"}}>
-							<div style={{display: "inline-block"}}>
-								{port.name}
-							</div>
-							<div style={{display: "inline-block", borderStyle: "solid", marginBottom: "-4px", position: "absolute", right: "-17px", background: "#777777"}}>
-								<PortWidget key={key} name={port.name} node={this.props.node} />
-							</div>
-						</div>
-					)
-				}
-				
-			}
-
-			// Display the view depending on the value type of the node
-			if(this.props.node.texture){
-				value = (
-					<div>
-						<TextureLineComponent ref="textureView" width={100} height={100} texture={this.props.node.texture} hideChannelSelect={true}/>
-						<FileButtonLineComponent label="" onClick={(file) => this.replaceTexture(file)} accept=".jpg, .png, .tga, .dds, .env" />
-					</div>
-				)
-			} else if(this.props.node.vector3){
-				value = (
-					<div style={{width: "220px"}}>
-						<Vector3LineComponent label="" target={this.props.node} propertyName="vector3"></Vector3LineComponent>
-					</div>
-				)
-			} else if(this.props.node.vector2){
-				value = (
-					<div style={{width: "220px"}}>
-						<Vector2LineComponent label="" target={this.props.node} propertyName="vector2"></Vector2LineComponent>
-					</div>
-				)
-			}
-		}
-
-		return (
-			<div style={{background: "white", borderStyle: "solid", padding: "10px"}}>
-				{headers}
-				{inputPorts}
-				{outputPorts}
-				{value}
-			</div>
-		);
-	}
-}

+ 37 - 0
nodeEditor/src/components/diagram/diagram.scss

@@ -0,0 +1,37 @@
+.diagramBlock {
+    background: white;
+    width: 200px;
+    border: 4px solid black;
+
+    &.input {
+        background: green;
+        color:white;
+    }
+
+    &.output {
+        background: blue;
+        color:white;
+
+        .inputs { 
+            color:white;
+        }
+    }
+
+    .header {
+        margin: 10px;
+        .header-labels {
+            font-size: 16px;
+            text-align: center;
+        }
+    }
+
+    .inputs {
+        text-align: left;
+        padding-left: 10px;
+    }
+
+    .outputs {
+        text-align: right;
+        padding-right: 10px;
+    }
+}

+ 14 - 9
nodeEditor/src/components/customDiragramNodes/generic/genericNodeFactory.tsx

@@ -2,17 +2,22 @@ import * as SRD from "storm-react-diagrams";
 import { GenericNodeWidget } from "./genericNodeWidget";
 import { GenericNodeModel } from "./genericNodeModel";
 import * as React from "react";
+import { GlobalState } from '../../../globalState';
 
 /**
  * Node factory which creates editor nodes
  */
 export class GenericNodeFactory extends SRD.AbstractNodeFactory {
+    private _globalState: GlobalState;
+
 	/**
 	 * Constructs a GenericNodeFactory
 	 */
-	constructor() {
-		super("generic");
-	}
+    constructor(globalState: GlobalState) {
+        super("generic");
+
+        this._globalState = globalState;
+    }
 
 	/**
 	 * Generates a node widget
@@ -20,15 +25,15 @@ export class GenericNodeFactory extends SRD.AbstractNodeFactory {
 	 * @param node node to generate
 	 * @returns node widget jsx
 	 */
-	generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element {
-		return <GenericNodeWidget node={node} />;
-	}
+    generateReactWidget(diagramEngine: SRD.DiagramEngine, node: GenericNodeModel): JSX.Element {
+        return <GenericNodeWidget node={node} globalState={this._globalState} />;
+    }
 
 	/**
 	 * Gets a new instance of a node model
 	 * @returns generic node model
 	 */
-	getNewInstance() {
-		return new GenericNodeModel();
-	}
+    getNewInstance() {
+        return new GenericNodeModel();
+    }
 }

nodeEditor/src/components/customDiragramNodes/generic/genericNodeModel.ts → nodeEditor/src/components/diagram/generic/genericNodeModel.ts


+ 117 - 0
nodeEditor/src/components/diagram/generic/genericNodeWidget.tsx

@@ -0,0 +1,117 @@
+import * as React from "react";
+import { PortWidget } from "storm-react-diagrams";
+import { GenericNodeModel } from './genericNodeModel';
+import { GenericPortModel } from './genericPortModel';
+import { TextureLineComponent } from "../../../sharedComponents/textureLineComponent"
+import { Nullable } from 'babylonjs/types';
+import { GlobalState } from '../../../globalState';
+
+/**
+ * GenericNodeWidgetProps
+ */
+export interface GenericNodeWidgetProps {
+    node: Nullable<GenericNodeModel>;
+    globalState: GlobalState;
+}
+
+/**
+ * GenericNodeWidgetState
+ */
+export interface GenericNodeWidgetState {
+
+}
+
+/**
+ * Used to display a node block for the node editor
+ */
+export class GenericNodeWidget extends React.Component<GenericNodeWidgetProps, GenericNodeWidgetState> {
+	/**
+	 * Creates a GenericNodeWidget
+	 * @param props 
+	 */
+    constructor(props: GenericNodeWidgetProps) {
+        super(props);
+        this.state = {};
+
+        if (this.props.node) {
+            this.props.node.addListener({
+                selectionChanged: () => {
+                    let selected = (this.props.node as any).selected;
+                    this.props.globalState.onSelectionChangedObservable.notifyObservers(selected ? this.props.node : null);
+                }
+            });
+        }
+    }
+
+    render() {
+        var headers = new Array<JSX.Element>()
+        var inputPorts = new Array<JSX.Element>()
+        var outputPorts = new Array<JSX.Element>()
+        var value = <div></div>
+        if (this.props.node) {
+            // Header labels
+            if (this.props.node.headerLabels.length) {
+                this.props.node.headerLabels.forEach((h, i) => {
+                    headers.push(<div className="header-labels" key={i}>{h.text}</div>)
+                });
+            }
+
+            // Input/Output ports
+            for (var key in this.props.node.ports) {
+                var port = this.props.node.ports[key] as GenericPortModel;
+                if (port.position == "input") {
+                    var control = <div></div>
+
+                    inputPorts.push(
+                        <div key={key} style={{ paddingBottom: "8px" }}>
+                            <div style={{ display: "inline-block", borderStyle: "solid", marginBottom: "-4px", position: "absolute", left: "-17px", background: "#777777" }}>
+                                <PortWidget key={key} name={port.name} node={this.props.node} />
+                            </div>
+                            <div style={{ display: "inline-block" }}>
+                                {port.name}
+                            </div>
+                            {control}
+                        </div>
+                    )
+                } else {
+                    outputPorts.push(
+                        <div key={key} style={{ paddingBottom: "8px" }}>
+                            <div style={{ display: "inline-block" }}>
+                                {port.name}
+                            </div>
+                            <div style={{ display: "inline-block", borderStyle: "solid", marginBottom: "-4px", position: "absolute", right: "-17px", background: "#777777" }}>
+                                <PortWidget key={key} name={port.name} node={this.props.node} />
+                            </div>
+                        </div>
+                    )
+                }
+
+            }
+
+            // Display the view depending on the value type of the node
+            if (this.props.node.texture) {
+                value = (
+                    <TextureLineComponent ref="textureView" width={200} height={180} texture={this.props.node.texture} hideChannelSelect={true} />
+                )
+            }
+        }
+
+        const isInputBlock = this.props.node && this.props.node.headerLabels.length;
+        const isOutputBlock = outputPorts.length === 0;
+
+        return (
+            <div className={"diagramBlock" + (isInputBlock ? "" : " input") + (isOutputBlock ? " output" : "")}>
+                <div className="header">
+                    {headers}
+                </div>
+                <div className="inputs">
+                    {inputPorts}
+                </div>
+                <div className="outputs">
+                    {outputPorts}
+                </div>
+                {value}
+            </div>
+        );
+    }
+}

nodeEditor/src/components/customDiragramNodes/generic/genericPortModel.ts → nodeEditor/src/components/diagram/generic/genericPortModel.ts


+ 113 - 166
nodeEditor/src/components/graphEditor.tsx

@@ -1,45 +1,28 @@
 import {
-	DiagramEngine,
-	DiagramModel,
-	DiagramWidget,
+    DiagramEngine,
+    DiagramModel,
+    DiagramWidget,
     MoveCanvasAction
 } from "storm-react-diagrams";
 
 import * as React from "react";
 import { GlobalState } from '../globalState';
 
-import { GenericNodeFactory } from './customDiragramNodes/generic/genericNodeFactory';
+import { GenericNodeFactory } from './diagram/generic/genericNodeFactory';
 import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPointTypes';
-import { GenericNodeModel } from './customDiragramNodes/generic/genericNodeModel';
-import { GenericPortModel } from './customDiragramNodes/generic/genericPortModel';
+import { GenericNodeModel } from './diagram/generic/genericNodeModel';
+import { GenericPortModel } from './diagram/generic/genericPortModel';
 import { Engine } from 'babylonjs/Engines/engine';
-import { LineContainerComponent } from "../sharedComponents/lineContainerComponent"
-import { ButtonLineComponent } from '../sharedComponents/buttonLineComponent';
 import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
 import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
 import { Texture } from 'babylonjs/Materials/Textures/texture';
 import { Vector2, Vector3, Vector4, Matrix } from 'babylonjs/Maths/math';
-import { AlphaTestBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/alphaTestBlock';
-import { FragmentOutputBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock';
-import { ImageProcessingBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock';
-import { RGBAMergerBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/rgbaMergerBlock';
-import { RGBASplitterBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/rgbaSplitterBlock';
-import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/textureBlock';
-import { BonesBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/bonesBlock';
-import { InstancesBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/instancesBlock';
-import { MorphTargetsBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/morphTargetsBlock';
-import { VertexOutputBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/vertexOutputBlock';
-import { FogBlock } from 'babylonjs/Materials/Node/Blocks/Dual/fogBlock';
-import { AddBlock } from 'babylonjs/Materials/Node/Blocks/addBlock';
-import { ClampBlock } from 'babylonjs/Materials/Node/Blocks/clampBlock';
-import { MatrixMultiplicationBlock } from 'babylonjs/Materials/Node/Blocks/matrixMultiplicationBlock';
-import { MultiplyBlock } from 'babylonjs/Materials/Node/Blocks/multiplyBlock';
-import { Vector2TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector2TransformBlock';
-import { Vector3TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector3TransformBlock';
-import { Vector4TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector4TransformBlock';
+import { NodeListComponent } from './nodeList/nodeListComponent';
+import { PropertyTabComponent } from './propertyTab/propertyTabComponent';
 
 require("storm-react-diagrams/dist/style.min.css");
 require("./main.scss");
+require("./diagram/diagram.scss");
 
 /*
 Graph Editor Overview
@@ -60,7 +43,7 @@ interface IGraphEditorProps {
 }
 
 export class GraphEditor extends React.Component<IGraphEditorProps> {
-    private _engine:DiagramEngine;
+    private _engine: DiagramEngine;
     private _model: DiagramModel;
 
     private _nodes = new Array<GenericNodeModel>();
@@ -69,99 +52,99 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
      * Current row/column position used when adding new nodes
      */
     private _rowPos = new Array<number>()
-    
+
     /**
      * Creates a node and recursivly creates its parent nodes from it's input
      * @param nodeMaterialBlock 
      */
     public createNodeFromObject(
-        options:{
-            column:number,
-            nodeMaterialBlock?:NodeMaterialBlock                      
+        options: {
+            column: number,
+            nodeMaterialBlock?: NodeMaterialBlock
         }
-    ){
+    ) {
         // Update rows/columns
-        if(this._rowPos[options.column] == undefined){
+        if (this._rowPos[options.column] == undefined) {
             this._rowPos[options.column] = 0;
-        }else{
+        } else {
             this._rowPos[options.column]++;
         }
 
         // Create new node in the graph
         var outputNode = new GenericNodeModel();
         this._nodes.push(outputNode)
-        outputNode.setPosition(1600-(300*options.column), 200*this._rowPos[options.column])
+        outputNode.setPosition(1600 - (300 * options.column), 200 * this._rowPos[options.column])
         this._model.addAll(outputNode);
 
-        if(options.nodeMaterialBlock){
+        if (options.nodeMaterialBlock) {
             outputNode.block = options.nodeMaterialBlock
-            outputNode.headerLabels.push({text: options.nodeMaterialBlock.getClassName()})
+            outputNode.headerLabels.push({ text: options.nodeMaterialBlock.getClassName() })
 
             // Create output ports
-            options.nodeMaterialBlock._outputs.forEach((connection:any)=>{
+            options.nodeMaterialBlock._outputs.forEach((connection: any) => {
                 var outputPort = new GenericPortModel(connection.name, "output");
                 outputPort.syncWithNodeMaterialConnectionPoint(connection);
                 outputNode.addPort(outputPort)
             })
 
             // Create input ports and nodes if they exist
-            options.nodeMaterialBlock._inputs.forEach((connection)=>{
+            options.nodeMaterialBlock._inputs.forEach((connection) => {
                 var inputPort = new GenericPortModel(connection.name, "input");
                 inputPort.connection = connection;
                 outputNode.addPort(inputPort)
-                
-                if(connection._connectedPoint){
+
+                if (connection._connectedPoint) {
                     // Block is not a leaf node, create node for the given block type
                     var connectedNode;
-                    var existingNodes = this._nodes.filter((n)=>{return n.block == (connection as any)._connectedPoint._ownerBlock});
-                    if(existingNodes.length == 0){
-                        connectedNode = this.createNodeFromObject({column: options.column+1, nodeMaterialBlock: connection._connectedPoint._ownerBlock});
-                    }else{
+                    var existingNodes = this._nodes.filter((n) => { return n.block == (connection as any)._connectedPoint._ownerBlock });
+                    if (existingNodes.length == 0) {
+                        connectedNode = this.createNodeFromObject({ column: options.column + 1, nodeMaterialBlock: connection._connectedPoint._ownerBlock });
+                    } else {
                         connectedNode = existingNodes[0];
                     }
-           
+
                     let link = connectedNode.ports[connection._connectedPoint.name].link(inputPort);
                     this._model.addAll(link);
-                    
-                }else {
+
+                } else {
                     // Create value node for the connection
                     var type = ""
-                    if(connection.type == NodeMaterialBlockConnectionPointTypes.Texture){
+                    if (connection.type == NodeMaterialBlockConnectionPointTypes.Texture) {
                         type = "Texture"
-                    } else if(connection.type == NodeMaterialBlockConnectionPointTypes.Matrix){
+                    } else if (connection.type == NodeMaterialBlockConnectionPointTypes.Matrix) {
                         type = "Matrix"
-                    } else if(connection.type & NodeMaterialBlockConnectionPointTypes.Vector3OrColor3){
+                    } else if (connection.type & NodeMaterialBlockConnectionPointTypes.Vector3OrColor3) {
                         type = "Vector3"
-                    } else if(connection.type & NodeMaterialBlockConnectionPointTypes.Vector2){
+                    } else if (connection.type & NodeMaterialBlockConnectionPointTypes.Vector2) {
                         type = "Vector2"
-                    }else if(connection.type & NodeMaterialBlockConnectionPointTypes.Vector3OrColor3OrVector4OrColor4){
+                    } else if (connection.type & NodeMaterialBlockConnectionPointTypes.Vector3OrColor3OrVector4OrColor4) {
                         type = "Vector4"
                     }
-                    
+
                     // Create links
-                    var localNode = this.addValueNode(type, options.column+1, connection);
+                    var localNode = this.addValueNode(type, options.column + 1, connection);
                     var ports = localNode.getPorts()
-                    for(var key in ports){
+                    for (var key in ports) {
                         let link = (ports[key] as GenericPortModel).link(inputPort);
                         this._model.addAll(link);
                     }
                 }
             })
         }
-        
+
         return outputNode;
     }
 
-    componentDidMount(){
-        if(this.props.globalState.hostDocument){
+    componentDidMount() {
+        if (this.props.globalState.hostDocument) {
             var widget = (this.refs["test"] as DiagramWidget);
-            widget.setState({document: this.props.globalState.hostDocument})
+            widget.setState({ document: this.props.globalState.hostDocument })
             this.props.globalState.hostDocument!.addEventListener("keyup", widget.onKeyUpPointer as any, false);
         }
     }
 
-    componentWillUnmount(){
-        if(this.props.globalState.hostDocument){
+    componentWillUnmount() {
+        if (this.props.globalState.hostDocument) {
             var widget = (this.refs["test"] as DiagramWidget);
             this.props.globalState.hostDocument!.removeEventListener("keyup", widget.onKeyUpPointer as any, false);
         }
@@ -173,81 +156,81 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
         // setup the diagram engine
         this._engine = new DiagramEngine();
         this._engine.installDefaultFactories()
-        this._engine.registerNodeFactory(new GenericNodeFactory());
+        this._engine.registerNodeFactory(new GenericNodeFactory(this.props.globalState));
 
         // setup the diagram model
         this._model = new DiagramModel();
 
         // Listen to events to connect/disconnect blocks or
         this._model.addListener({
-            linksUpdated: (e)=>{
-                if(!e.isCreated){
+            linksUpdated: (e) => {
+                if (!e.isCreated) {
                     // Link is deleted
                     console.log("link deleted");
                     var link = GenericPortModel.SortInputOutput(e.link.sourcePort as GenericPortModel, e.link.targetPort as GenericPortModel);
                     console.log(link)
-                    if(link){
-                        if(link.output.connection && link.input.connection){
+                    if (link) {
+                        if (link.output.connection && link.input.connection) {
                             // Disconnect standard nodes
-                            console.log("disconnected "+link.output.connection.name+" from "+link.input.connection.name)
+                            console.log("disconnected " + link.output.connection.name + " from " + link.input.connection.name)
                             link.output.connection.disconnectFrom(link.input.connection)
                             link.input.syncWithNodeMaterialConnectionPoint(link.input.connection)
                             link.output.syncWithNodeMaterialConnectionPoint(link.output.connection)
-                        }else if(link.input.connection && link.input.connection.value){
+                        } else if (link.input.connection && link.input.connection.value) {
                             console.log("value link removed");
                             link.input.connection.value = null;
-                        }else{
+                        } else {
                             console.log("invalid link error");
-                        }   
+                        }
                     }
-                }else{
+                } else {
                     console.log("link created")
                     console.log(e.link.sourcePort)
                 }
                 e.link.addListener({
-                    sourcePortChanged: ()=>{
+                    sourcePortChanged: () => {
                         console.log("port change")
                     },
-                    targetPortChanged: ()=>{
+                    targetPortChanged: () => {
                         // Link is created with a target port
                         console.log("Link set to target")
                         var link = GenericPortModel.SortInputOutput(e.link.sourcePort as GenericPortModel, e.link.targetPort as GenericPortModel);
-                        
-                        if(link){
-                            if(link.output.connection && link.input.connection){
-                               console.log("link standard blocks")
-                               link.output.connection.connectTo(link.input.connection)
-                            }else if(link.input.connection){
+
+                        if (link) {
+                            if (link.output.connection && link.input.connection) {
+                                console.log("link standard blocks")
+                                link.output.connection.connectTo(link.input.connection)
+                            } else if (link.input.connection) {
                                 console.log("link value to standard block")
                                 link.input.connection.value = link.output.getValue();
-                                
+
                             }
-                            if(this.props.globalState.nodeMaterial){
+                            if (this.props.globalState.nodeMaterial) {
                                 this.props.globalState.nodeMaterial.build()
                             }
                         }
                     }
-                    
+
                 })
-                
+
             },
-            nodesUpdated: (e)=>{
-                if(e.isCreated){
+            nodesUpdated: (e) => {
+                if (e.isCreated) {
                     console.log("new node")
-                }else{
+                } else {
                     console.log("node deleted")
                 }
             }
         })
 
         // Load graph of nodes from the material
-        if(this.props.globalState.nodeMaterial){
-            var material:any = this.props.globalState.nodeMaterial;
-            material._vertexOutputNodes.forEach((n:any)=>{
-                this.createNodeFromObject({column: 0, nodeMaterialBlock: n});
+        if (this.props.globalState.nodeMaterial) {
+            var material: any = this.props.globalState.nodeMaterial;
+            material._vertexOutputNodes.forEach((n: any) => {
+                this.createNodeFromObject({ column: 0, nodeMaterialBlock: n });
             })
-            material._fragmentOutputNodes.forEach((n:any)=>{
-                this.createNodeFromObject({column: 0, nodeMaterialBlock: n});
+            material._fragmentOutputNodes.forEach((n: any) => {
+                this.createNodeFromObject({ column: 0, nodeMaterialBlock: n });
             })
         }
 
@@ -258,72 +241,72 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
         this._engine.setDiagramModel(this._model);
     }
 
-    addNodeFromClass(ObjectClass:typeof NodeMaterialBlock){
-        var block = new ObjectClass(ObjectClass.prototype.getClassName()+"sdfsdf")
-        var localNode = this.createNodeFromObject({column: 0, nodeMaterialBlock: block})
+    addNodeFromClass(ObjectClass: typeof NodeMaterialBlock) {
+        var block = new ObjectClass(ObjectClass.prototype.getClassName() + "sdfsdf")
+        var localNode = this.createNodeFromObject({ column: 0, nodeMaterialBlock: block })
         var widget = (this.refs["test"] as DiagramWidget);
-       
+
         this.forceUpdate()
 
         // This is needed to fix link offsets when created, (eg. create a fog block)
         // Todo figure out how to correct this without this
         setTimeout(() => {
-            widget.startFiringAction(new MoveCanvasAction(1,0, this._model));
+            widget.startFiringAction(new MoveCanvasAction(1, 0, this._model));
         }, 500);
 
         return localNode
     }
 
-    addValueNode(type: string, column = 0, connection?: NodeMaterialConnectionPoint){
-        var localNode = this.createNodeFromObject({column: column})
+    addValueNode(type: string, column = 0, connection?: NodeMaterialConnectionPoint) {
+        var localNode = this.createNodeFromObject({ column: column })
         var outPort = new GenericPortModel(type, "output");
-        if(type == "Texture"){
-            outPort.getValue = ()=>{
+        if (type == "Texture") {
+            outPort.getValue = () => {
                 return localNode.texture;
             }
-            if(connection && connection.value){
+            if (connection && connection.value) {
                 localNode.texture = connection.value
-            }else{
+            } else {
                 localNode.texture = new Texture(null, Engine.LastCreatedScene)
             }
-        }else if(type == "Vector2"){
-            outPort.getValue = ()=>{
+        } else if (type == "Vector2") {
+            outPort.getValue = () => {
                 return localNode.vector2;
             }
-            if(connection && connection.value){
+            if (connection && connection.value) {
                 localNode.vector2 = connection.value
-            }else{
+            } else {
                 localNode.vector2 = new Vector2()
             }
-        }else if(type == "Vector3"){
-            outPort.getValue = ()=>{
+        } else if (type == "Vector3") {
+            outPort.getValue = () => {
                 return localNode.vector3;
             }
-            if(connection && connection.value){
+            if (connection && connection.value) {
                 localNode.vector3 = connection.value
-            }else{
+            } else {
                 localNode.vector3 = new Vector3()
             }
-        }else if(type == "Vector4"){
-            outPort.getValue = ()=>{
+        } else if (type == "Vector4") {
+            outPort.getValue = () => {
                 return localNode.vector4;
             }
-            if(connection && connection.value){
+            if (connection && connection.value) {
                 localNode.vector4 = connection.value
-            }else{
-                localNode.vector4 = new Vector4(0,0,0,1)
+            } else {
+                localNode.vector4 = new Vector4(0, 0, 0, 1)
             }
-        }else if(type == "Matrix"){
-            outPort.getValue = ()=>{
+        } else if (type == "Matrix") {
+            outPort.getValue = () => {
                 return localNode.matrix;
             }
-            if(connection && connection.value){
+            if (connection && connection.value) {
                 localNode.matrix = connection.value
-            }else{
+            } else {
                 localNode.matrix = new Matrix()
             }
-        }else{
-            console.log("Node type "+type+"is not supported")
+        } else {
+            console.log("Node type " + type + "is not supported")
         }
         localNode.addPort(outPort)
         this.forceUpdate()
@@ -331,53 +314,17 @@ export class GraphEditor extends React.Component<IGraphEditorProps> {
         return localNode;
     }
 
-    
-
-    // Block types used to create the menu from
-    allBlocks = {
-        Fragment: [AlphaTestBlock, FragmentOutputBlock, ImageProcessingBlock, RGBAMergerBlock, RGBASplitterBlock, TextureBlock],
-        Vertex: [BonesBlock, InstancesBlock, MorphTargetsBlock, VertexOutputBlock],
-        Dual: [FogBlock],
-        Other: [AddBlock, ClampBlock, MatrixMultiplicationBlock, MultiplyBlock, Vector2TransformBlock, Vector3TransformBlock, Vector4TransformBlock],
-        Value: ["Texture", "Vector2", "Vector3", "Matrix"],
-    }
-
     render() {
-        // Create node menu
-        var blockMenu = []
-        for(var key in this.allBlocks){
-            var blockList = (this.allBlocks as any)[key].map((b:any)=>{
-                var label = typeof b === "string" ? b : b.prototype.getClassName()
-                var onClick =typeof b === "string" ? () => {this.addValueNode(b)} : () => {this.addNodeFromClass(b)};
-                return  <ButtonLineComponent label={label} onClick={onClick} />
-            })
-            blockMenu.push(
-                <LineContainerComponent  title={key+" blocks"}>
-                    {blockList}
-                </LineContainerComponent>
-            )
-        }
-
         return (
-            <div id="node-editor-graph-root" style={{
-                display: "flex",
-                height: "100%",
-                background: "#464646",
-            }}>
+            <div id="node-editor-graph-root">
                 {/* Node creation menu */}
-                <div id="actionTabs" style={{width: "170px", borderRightStyle: "solid", borderColor: "grey", borderWidth: "1px" }} >
-                    <div className="tabs" style={{gridTemplateRows: "0px 1fr"}}>
-                        <div className="labels"/>
-                        <div className="panes">
-                            <div className="pane">
-                                {blockMenu}
-                            </div>
-                        </div>
-                    </div>
-                </div>
-                
+                <NodeListComponent globalState={this.props.globalState} onAddValueNode={b => this.addValueNode(b)} onAddNodeFromClass={b => this.addNodeFromClass(b)} />
+
                 {/* The node graph diagram */}
-                <DiagramWidget deleteKeys={[46]} ref={"test"} inverseZoom={true} className="srd-demo-canvas" diagramEngine={this._engine} maxNumberPointsPerLink={0} />
+                <DiagramWidget deleteKeys={[46]} ref={"test"} inverseZoom={true} className="diagram-container" diagramEngine={this._engine} maxNumberPointsPerLink={0} />
+
+                {/* Property tab */}
+                <PropertyTabComponent globalState={this.props.globalState} />
             </div>
         );
 

+ 21 - 888
nodeEditor/src/components/main.scss

@@ -1,892 +1,25 @@
-
 #node-editor-graph-root {
-    $line-padding-left: 2px;
+    display: grid;
+    grid-template-rows: 100%;
+    grid-template-columns: 200px calc(100% - 500px) 300px;
+    height: 100%;
+    width: 100%;
+    background: #464646;
+    font: 14px "acumin-pro";   
+}
+
+#nodeList {
+    grid-row: 1;
+    grid-column: 1;
+}
 
-    #inspector-host {
-        position: absolute;
-        right: 0px;
-        top:0px;
-        bottom: 0px;
-    }
-    
-    #__resizable_base__ {
-        display: none;
-    }
-    
-    #actionTabs {
-        background: #333333;
-        height: 100%;
-        margin: 0;
-        padding: 0;
-        display: grid;
-        grid-template-rows: auto 1fr;
-        font: 14px "Arial";    
-        overflow: hidden;
-    
-        .hoverIcon:hover {
-            opacity: 0.8;
-        }
-    
-        #header {
-            height: 30px;
-            font-size: 16px;
-            color: white;
-            background: #222222;
-            grid-row: 1;
-            text-align: center;
-            display: grid;
-            grid-template-columns: 30px 1fr 50px;        
-            -webkit-user-select: none; 
-            -moz-user-select: none;   
-            -ms-user-select: none;    
-            user-select: none;                
-    
-            #logo {
-                grid-column: 1; 
-                width: 24px;
-                height: 24px;
-                display: flex;
-                align-self: center;   
-                justify-self: center;
-            }        
-    
-            #back {
-                grid-column: 1; 
-                display: grid;
-                align-self: center;   
-                justify-self: center;
-                cursor: pointer;
-            }              
-    
-            #title {
-                grid-column: 2; 
-                display: grid;
-                align-items: center;   
-                text-align: center;
-            }
-    
-            #commands {
-                grid-column: 3; 
-                display: grid;
-                align-items: center;  
-                grid-template-columns: 1fr 1fr;   
-                
-                .expand {
-                    grid-column: 1;
-                    display: grid;
-                    align-items: center;   
-                    justify-items: center;
-                    cursor: pointer;     
-                }
-    
-                .close {
-                    grid-column: 2;
-                    display: grid;
-                    align-items: center;   
-                    justify-items: center;
-                    cursor: pointer;     
-                }        
-            }
-        }
-    
-        .tabs {
-            display: grid;
-            grid-row: 2;
-            grid-template-rows: 40px 1fr;
-            font: 14px "Arial";
-            overflow: hidden;
-    
-            .labels {
-                grid-row: 1;
-                display: flex;
-                align-items: center;
-                justify-items: center;
-                border-bottom: 1px solid #ffffff; 
-                margin: 0;
-                padding: 0;         
-    
-                .label {
-                    font-size: 24px;
-                    color: white;
-                    width: 40px;
-                    display: flex;
-                    align-content: center;
-                    justify-content: center;
-                    border: 1px solid transparent;            
-                    border-bottom: none;    
-                    background: #333333;
-                    padding: 5px;  
-                    height: 28px;
-                    cursor: pointer;
-    
-                    &.active {
-                        border-color: #ffffff;  
-                        border-bottom: 2px solid transparent;           
-                        margin-bottom: -2px;
-                    }
-                }
-            }
-    
-            .panes {
-                grid-row: 2;
-    
-                display: grid;
-                grid-template-rows: 100%;
-    
-                overflow: hidden;
-    
-                .infoMessage {
-                    opacity: 0.5;
-                    color: white;
-                    margin: 15px 5px 0px 5px;
-                                    
-                }
-    
-                .pane {
-                    color: white;
-    
-                    overflow-x: hidden;
-                    overflow-y: auto;
-                    height: 100%;
-    
-                    -webkit-user-select: none; 
-                    -moz-user-select: none;   
-                    -ms-user-select: none;    
-                    user-select: none;     
-    
-                    .underline {
-                        border-bottom: 0.5px solid rgba(255, 255, 255, 0.5);
-                    }
-                    
-                    .textureLinkLine {
-                        display: grid;
-                        grid-template-columns: auto 1fr;
-    
-                        .debug {
-                            grid-column: 1;
-                            margin-left: 5px;
-                            margin-right: 5px;
-                            display: grid;
-                            align-items: center; 
-                            justify-items: center;                          
-                            cursor: pointer;
-                            opacity: 0.5;
-    
-                            &.selected {
-                                opacity: 1.0;
-                            }
-                        }
-    
-                        .textLine {
-                            grid-column: 2;
-                        }
-                    }
-    
-                    .messageLine {
-                        text-align: center;
-                        font-size: 12px;
-                        font-style: italic;
-                        opacity: 0.6;
-                    }
-    
-                    .iconMessageLine {
-                        padding-left: $line-padding-left;
-                        height: 30px;
-                        display: grid;
-                        grid-template-columns: 30px 1fr;
-    
-                        .icon {
-                            grid-column: 1;
-                            display: grid;
-                            align-items: center;
-                            justify-items: center;
-                        }
-    
-                        .value {
-                            grid-column: 2;
-                            display: flex;
-                            align-items: center;
-                        }
-                    }
-    
-                    .textLine {
-                        padding-left: $line-padding-left;
-                        height: 30px;
-                        display: grid;
-                        grid-template-columns: 1fr auto;
-    
-                        .label {
-                            grid-column: 1;
-                            display: flex;
-                            align-items: center;
-                        }
-    
-                        .link-value {
-                            grid-column: 2;
-                            white-space: nowrap;
-                            text-overflow: ellipsis;
-                            overflow: hidden;
-                            text-align: end;
-                            opacity: 0.8;
-                            margin:5px;
-                            margin-top: 6px;
-                            max-width: 140px;
-                            text-decoration: underline;
-                            cursor: pointer;
-                        }
-    
-                        .value {
-                            grid-column: 2;
-                            white-space: nowrap;
-                            text-overflow: ellipsis;
-                            overflow: hidden;
-                            text-align: end;
-                            opacity: 0.8;
-                            margin:5px;
-                            margin-top: 6px;
-                            max-width: 200px;
-                            -webkit-user-select: text; 
-                            -moz-user-select: text;   
-                            -ms-user-select: text;    
-                            user-select: text;                
-    
-                            &.check {
-                                color: green;
-                            }
-    
-                            &.uncheck {
-                                color: red;
-                            }  
-                        }
-                    }
-    
-                    .textInputLine {
-                        padding-left: $line-padding-left;
-                        height: 30px;
-                        display: grid;
-                        grid-template-columns: 1fr 120px;
-    
-                        .label {
-                            grid-column: 1;
-                            display: flex;
-                            align-items: center;
-                        }
-    
-                        .value {                        
-                            display: flex;
-                            align-items: center;
-                            grid-column: 2;
-                            
-                            input {
-                                width: 110px;
-                            }
-                        }
-                    }
-    
-                    .buttonLine {
-                        height: 30px;
-                        display: grid;
-                        align-items: center;
-                        justify-items: stretch;
-    
-                        input[type="file"] {
-                            display: none;
-                        }
-    
-                        .file-upload {
-                            background: transparent;
-                            border: 1px solid rgb(51, 122, 183);
-                            margin: 0px 10px;
-                            color:white;
-                            padding: 4px 5px;
-                            opacity: 0.9;
-                            cursor: pointer;
-                            text-align: center;
-                        }
-    
-                        .file-upload:hover {
-                            opacity: 1.0;
-                        }
-    
-                        .file-upload:active {
-                            transform: scale(0.98);
-                            transform-origin: 0.5 0.5;
-                        }
-    
-                        button {
-                            background: #222222;
-                            border: 1px solid rgb(51, 122, 183);
-                            margin: 5px 10px 5px 10px;
-                            color:white;
-                            padding: 4px 5px;
-                            opacity: 0.9;
-                        }
-    
-                        button:hover {
-                            opacity: 1.0;
-                        }
-    
-                        button:active {
-                            background: #282828;
-                        }   
-                        
-                        button:focus {
-                            border: 1px solid rgb(51, 122, 183);
-                            outline: 0px;
-                        }  
-                    }
-    
-                    .radioLine {
-                        padding-left: $line-padding-left;
-                        height: 30px;
-                        display: grid;
-                        grid-template-columns: 1fr 24px;
-    
-                        .label {
-                            grid-column: 1;
-                            display: flex;
-                            align-items: center;
-                        }
-    
-                        .radioContainer {
-                            display: flex;
-                            align-items: center;
-    
-                            .radio {
-                                grid-column: 2;                        
-                                display: none;
-    
-                                &:checked + label:before {
-                                    border-color: rgb(51, 122, 183);
-                                }
-                                &:checked + label:after {
-                                    transform: scale(1);
-                                }                        
-                            }
-    
-                            .labelForRadio {
-                                display: inline-block;
-                                height: 14px;
-                                position: relative;
-                                padding: 0 24px;
-                                margin-bottom: 0;
-                                cursor: pointer;
-                                vertical-align: bottom;
-                                &:before, &:after {
-                                    position: absolute;            
-                                    content: '';  
-                                    border-radius: 50%;
-                                    transition: all .3s ease;
-                                    transition-property: transform, border-color;
-                                }
-                                &:before {
-                                    left: 0px;
-                                    top: 0;
-                                    width: 16px;
-                                    height: 16px;
-                                    border: 2px solid white;
-                                }
-                                &:after {
-                                    top: 6px;
-                                    left: 6px;
-                                    width: 8px;
-                                    height: 8px;
-                                    transform: scale(0);
-                                    background:rgb(51, 122, 183);
-                                }
-                            }
-                        }
-                    }
-    
-                    .vector3Line {
-                        padding-left:$line-padding-left;                    
-                        display: grid;
-    
-                        .firstLine {
-                            display: grid;
-                            grid-template-columns: 1fr auto 20px;
-                            height: 30px;
-    
-                            .label {
-                                grid-column: 1;
-                                display: flex;
-                                align-items: center;
-                            }
-    
-                            .vector {
-                                grid-column: 2;
-                                display: flex;
-                                align-items: center;
-                                text-align: right;
-                                opacity: 0.8;
-                            }
-    
-                            .expand {
-                                grid-column: 3;
-                                display: grid;
-                                align-items: center;
-                                justify-items: center;
-                                cursor: pointer;
-                            }
-                        }
-    
-                        .secondLine {
-                            display: grid;
-                            padding-right: 5px;  
-                            border-left: 1px solid rgb(51, 122, 183);
-    
-                            .numeric {
-                                display: grid;
-                                grid-template-columns: 1fr auto;
-                            }
-    
-                            .numeric-label {
-                                text-align: right;
-                                grid-column: 1;
-                                display: flex;
-                                align-items: center;                            
-                                justify-self: right;
-                                margin-right: 10px;                          
-                            }
-    
-                            .numeric-value {
-                                width: 120px;
-                                grid-column: 2;
-                                display: flex;
-                                align-items: center;  
-                                border: 1px solid  rgb(51, 122, 183);
-                            }                        
-                        }
-                    }
-    
-                    .checkBoxLine {
-                        padding-left: $line-padding-left;
-                        height: 30px;
-                        display: grid;
-                        grid-template-columns: 1fr auto;
-    
-    
-                        .label {
-                            grid-column: 1;
-                            display: flex;
-                            align-items: center;
-                        }
-    
-                        .checkBox {
-                            grid-column: 2;
-                            
-                            display: flex;
-                            align-items: center;
-    
-                            .lbl {
-                                position: relative;
-                                display: block;
-                                height: 14px;
-                                width: 34px;
-                                margin-right: 5px;
-                                background: #898989;
-                                border-radius: 100px;
-                                cursor: pointer;
-                                transition: all 0.3s ease;
-                            }
-    
-                            .lbl:after {
-                                position: absolute;
-                                left: 3px;
-                                top: 2px;
-                                display: block;
-                                width: 10px;
-                                height: 10px;
-                                border-radius: 100px;
-                                background: #fff;
-                                box-shadow: 0px 3px 3px rgba(0,0,0,0.05);
-                                content: '';
-                                transition: all 0.15s ease;
-                            }
-    
-                            .lbl:active:after { 
-                                transform: scale(1.15, 0.85); 
-                            }
-    
-                            .cbx:checked ~ label { 
-                                background: rgb(51, 122, 183);
-                            }
-    
-                            .cbx:checked ~ label:after {
-                                left: 20px;
-                                background: rgb(22, 73, 117);
-                            }
-    
-                            .hidden { 
-                                display: none; 
-                            }               
-                        }                    
-                    }                   
-    
-                    .textureLine {                   
-                        display: grid;
-                        grid-template-rows: 30px auto;
-    
-                        .control {
-                            margin-top: 2px;
-                            grid-row: 1;
-                            display: grid;
-                            grid-template-columns: 1fr 40px 40px 40px 40px 40px 1fr;
-    
-                            .red {
-                                grid-column: 2;
-                            }
-    
-                            .green {
-                                grid-column: 3;
-                            }
-    
-                            .blue {
-                                grid-column: 4;
-                            }
-    
-                            .alpha {
-                                grid-column: 5;
-                            }                        
-    
-                            .all {
-                                grid-column: 6;
-                            }                        
-                        }
-    
-                        .control3D {
-                            margin-top: 2px;
-                            grid-row: 1;
-                            display: grid;
-                            grid-template-columns: 1fr 40px 40px 40px 40px 40px 40px 1fr;
-    
-                            .px {
-                                grid-column: 2;
-                            }
-    
-                            .nx {
-                                grid-column: 3;
-                            }
-    
-                            .py {
-                                grid-column: 4;
-                            }
-    
-                            .ny {
-                                grid-column: 5;
-                            }   
-    
-                            .pz {
-                                grid-column: 6;
-                            }
-    
-                            .nz {
-                                grid-column: 7;
-                            }                     
-                        }                    
-    
-                        .command {
-                            border: 1px solid transparent;
-                            background:transparent;
-                            color: white;
-                        }
-    
-                        .selected {
-                            border: 1px solid rgb(51, 122, 183);
-                        }
-    
-                        .preview {
-                            grid-row: 2;
-                            display: grid;
-                            align-self: center;
-                            justify-self: center;
-                            height: 256px;
-                            width: 256px;
-                            margin-top: 5px;
-                            margin-bottom: 5px;
-                            border: 2px solid rgba(255, 255, 255, 0.4);
-                        }
-                    }
-    
-                    .gltf-extension-property {
-                        margin-left: 30px;
-                        border-left: 1px solid rgb(51, 122, 183);
-                    }
-    
-                    .floatLine {
-                        padding-left: $line-padding-left;
-                        height: 30px;
-                        display: grid;
-                        grid-template-columns: 1fr 120px;
-    
-    
-                        .label {
-                            grid-column: 1;
-                            display: flex;
-                            align-items: center;
-                        }
-    
-                        .value {
-                            grid-column: 2;
-                            
-                            display: flex;
-                            align-items: center;
-                            
-                            input {
-                                width: 110px;
-                            }
-                        }
-                    }
-    
-                    .sliderLine {
-                        padding-left: 2px;
-                        height: 30px;
-                        display: grid;
-                        grid-template-columns: 1fr auto;
-    
-                        .label {
-                            grid-column: 1;
-                            display: flex;
-                            align-items: center;
-                        }
-    
-                        .slider {
-                            grid-column: 2;
-                            margin-right: 5px;
-                            
-                            display: flex;
-                            align-items: center;
-    
-                            .range {
-                                -webkit-appearance: none;
-                                width: 120px;
-                                height: 6px;
-                                background: #d3d3d3;
-                                border-radius: 5px;
-                                outline: none;
-                                opacity: 0.7;
-                                -webkit-transition: .2s;
-                                transition: opacity .2s;
-                            }
-                            
-                            .range:hover {
-                                opacity: 1;
-                            }
-                            
-                            .range::-webkit-slider-thumb {
-                                -webkit-appearance: none;
-                                appearance: none;
-                                width: 14px;
-                                height: 14px;
-                                border-radius: 50%;
-                                background: rgb(51, 122, 183);
-                                cursor: pointer;
-                            }
-                            
-                            .range::-moz-range-thumb {
-                                width: 14px;
-                                height: 14px;
-                                border-radius: 50%;
-                                background: rgb(51, 122, 183);
-                                cursor: pointer;
-                            }
-                        }                    
-                    }       
-                    
-                    .color3Line {
-                        padding-left: $line-padding-left;
-                        display: grid;
-    
-                        .firstLine {
-                            height: 30px;
-                            display: grid;
-                            grid-template-columns: 1fr auto 20px 20px;
-    
-                            .label {
-                                grid-column: 1;
-                                display: flex;
-                                align-items: center;
-                            }
-    
-                            .color3 {
-                                grid-column: 2;
-                                
-                                display: flex;
-                                align-items: center;   
-    
-                                input[type="color"] {
-                                    -webkit-appearance: none;
-                                    border: 1px solid rgba(255, 255, 255, 0.5);
-                                    padding: 0;
-                                    width: 30px;
-                                    height: 20px;
-                                }
-                                input[type="color"]::-webkit-color-swatch-wrapper {
-                                    padding: 0;
-                                }
-                                input[type="color"]::-webkit-color-swatch {
-                                    border: none;
-                                }
-                                
-                                input {
-                                    margin-right: 5px;
-                                }
-                            }
-    
-                            .copy {
-                                grid-column: 3;
-                                display: grid;
-                                align-items: center;
-                                justify-items: center;
-                                cursor: pointer;
-                            }
-    
-                            .expand {
-                                grid-column: 4;
-                                display: grid;
-                                align-items: center;
-                                justify-items: center;
-                                cursor: pointer;
-                            }
-                        }   
-    
-                        .secondLine {
-                            display: grid;
-                            padding-right: 5px;  
-                            border-left: 1px solid rgb(51, 122, 183);
-    
-                            .numeric {
-                                display: grid;
-                                grid-template-columns: 1fr auto;
-                            }
-    
-                            .numeric-label {
-                                text-align: right;
-                                grid-column: 1;
-                                display: flex;
-                                align-items: center;                            
-                                justify-self: right;
-                                margin-right: 10px;                          
-                            }
-    
-                            .numeric-value {
-                                width: 120px;
-                                grid-column: 2;
-                                display: flex;
-                                align-items: center;  
-                                border: 1px solid  rgb(51, 122, 183);
-                            }                        
-                        }                  
-                    }     
-                    
-                    .listLine {
-                        padding-left: $line-padding-left;
-                        height: 30px;
-                        display: grid;
-                        grid-template-columns: 1fr auto;
-    
-    
-                        .label {
-                            grid-column: 1;
-                            display: flex;
-                            align-items: center;
-                        }
-    
-                        .options {
-                            grid-column: 2;
-                            
-                            display: flex;
-                            align-items: center;   
-                            margin-right: 5px;
-    
-                            select {
-                                width: 115px;
-                            }
-                        }                    
-                    }                   
-    
-                    .paneContainer {
-                        margin-top: 3px;
-                        display:grid;
-                        grid-template-rows: 100%;
-                        grid-template-columns: 100%;
-                        
-                        .paneList {
-                            border-left: 3px solid transparent;
-                        }
-    
-                        &:hover {  
-                            .paneList {                      
-                                border-left: 3px solid rgba(51, 122, 183, 0.8);
-                            }
-    
-                            .paneContainer-content {
-                                .header {
-                                    .title {   
-                                        border-left: 3px solid rgb(51, 122, 183);
-                                    }
-                                }
-                            }
-                        }
-                        
-                        .paneContainer-highlight-border {
-                            grid-row: 1;
-                            grid-column: 1;
-                            opacity: 1;
-                            border: 3px solid red;
-                            transition: opacity 250ms;
-                            pointer-events: none;
-                            
-                            &.transparent {
-                                opacity: 0;
-                            }
-                        }
-    
-                        .paneContainer-content {
-                            grid-row: 1;
-                            grid-column: 1;
-    
-                            .header {
-                                display: grid;
-                                grid-template-columns: 1fr auto;
-                                background: #555555;    
-                                height: 30px;   
-                                padding-right: 5px;                        
-                                cursor: pointer;
-                                
-                                .title {                                
-                                    border-left: 3px solid transparent;
-                                    padding-left: 5px;
-                                    grid-column: 1;
-                                    display: flex;
-                                    align-items: center;
-                                }
-    
-                                .collapse {
-                                    grid-column: 2;
-                                    display: flex;
-                                    align-items: center;  
-                                    justify-items: center;
-                                    transform-origin: center;
-    
-                                    &.closed {
-                                        transform: rotate(180deg);
-                                    }
-                                }                        
-                            }
-    
-                            .paneList > div:not(:last-child) {
-                                border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
-                            }
-    
-                            .fragment > div:not(:last-child)  {
-                                border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
+.diagram-container {
+    grid-row: 1;
+    grid-column: 2;
+    background: #222222;
 }
 
+#propertyTab {
+    grid-row: 1;
+    grid-column: 3;
+}

+ 123 - 0
nodeEditor/src/components/nodeList/nodeList.scss

@@ -0,0 +1,123 @@
+#nodeList {
+    background: #333333;
+    height: 100%;
+    margin: 0;
+    padding: 0;
+    display: grid;
+    width: 200px; 
+    overflow: hidden;
+
+    .pane {
+        color: white;
+
+        overflow-x: hidden;
+        overflow-y: auto;
+        height: 100%;
+
+        -webkit-user-select: none; 
+        -moz-user-select: none;   
+        -ms-user-select: none;    
+        user-select: none;     
+
+        .underline {
+            border-bottom: 0.5px solid rgba(255, 255, 255, 0.5);
+        }
+    
+        .buttonLine {
+            height: 30px;
+            display: grid;
+            align-items: center;
+            justify-items: stretch;
+
+            button {
+                background: #222222;
+                border: 1px solid rgb(51, 122, 183);
+                margin: 5px 10px 5px 10px;
+                color:white;
+                padding: 4px 5px;
+                opacity: 0.9;
+            }
+
+            button:hover {
+                opacity: 1.0;
+            }
+
+            button:active {
+                background: #282828;
+            }   
+            
+            button:focus {
+                border: 1px solid rgb(51, 122, 183);
+                outline: 0px;
+            }  
+        }
+
+        .paneContainer {
+            margin-top: 3px;
+            display:grid;
+            grid-template-rows: 100%;
+            grid-template-columns: 100%;
+            
+            .paneList {
+                border-left: 3px solid transparent;
+            }
+
+            &:hover {  
+                .paneList {                      
+                    border-left: 3px solid rgba(51, 122, 183, 0.8);
+                }
+
+                .paneContainer-content {
+                    .header {
+                        .title {   
+                            border-left: 3px solid rgb(51, 122, 183);
+                        }
+                    }
+                }
+            }
+
+            .paneContainer-content {
+                grid-row: 1;
+                grid-column: 1;
+
+                .header {
+                    display: grid;
+                    grid-template-columns: 1fr auto;
+                    background: #555555;    
+                    height: 30px;   
+                    padding-right: 5px;                        
+                    cursor: pointer;
+                    
+                    .title {                                
+                        border-left: 3px solid transparent;
+                        padding-left: 5px;
+                        grid-column: 1;
+                        display: flex;
+                        align-items: center;
+                    }
+
+                    .collapse {
+                        grid-column: 2;
+                        display: flex;
+                        align-items: center;  
+                        justify-items: center;
+                        transform-origin: center;
+
+                        &.closed {
+                            transform: rotate(180deg);
+                        }
+                    }                        
+                }
+
+                .paneList > div:not(:last-child) {
+                    border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
+                }
+
+                .fragment > div:not(:last-child)  {
+                    border-bottom: 0.5px solid rgba(255, 255, 255, 0.1);
+                }
+            }
+        }
+    }    
+}
+

+ 71 - 0
nodeEditor/src/components/nodeList/nodeListComponent.tsx

@@ -0,0 +1,71 @@
+
+import * as React from "react";
+import { GlobalState } from '../../globalState';
+import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
+import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
+import { AlphaTestBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/alphaTestBlock';
+import { FragmentOutputBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/fragmentOutputBlock';
+import { ImageProcessingBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/imageProcessingBlock';
+import { RGBAMergerBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/rgbaMergerBlock';
+import { RGBASplitterBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/rgbaSplitterBlock';
+import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/textureBlock';
+import { BonesBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/bonesBlock';
+import { InstancesBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/instancesBlock';
+import { MorphTargetsBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/morphTargetsBlock';
+import { VertexOutputBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/vertexOutputBlock';
+import { FogBlock } from 'babylonjs/Materials/Node/Blocks/Dual/fogBlock';
+import { AddBlock } from 'babylonjs/Materials/Node/Blocks/addBlock';
+import { ClampBlock } from 'babylonjs/Materials/Node/Blocks/clampBlock';
+import { MatrixMultiplicationBlock } from 'babylonjs/Materials/Node/Blocks/matrixMultiplicationBlock';
+import { MultiplyBlock } from 'babylonjs/Materials/Node/Blocks/multiplyBlock';
+import { Vector2TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector2TransformBlock';
+import { Vector3TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector3TransformBlock';
+import { Vector4TransformBlock } from 'babylonjs/Materials/Node/Blocks/vector4TransformBlock';
+import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
+
+require("./nodeList.scss");
+
+interface INodeListComponentProps {
+    globalState: GlobalState;
+    onAddValueNode: (b: string) => void;
+    onAddNodeFromClass: (ObjectClass: typeof NodeMaterialBlock) => void;
+}
+
+export class NodeListComponent extends React.Component<INodeListComponentProps> {
+    render() {
+        // Block types used to create the menu from
+        const allBlocks = {
+            Fragment: [AlphaTestBlock, FragmentOutputBlock, ImageProcessingBlock, RGBAMergerBlock, RGBASplitterBlock, TextureBlock],
+            Vertex: [BonesBlock, InstancesBlock, MorphTargetsBlock, VertexOutputBlock],
+            Dual: [FogBlock],
+            Other: [AddBlock, ClampBlock, MatrixMultiplicationBlock, MultiplyBlock, Vector2TransformBlock, Vector3TransformBlock, Vector4TransformBlock],
+            Value: ["Texture", "Vector2", "Vector3", "Matrix"],
+        }
+
+        // Create node menu
+        var blockMenu = []
+        for (var key in allBlocks) {
+            var blockList = (allBlocks as any)[key].map((b: any) => {
+                var label = typeof b === "string" ? b : b.prototype.getClassName()
+                var onClick = typeof b === "string" ? () => { this.props.onAddValueNode(b) } : () => { this.props.onAddNodeFromClass(b) };
+                return <ButtonLineComponent label={label} onClick={onClick} />
+            })
+            blockMenu.push(
+                <LineContainerComponent title={key + " blocks"} closed={false}>
+                    {blockList}
+                </LineContainerComponent>
+            )
+        }
+
+        return (
+            <div id="nodeList" style={{ borderRightStyle: "solid", borderColor: "grey", borderWidth: "1px" }} >
+                <div className="panes">
+                    <div className="pane">
+                        {blockMenu}
+                    </div>
+                </div>
+            </div>
+        );
+
+    }
+}

+ 56 - 0
nodeEditor/src/components/propertyTab/properties/texturePropertyTabComponent.tsx

@@ -0,0 +1,56 @@
+
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+import { Texture } from 'babylonjs/Materials/Textures/texture';
+import { FileButtonLineComponent } from '../../../sharedComponents/fileButtonLineComponent';
+import { GenericNodeModel } from '../../diagram/generic/genericNodeModel';
+import { Tools } from 'babylonjs/Misc/tools';
+import { Engine } from 'babylonjs/Engines/engine';
+
+interface ITexturePropertyTabComponentProps {
+    globalState: GlobalState;
+    node: GenericNodeModel;
+}
+
+export class TexturePropertyTabComponent extends React.Component<ITexturePropertyTabComponentProps> {
+
+	/**
+	 * Replaces the texture of the node
+	 * @param file the file of the texture to use
+	 */
+    replaceTexture(file: File) {
+        if (!this.props.node) {
+            return;
+        }
+
+        let texture = this.props.node.texture as Texture;
+        if (!texture) {
+            this.props.node.texture = new Texture(null, Engine.LastCreatedScene)
+            texture = this.props.node.texture;
+        }
+
+        Tools.ReadFile(file, (data) => {
+            var blob = new Blob([data], { type: "octet/stream" });
+            var url = URL.createObjectURL(blob);
+
+            if (texture.isCube) {
+                let extension: string | undefined = undefined;
+                if (file.name.toLowerCase().indexOf(".dds") > 0) {
+                    extension = ".dds";
+                } else if (file.name.toLowerCase().indexOf(".env") > 0) {
+                    extension = ".env";
+                }
+
+                (texture as Texture).updateURL(url, extension, () => this.forceUpdate());
+            } else {
+                (texture as Texture).updateURL(url, null, () => this.forceUpdate());
+            }
+        }, undefined, true);
+    }
+
+    render() {
+        return (
+            <FileButtonLineComponent label="Replace texture" onClick={(file) => this.replaceTexture(file)} accept=".jpg, .png, .tga, .dds, .env" />
+        );
+    }
+}

+ 19 - 0
nodeEditor/src/components/propertyTab/properties/vector2PropertyTabComponent.tsx

@@ -0,0 +1,19 @@
+
+import * as React from "react";
+import { GlobalState } from '../../../globalState';
+import { GenericNodeModel } from '../../diagram/generic/genericNodeModel';
+import { Vector2LineComponent } from '../../../sharedComponents/vector2LineComponent';
+
+interface IVector2PropertyTabComponentProps {
+    globalState: GlobalState;
+    node: GenericNodeModel;
+}
+
+export class Vector2PropertyTabComponent extends React.Component<IVector2PropertyTabComponentProps> {
+
+    render() {
+        return (
+            <Vector2LineComponent label="Value" target={this.props.node} propertyName="vector2"></Vector2LineComponent>
+        );
+    }
+}

+ 120 - 0
nodeEditor/src/components/propertyTab/propertyTab.scss

@@ -0,0 +1,120 @@
+#propertyTab {
+    padding: 5px;
+    $line-padding-left: 2px;
+    color:white;
+
+    .vector3Line {
+        padding-left:$line-padding-left;                    
+        display: grid;
+
+        .firstLine {
+            display: grid;
+            grid-template-columns: 1fr auto 20px;
+            height: 30px;
+
+            .label {
+                grid-column: 1;
+                display: flex;
+                align-items: center;
+            }
+
+            .vector {
+                grid-column: 2;
+                display: flex;
+                align-items: center;
+                text-align: right;
+                opacity: 0.8;
+            }
+
+            .expand {
+                grid-column: 3;
+                display: grid;
+                align-items: center;
+                justify-items: center;
+                cursor: pointer;
+            }
+        }
+
+        .secondLine {
+            display: grid;
+            padding-right: 5px;  
+            border-left: 1px solid rgb(51, 122, 183);
+
+            .numeric {
+                display: grid;
+                grid-template-columns: 1fr auto;
+            }
+
+            .numeric-label {
+                text-align: right;
+                grid-column: 1;
+                display: flex;
+                align-items: center;                            
+                justify-self: right;
+                margin-right: 10px;                          
+            }
+
+            .numeric-value {
+                width: 120px;
+                grid-column: 2;
+                display: flex;
+                align-items: center;  
+                border: 1px solid  rgb(51, 122, 183);
+            }                        
+        }
+    }
+
+    .buttonLine {
+        height: 30px;
+        display: grid;
+        align-items: center;
+        justify-items: stretch;
+
+        input[type="file"] {
+            display: none;
+        }
+
+        .file-upload {            
+            background: #222222;
+            border: 1px solid rgb(51, 122, 183);
+            margin: 5px 10px;
+            color:white;
+            padding: 4px 5px;
+            opacity: 0.9;
+            cursor: pointer;
+            text-align: center;
+        }
+
+        .file-upload:hover {
+            opacity: 1.0;
+        }
+
+        .file-upload:active {
+            transform: scale(0.98);
+            transform-origin: 0.5 0.5;
+        }
+
+        button {
+            background: #222222;
+            border: 1px solid rgb(51, 122, 183);
+            margin: 5px 10px 5px 10px;
+            color:white;
+            padding: 4px 5px;
+            opacity: 0.9;
+        }
+
+        button:hover {
+            opacity: 1.0;
+        }
+
+        button:active {
+            background: #282828;
+        }   
+        
+        button:focus {
+            border: 1px solid rgb(51, 122, 183);
+            outline: 0px;
+        }  
+    }
+
+}

+ 50 - 0
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -0,0 +1,50 @@
+
+import * as React from "react";
+import { GlobalState } from '../../globalState';
+import { Nullable } from 'babylonjs/types';
+import { TexturePropertyTabComponent } from './properties/texturePropertyTabComponent';
+import { GenericNodeModel } from '../diagram/generic/genericNodeModel';
+import { Vector2PropertyTabComponent } from './properties/vector2PropertyTabComponent';
+require("./propertyTab.scss");
+
+interface IPropertyTabComponentProps {
+    globalState: GlobalState;
+}
+
+export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<GenericNodeModel> }> {
+
+    constructor(props: IPropertyTabComponentProps) {
+        super(props)
+
+        this.state = { currentNode: null };
+    }
+
+    componentWillMount() {
+        this.props.globalState.onSelectionChangedObservable.add(block => {
+            this.setState({ currentNode: block });
+        });
+    }
+
+    render() {
+        if (this.state.currentNode) {
+            if (this.state.currentNode.texture) {
+                return (
+                    <div id="propertyTab">
+                        <TexturePropertyTabComponent globalState={this.props.globalState} node={this.state.currentNode} />
+                    </div>
+                );
+            }
+            if (this.state.currentNode.vector2) {
+                return (
+                    <div id="propertyTab">
+                        <Vector2PropertyTabComponent globalState={this.props.globalState} node={this.state.currentNode} />
+                    </div>
+                );
+            }
+        }
+
+        return (
+            <div id="propertyTab" />
+        );
+    }
+}

+ 8 - 4
nodeEditor/src/globalState.ts

@@ -1,6 +1,10 @@
-import {NodeMaterial} from "babylonjs/Materials/Node/nodeMaterial"
-import {Nullable} from "babylonjs/types"
+import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial"
+import { Nullable } from "babylonjs/types"
+import { Observable } from 'babylonjs/Misc/observable';
+import { GenericNodeModel } from './components/diagram/generic/genericNodeModel';
+
 export class GlobalState {
-    nodeMaterial?:NodeMaterial;
-    hostDocument?:Nullable<Document>;
+    nodeMaterial?: NodeMaterial;
+    hostDocument?: Nullable<Document>;
+    onSelectionChangedObservable = new Observable<Nullable<GenericNodeModel>>();
 }

+ 8 - 8
nodeEditor/src/nodeEditor.ts

@@ -2,8 +2,8 @@ import * as React from "react";
 import * as ReactDOM from "react-dom";
 import { GlobalState } from './globalState';
 import { GraphEditor } from './components/graphEditor';
-import {NodeMaterial} from "babylonjs/Materials/Node/nodeMaterial"
-import {Popup} from "../src/sharedComponents/popup"
+import { NodeMaterial } from "babylonjs/Materials/Node/nodeMaterial"
+import { Popup } from "../src/sharedComponents/popup"
 /**
  * Interface used to specify creation options for the node editor
  */
@@ -24,8 +24,8 @@ export class NodeEditor {
      * @param options defines the options to use to configure the node editor
      */
     public static Show(options: INodeEditorOptions) {
-        if(!options.hostElement){
-            options.hostElement = Popup.CreatePopup("SCENE EXPLORER", "node-editor", 1000, 800)!;
+        if (!options.hostElement) {
+            options.hostElement = Popup.CreatePopup("BABYLON.JS NODE EDITOR", "node-editor", 1000, 800)!;
         }
         let globalState = new GlobalState();
         globalState.nodeMaterial = options.nodeMaterial
@@ -39,15 +39,15 @@ export class NodeEditor {
 
         // Close the popup window when the page is refreshed or scene is disposed
         var popupWindow = (Popup as any)["node-editor"];
-        if(globalState.nodeMaterial && popupWindow){
-            globalState.nodeMaterial.getScene().onDisposeObservable.addOnce(()=>{
-                if(popupWindow){
+        if (globalState.nodeMaterial && popupWindow) {
+            globalState.nodeMaterial.getScene().onDisposeObservable.addOnce(() => {
+                if (popupWindow) {
                     popupWindow.close();
                 }
             })
             window.onbeforeunload = function(event) {
                 var popupWindow = (Popup as any)["node-editor"];
-                if(popupWindow){
+                if (popupWindow) {
                     popupWindow.close();
                 }
             };

+ 2 - 25
nodeEditor/src/sharedComponents/lineContainerComponent.tsx

@@ -4,13 +4,12 @@ import { faChevronDown } from '@fortawesome/free-solid-svg-icons';
 
 
 interface ILineContainerComponentProps {
-    globalState?: any; //
     title: string;
     children: any[] | any;
     closed?: boolean;
 }
 
-export class LineContainerComponent extends React.Component<ILineContainerComponentProps, { isExpanded: boolean, isHighlighted: boolean }> {
+export class LineContainerComponent extends React.Component<ILineContainerComponentProps, { isExpanded: boolean }> {
     private static _InMemoryStorage: { [key: string]: boolean };
 
     constructor(props: ILineContainerComponentProps) {
@@ -33,7 +32,7 @@ export class LineContainerComponent extends React.Component<ILineContainerCompon
             initialState = !this.props.closed;
         }
 
-        this.state = { isExpanded: initialState, isHighlighted: false };
+        this.state = { isExpanded: initialState };
     }
 
     switchExpandedState(): void {
@@ -54,26 +53,6 @@ export class LineContainerComponent extends React.Component<ILineContainerCompon
         this.setState({ isExpanded: newState });
     }
 
-    componentDidMount() {
-        if (this.props.globalState && !this.props.globalState.selectedLineContainerTitle) {
-            return;
-        }
-
-        if (this.props.globalState && this.props.globalState.selectedLineContainerTitle === this.props.title) {
-            setTimeout(() => {
-                this.props.globalState!.selectedLineContainerTitle = "";
-            });
-
-            this.setState({ isExpanded: true, isHighlighted: true });
-
-            window.setTimeout(() => {
-                this.setState({ isHighlighted: false });
-            }, 5000);
-        } else {
-            this.setState({isExpanded: false});
-        }        
-    }
-
     renderHeader() {
         const className = this.state.isExpanded ? "collapse" : "collapse closed";
 
@@ -112,8 +91,6 @@ export class LineContainerComponent extends React.Component<ILineContainerCompon
                         {this.props.children}
                     </div >
                 </div>
-                <div className={"paneContainer-highlight-border" + (!this.state.isHighlighted ? " transparent" : "")}>
-                </div>
             </div>
         );
     }

+ 25 - 15
nodeEditor/src/sharedComponents/popup.ts

@@ -6,65 +6,75 @@ export class Popup {
             top: (window.innerHeight - width) / 2 + window.screenY,
             left: (window.innerWidth - height) / 2 + window.screenX
         };
-    
+
         var windowCreationOptions = Object.keys(windowCreationOptionsList)
             .map(
                 (key) => key + '=' + (windowCreationOptionsList as any)[key]
             )
             .join(',');
-    
+
         const popupWindow = window.open("", title, windowCreationOptions);
         if (!popupWindow) {
             return null;
         }
-    
+
         const parentDocument = popupWindow.document;
-    
+
+        // Font
+        const newLinkEl = parentDocument.createElement('link');
+
+        newLinkEl.rel = 'stylesheet';
+        newLinkEl.href = "https://use.typekit.net/cta4xsb.css";
+        parentDocument.head!.appendChild(newLinkEl);
+
+
         parentDocument.title = title;
         parentDocument.body.style.width = "100%";
         parentDocument.body.style.height = "100%";
         parentDocument.body.style.margin = "0";
         parentDocument.body.style.padding = "0";
-    
+
         let parentControl = parentDocument.createElement("div");
         parentControl.style.width = "100%";
         parentControl.style.height = "100%";
         parentControl.style.margin = "0";
         parentControl.style.padding = "0";
-    
+
         popupWindow.document.body.appendChild(parentControl);
-    
         this._CopyStyles(window.document, parentDocument);
-    
+        setTimeout(() => { // need this for late bindings
+            this._CopyStyles(window.document, parentDocument);
+        }, 0);
+
         (this as any)[windowVariableName] = popupWindow;
-    
+
         return parentControl;
     }
 
     private static _CopyStyles(sourceDoc: HTMLDocument, targetDoc: HTMLDocument) {
         for (var index = 0; index < sourceDoc.styleSheets.length; index++) {
             var styleSheet: any = sourceDoc.styleSheets[index];
-            try{
+            try {
                 if (styleSheet.cssRules) { // for <style> elements
                     const newStyleEl = sourceDoc.createElement('style');
-    
+
                     for (var cssRule of styleSheet.cssRules) {
                         // write the text of each rule into the body of the style element
                         newStyleEl.appendChild(sourceDoc.createTextNode(cssRule.cssText));
                     }
-    
+
                     targetDoc.head!.appendChild(newStyleEl);
                 } else if (styleSheet.href) { // for <link> elements loading CSS from a URL
                     const newLinkEl = sourceDoc.createElement('link');
-    
+
                     newLinkEl.rel = 'stylesheet';
                     newLinkEl.href = styleSheet.href;
                     targetDoc.head!.appendChild(newLinkEl);
                 }
-            }catch(e){
+            } catch (e) {
                 console.log(e)
             }
-            
+
         }
     }
 }

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

@@ -19,6 +19,19 @@ import { NodeMaterialOptimizer } from './Optimizers/nodeMaterialOptimizer';
 import { ImageProcessingConfiguration, IImageProcessingConfigurationDefines } from '../imageProcessingConfiguration';
 import { Nullable } from '../../types';
 import { VertexBuffer } from '../../Meshes/buffer';
+import { Tools } from '../../Misc/tools';
+
+// declare NODEEDITOR namespace for compilation issue
+declare var NODEEDITOR: any;
+declare var BABYLON: any;
+
+/**
+ * Interface used to configure the node material editor
+ */
+export interface INodeMaterialEditorOptions {
+    /** Define the URl to load node editor script */
+    editorURL?: string;
+}
 
 /** @hidden */
 export class NodeMaterialDefines extends MaterialDefines implements IImageProcessingConfigurationDefines {
@@ -88,6 +101,26 @@ export class NodeMaterial extends PushMaterial {
     private _textureConnectionPoints = new Array<NodeMaterialConnectionPoint>();
     private _optimizers = new Array<NodeMaterialOptimizer>();
 
+    /** Define the URl to load node editor script */
+    public static EditorURL = `https://unpkg.com/babylonjs-node-editor@${Engine.Version}/babylon.nodeEditor.js`;
+
+    private BJSNODEMATERIALEDITOR = this._getGlobalNodeMaterialEditor();
+
+    /** Get the inspector from bundle or global */
+    private _getGlobalNodeMaterialEditor(): any {
+        // UMD Global name detection from Webpack Bundle UMD Name.
+        if (typeof NODEEDITOR !== 'undefined') {
+            return NODEEDITOR;
+        }
+
+        // In case of module let's check the global emitted from the editor entry point.
+        if (typeof BABYLON !== 'undefined' && typeof BABYLON.NodeEditor !== 'undefined') {
+            return BABYLON;
+        }
+
+        return undefined;
+    }
+
     /**
     * Defines the maximum number of lights that can be used in the material
     */
@@ -718,4 +751,36 @@ export class NodeMaterial extends PushMaterial {
 
         super.dispose(forceDisposeEffect, forceDisposeTextures, notBoundToMesh);
     }
+
+    /** Creates the node editor window. */
+    private _createNodeEditor() {
+        this.BJSNODEMATERIALEDITOR = this.BJSNODEMATERIALEDITOR || this._getGlobalNodeMaterialEditor();
+
+        this.BJSNODEMATERIALEDITOR.NodeEditor.Show({
+            nodeMaterial: this
+        });
+    }
+
+    /**
+     * Launch the node material editor
+     * @param config Define the configuration of the editor
+     * @return a promise fulfilled when the node editor is visible
+     */
+    public edit(config?: INodeMaterialEditorOptions): Promise<void> {
+        return new Promise((resolve, reject) => {
+            if (typeof this.BJSNODEMATERIALEDITOR == 'undefined') {
+                const editorUrl = config && config.editorURL ? config.editorURL : NodeMaterial.EditorURL;
+
+                // Load editor and add it to the DOM
+                Tools.LoadScript(editorUrl, () => {
+                    this._createNodeEditor();
+                    resolve();
+                });
+            } else {
+                // Otherwise creates the editor
+                this._createNodeEditor();
+                resolve();
+            }
+        });
+    }
 }