Bläddra i källkod

merge with master

Benjamin Guignabert 5 år sedan
förälder
incheckning
469ab10373
100 ändrade filer med 14891 tillägg och 2258 borttagningar
  1. 3 4
      Playground/js/main.js
  2. 25 0
      Playground/js/monacoCreator.js
  3. 44 0
      Playground/templates.json
  4. 2 1
      Tools/Config/config.json
  5. 11 0
      Tools/Publisher/tasks/processEs6Packages.js
  6. 11 11
      dist/preview release/ammo.js
  7. 1 1
      dist/preview release/ammo.wasm.js
  8. BIN
      dist/preview release/ammo.wasm.wasm
  9. 1298 105
      dist/preview release/babylon.d.ts
  10. 2 2
      dist/preview release/babylon.js
  11. 4540 589
      dist/preview release/babylon.max.js
  12. 1 1
      dist/preview release/babylon.max.js.map
  13. 2687 195
      dist/preview release/babylon.module.d.ts
  14. 1302 105
      dist/preview release/documentation.d.ts
  15. 1 1
      dist/preview release/glTF2Interface/package.json
  16. 4 0
      dist/preview release/gui/babylon.gui.d.ts
  17. 7 0
      dist/preview release/gui/babylon.gui.js
  18. 1 1
      dist/preview release/gui/babylon.gui.js.map
  19. 2 2
      dist/preview release/gui/babylon.gui.min.js
  20. 8 0
      dist/preview release/gui/babylon.gui.module.d.ts
  21. 2 2
      dist/preview release/gui/package.json
  22. 7 7
      dist/preview release/inspector/babylon.inspector.bundle.js
  23. 157 3
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  24. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  25. 42 0
      dist/preview release/inspector/babylon.inspector.d.ts
  26. 86 0
      dist/preview release/inspector/babylon.inspector.module.d.ts
  27. 7 7
      dist/preview release/inspector/package.json
  28. 3 3
      dist/preview release/loaders/package.json
  29. 9 2
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  30. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.js.map
  31. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  32. 9 2
      dist/preview release/materialsLibrary/babylonjs.materials.js
  33. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.js.map
  34. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  35. 2 2
      dist/preview release/materialsLibrary/package.json
  36. 60 39
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  37. 7 7
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  38. 513 320
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  39. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  40. 137 88
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  41. 2 2
      dist/preview release/nodeEditor/package.json
  42. 1 1
      dist/preview release/package.json
  43. 1 1
      dist/preview release/packagesSizeBaseLine.json
  44. 2 2
      dist/preview release/postProcessesLibrary/package.json
  45. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  46. 3 3
      dist/preview release/serializers/package.json
  47. 2687 195
      dist/preview release/viewer/babylon.module.d.ts
  48. 190 126
      dist/preview release/viewer/babylon.viewer.js
  49. 1 1
      dist/preview release/viewer/babylon.viewer.max.js
  50. 51 22
      dist/preview release/what's new.md
  51. 1 0
      dist/what's new.md
  52. 1 0
      gui/src/2D/advancedDynamicTexture.ts
  53. 9 0
      gui/src/2D/controls/control.ts
  54. 2 0
      inspector/src/components/actionTabs/actionTabs.scss
  55. 1 0
      inspector/src/components/actionTabs/tabs/debugTabComponent.tsx
  56. 28 0
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx
  57. 55 26
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationPropertyGridComponent.tsx
  58. 84 0
      inspector/src/components/actionTabs/tabs/propertyGrids/animations/popupComponent.tsx
  59. 1 1
      inspector/src/components/globalState.ts
  60. 10 0
      inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx
  61. 5 0
      inspector/src/inspector.ts
  62. 4 1
      materialsLibrary/src/custom/customMaterial.ts
  63. 8 1
      materialsLibrary/src/custom/pbrCustomMaterial.ts
  64. 104 77
      nodeEditor/src/blockTools.ts
  65. 23 13
      nodeEditor/src/components/nodeList/nodeListComponent.tsx
  66. 16 0
      nodeEditor/src/components/propertyTab/propertyTab.scss
  67. 24 7
      nodeEditor/src/components/propertyTab/propertyTabComponent.tsx
  68. 2 1
      nodeEditor/src/diagram/display/textureDisplayManager.ts
  69. 2 0
      nodeEditor/src/diagram/displayLedger.ts
  70. 5 12
      nodeEditor/src/diagram/frameNodePort.ts
  71. 15 2
      nodeEditor/src/diagram/graphCanvas.tsx
  72. 140 78
      nodeEditor/src/diagram/graphFrame.ts
  73. 26 3
      nodeEditor/src/diagram/graphNode.ts
  74. 2 0
      nodeEditor/src/diagram/nodeLink.ts
  75. 81 2
      nodeEditor/src/diagram/nodePort.ts
  76. 0 24
      nodeEditor/src/diagram/properties/PerturbNormalNodePropertyComponent.tsx
  77. 0 33
      nodeEditor/src/diagram/properties/clampNodePropertyComponent.tsx
  78. 1 1
      nodeEditor/src/diagram/properties/frameNodePortPropertyComponent.tsx
  79. 113 5
      nodeEditor/src/diagram/properties/genericNodePropertyComponent.tsx
  80. 2 2
      nodeEditor/src/diagram/properties/gradientNodePropertyComponent.tsx
  81. 2 2
      nodeEditor/src/diagram/properties/inputNodePropertyComponent.tsx
  82. 2 2
      nodeEditor/src/diagram/properties/lightInformationPropertyTabComponent.tsx
  83. 2 2
      nodeEditor/src/diagram/properties/lightPropertyTabComponent.tsx
  84. 54 0
      nodeEditor/src/diagram/properties/nodePortPropertyComponent.tsx
  85. 0 33
      nodeEditor/src/diagram/properties/remapNodePropertyComponent.tsx
  86. 19 8
      nodeEditor/src/diagram/properties/texturePropertyTabComponent.tsx
  87. 2 2
      nodeEditor/src/diagram/properties/transformNodePropertyComponent.tsx
  88. 2 2
      nodeEditor/src/diagram/properties/trigonometryNodePropertyComponent.tsx
  89. 0 23
      nodeEditor/src/diagram/properties/worleyNoise3DNodePropertyComponent.tsx
  90. 2 8
      nodeEditor/src/diagram/propertyLedger.ts
  91. 1 0
      nodeEditor/src/globalState.ts
  92. 15 5
      nodeEditor/src/sharedComponents/checkBoxLineComponent.tsx
  93. 1 1
      package.json
  94. 13 13
      src/Audio/sound.ts
  95. 9 0
      src/Debug/debugLayer.ts
  96. 7 7
      src/Engines/Extensions/engine.rawTexture.ts
  97. 52 0
      src/Engines/Extensions/engine.readTexture.ts
  98. 5 0
      src/Engines/Extensions/engine.views.ts
  99. 1 0
      src/Engines/Extensions/index.ts
  100. 0 0
      src/Engines/engine.ts

+ 3 - 4
Playground/js/main.js

@@ -566,7 +566,7 @@ class Main {
                         exampleList.appendChild(noResultContainer);
                         exampleList.appendChild(noResultContainer);
                     }
                     }
 
 
-                    if (!location.hash && restoreVersionResult == false) {
+                    if (!location.hash && restoreVersionResult == false && location.pathname.indexOf('pg/') === -1) {
                         // Query string
                         // Query string
                         var queryString = window.location.search;
                         var queryString = window.location.search;
 
 
@@ -1016,12 +1016,11 @@ class Main {
     };
     };
     checkHash() {
     checkHash() {
         let pgHash = "";
         let pgHash = "";
-        if (location.search) {
+        if (location.search && (!location.pathname  || location.pathname === '/') && !location.hash) {
             var query = this.parseQuery(location.search);
             var query = this.parseQuery(location.search);
             if (query.pg) {
             if (query.pg) {
                 pgHash = "#" + query.pg + "#" + (query.revision || "0")
                 pgHash = "#" + query.pg + "#" + (query.revision || "0")
             }
             }
-
         } else if (location.hash) {
         } else if (location.hash) {
             if (this.previousHash !== location.hash) {
             if (this.previousHash !== location.hash) {
                 this.cleanHash();
                 this.cleanHash();
@@ -1156,4 +1155,4 @@ class Main {
         }
         }
         return query;
         return query;
     }
     }
-}
+}

+ 25 - 0
Playground/js/monacoCreator.js

@@ -21,6 +21,7 @@ class MonacoCreator {
         this.blockEditorChange = false;
         this.blockEditorChange = false;
         this.definitionWorker = null;
         this.definitionWorker = null;
         this.deprecatedCandidates = [];
         this.deprecatedCandidates = [];
+        this.templates = [];
 
 
         this.compilerTriggerTimeoutID = null;
         this.compilerTriggerTimeoutID = null;
 
 
@@ -113,6 +114,12 @@ class MonacoCreator {
 
 
         this.setupDefinitionWorker(libContent);
         this.setupDefinitionWorker(libContent);
 
 
+        // Load code templates
+        response = await fetch("/templates.json");
+        if (response.ok) {
+            this.templates = await response.json();
+        }
+
         // WARNING !!! We need the 'dev' version of Monaco, as we use monkey-patching to hook into the suggestion adapter
         // WARNING !!! We need the 'dev' version of Monaco, as we use monkey-patching to hook into the suggestion adapter
         require.config({
         require.config({
             paths: {
             paths: {
@@ -127,6 +134,13 @@ class MonacoCreator {
             // This is used for a vscode-like color preview for ColorX types
             // This is used for a vscode-like color preview for ColorX types
             this.setupMonacoColorProvider();
             this.setupMonacoColorProvider();
 
 
+            // enhance templates with extra properties
+            for (const template of this.templates) {
+                template.kind = monaco.languages.CompletionItemKind.Snippet,
+                template.sortText = "!" + template.label; // make sure templates are on top of the completion window
+                template.insertTextRules = monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet;
+            }
+
             // As explained above, we need the 'dev' version of Monaco to access this adapter!
             // As explained above, we need the 'dev' version of Monaco to access this adapter!
             require(['vs/language/typescript/languageFeatures'], module => {
             require(['vs/language/typescript/languageFeatures'], module => {
                 this.hookMonacoCompletionProvider(module.SuggestAdapter);
                 this.hookMonacoCompletionProvider(module.SuggestAdapter);
@@ -289,6 +303,17 @@ class MonacoCreator {
                 }
                 }
             }
             }
 
 
+            // add our own templates when invoked without context
+            if (context.triggerKind == monaco.languages.CompletionTriggerKind.Invoke) {
+                for (const template of owner.templates) {
+                    if (template.language && owner.monacoMode != template.language)
+                        continue;
+
+                    template.range = undefined;
+                    suggestions.push(template);
+                }
+            }
+
             // preserve incomplete flag or force it when the definition is not yet analyzed
             // preserve incomplete flag or force it when the definition is not yet analyzed
             const incomplete = (result.incomplete && result.incomplete == true) || owner.deprecatedCandidates.length == 0;
             const incomplete = (result.incomplete && result.incomplete == true) || owner.deprecatedCandidates.length == 0;
 
 

+ 44 - 0
Playground/templates.json

@@ -0,0 +1,44 @@
+[
+  {
+    "label" : "Create a sphere",
+    "documentation" : "https://doc.babylonjs.com/how_to/set_shapes",
+    "insertText" : "var sphere = BABYLON.MeshBuilder.CreateSphere(\"${1:sphere}\", {diameter: ${2:1}}, scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a box",
+    "documentation" : "https://doc.babylonjs.com/how_to/set_shapes",
+    "insertText" : "var box = BABYLON.MeshBuilder.CreateBox(\"${1:box}\", {size: ${2:1}}, scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a cylinder",
+    "documentation" : "https://doc.babylonjs.com/how_to/set_shapes",
+    "insertText" : "var cylinder = BABYLON.MeshBuilder.CreateCylinder(\"${1:cylinder}\", {height: ${2:2}, diameter: ${3:1}}, scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create a ground plane",
+    "documentation" : "https://doc.babylonjs.com/how_to/set_shapes",
+    "insertText" : "var ground = BABYLON.MeshBuilder.CreateGround(\"${1:ground}\", {width: ${2:6}, height: ${3:6}}, scene);",
+    "language" : "javascript"
+  },
+  {
+    "label" : "Create an Arc Rotate Camera w/Degrees",
+    "documentation" : "https://doc.babylonjs.com/babylon101/cameras#arc-rotate-camera",
+    "insertText" : "var camera = new BABYLON.ArcRotateCamera(\"${1:camera}\", BABYLON.Tools.ToRadians(${2:90}), BABYLON.Tools.ToRadians(${3:65}), ${4:10}, ${5:BABYLON.Vector3.Zero()}, scene);",
+    "language" : "javascript"
+  },
+  {
+  "label" : "Create an Arc Rotate Camera w/Radians",
+  "documentation" : "https://doc.babylonjs.com/babylon101/cameras#arc-rotate-camera",
+  "insertText" : "var camera = new BABYLON.ArcRotateCamera(\"${1:camera}\", ${2:0}, ${3:Math.PI/2}, ${4:10}, ${5:BABYLON.Vector3.Zero()}, scene);",
+  "language" : "javascript"
+  },
+  {
+  "label" : "Import a Mesh w/callback",
+  "documentation" : "https://doc.babylonjs.com/resources/external_pg_assets",
+  "insertText" : "BABYLON.SceneLoader.ImportMesh(\"${1:meshName}\", \"${2:url to the mesh parent directory}\", \"${3:Mesh filename.fileextension}\", scene, function(newMeshes){\n\n});",
+  "language" : "javascript"
+  }
+]

+ 2 - 1
Tools/Config/config.json

@@ -142,7 +142,8 @@
             },
             },
             "es6": {
             "es6": {
                 "packageName": "@babylonjs/core",
                 "packageName": "@babylonjs/core",
-                "readme": "readme-es6.md"
+                "readme": "readme-es6.md",
+                "license": "license.md"
             }
             }
         }
         }
     },
     },

+ 11 - 0
Tools/Publisher/tasks/processEs6Packages.js

@@ -51,6 +51,13 @@ function processEs6Packages(version) {
             fs.copySync(source, destination);
             fs.copySync(source, destination);
         }
         }
 
 
+        if (es6Config.license) {
+            let source = path.join(config.computed.rootFolder, es6Config.readme);
+            let destination = path.join(packagePath, "license.md");
+            colorConsole.log("    Copy es6 license file: ", source.cyan, destination.cyan);
+            fs.copySync(source, destination);
+        }
+
         umdPackageJson.name = es6Config.packageName;
         umdPackageJson.name = es6Config.packageName;
         umdPackageJson.version = version;
         umdPackageJson.version = version;
         umdPackageJson.main = es6Config.index || "index.js";
         umdPackageJson.main = es6Config.index || "index.js";
@@ -68,6 +75,10 @@ function processEs6Packages(version) {
             umdPackageJson.files = files;
             umdPackageJson.files = files;
         }
         }
 
 
+        if (es6Config.license && umdPackageJson.files.indexOf("license.md") === -1) {
+            umdPackageJson.files.push("license.md");
+        }
+
         ["dependencies", "peerDependencies", "devDependencies"].forEach(key => {
         ["dependencies", "peerDependencies", "devDependencies"].forEach(key => {
             if (umdPackageJson[key]) {
             if (umdPackageJson[key]) {
                 let dependencies = umdPackageJson[key];
                 let dependencies = umdPackageJson[key];

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 11 - 11
dist/preview release/ammo.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/ammo.wasm.js


BIN
dist/preview release/ammo.wasm.wasm


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1298 - 105
dist/preview release/babylon.d.ts


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 2
dist/preview release/babylon.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 4540 - 589
dist/preview release/babylon.max.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/babylon.max.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2687 - 195
dist/preview release/babylon.module.d.ts


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1302 - 105
dist/preview release/documentation.d.ts


+ 1 - 1
dist/preview release/glTF2Interface/package.json

@@ -1,7 +1,7 @@
 {
 {
     "name": "babylonjs-gltf2interface",
     "name": "babylonjs-gltf2interface",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
     "description": "A typescript declaration of babylon's gltf2 inteface.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 4 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -822,6 +822,10 @@ declare module BABYLON.GUI {
          */
          */
         onAfterDrawObservable: BABYLON.Observable<Control>;
         onAfterDrawObservable: BABYLON.Observable<Control>;
         /**
         /**
+        * An event triggered when the control has been disposed
+        */
+        onDisposeObservable: BABYLON.Observable<Control>;
+        /**
          * Get the hosting AdvancedDynamicTexture
          * Get the hosting AdvancedDynamicTexture
          */
          */
         get host(): AdvancedDynamicTexture;
         get host(): AdvancedDynamicTexture;

+ 7 - 0
dist/preview release/gui/babylon.gui.js

@@ -3870,6 +3870,10 @@ var Control = /** @class */ (function () {
          * An event triggered after the control was drawn
          * An event triggered after the control was drawn
          */
          */
         this.onAfterDrawObservable = new babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["Observable"]();
         this.onAfterDrawObservable = new babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["Observable"]();
+        /**
+        * An event triggered when the control has been disposed
+        */
+        this.onDisposeObservable = new babylonjs_Misc_observable__WEBPACK_IMPORTED_MODULE_0__["Observable"]();
         this._tmpMeasureA = new _measure__WEBPACK_IMPORTED_MODULE_2__["Measure"](0, 0, 0, 0);
         this._tmpMeasureA = new _measure__WEBPACK_IMPORTED_MODULE_2__["Measure"](0, 0, 0, 0);
     }
     }
     Object.defineProperty(Control.prototype, "shadowOffsetX", {
     Object.defineProperty(Control.prototype, "shadowOffsetX", {
@@ -5485,6 +5489,9 @@ var Control = /** @class */ (function () {
                 this.linkWithMesh(null);
                 this.linkWithMesh(null);
             }
             }
         }
         }
+        // Callback
+        this.onDisposeObservable.notifyObservers(this);
+        this.onDisposeObservable.clear();
     };
     };
     Object.defineProperty(Control, "HORIZONTAL_ALIGNMENT_LEFT", {
     Object.defineProperty(Control, "HORIZONTAL_ALIGNMENT_LEFT", {
         /** HORIZONTAL_ALIGNMENT_LEFT */
         /** HORIZONTAL_ALIGNMENT_LEFT */

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2 - 2
dist/preview release/gui/babylon.gui.min.js


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

@@ -853,6 +853,10 @@ declare module "babylonjs-gui/2D/controls/control" {
          */
          */
         onAfterDrawObservable: Observable<Control>;
         onAfterDrawObservable: Observable<Control>;
         /**
         /**
+        * An event triggered when the control has been disposed
+        */
+        onDisposeObservable: Observable<Control>;
+        /**
          * Get the hosting AdvancedDynamicTexture
          * Get the hosting AdvancedDynamicTexture
          */
          */
         get host(): AdvancedDynamicTexture;
         get host(): AdvancedDynamicTexture;
@@ -5193,6 +5197,10 @@ declare module BABYLON.GUI {
          */
          */
         onAfterDrawObservable: BABYLON.Observable<Control>;
         onAfterDrawObservable: BABYLON.Observable<Control>;
         /**
         /**
+        * An event triggered when the control has been disposed
+        */
+        onDisposeObservable: BABYLON.Observable<Control>;
+        /**
          * Get the hosting AdvancedDynamicTexture
          * Get the hosting AdvancedDynamicTexture
          */
          */
         get host(): AdvancedDynamicTexture;
         get host(): AdvancedDynamicTexture;

+ 2 - 2
dist/preview release/gui/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-gui",
     "name": "babylonjs-gui",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
     "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.11"
+        "babylonjs": "4.2.0-alpha.12"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 7
dist/preview release/inspector/babylon.inspector.bundle.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 157 - 3
dist/preview release/inspector/babylon.inspector.bundle.max.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


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

@@ -35,6 +35,7 @@ declare module INSPECTOR {
         onTabChangedObservable: BABYLON.Observable<number>;
         onTabChangedObservable: BABYLON.Observable<number>;
         onSelectionRenamedObservable: BABYLON.Observable<void>;
         onSelectionRenamedObservable: BABYLON.Observable<void>;
         onPluginActivatedObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>>;
         onPluginActivatedObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>>;
+        onNewSceneObservable: BABYLON.Observable<BABYLON.Scene>;
         sceneImportDefaults: {
         sceneImportDefaults: {
             [key: string]: any;
             [key: string]: any;
         };
         };
@@ -510,6 +511,42 @@ declare module INSPECTOR {
     }
     }
 }
 }
 declare module INSPECTOR {
 declare module INSPECTOR {
+    interface IAnimationCurveEditorComponentProps {
+        close: (event: any) => void;
+        title: string;
+    }
+    export class AnimationCurveEditorComponent extends React.Component<IAnimationCurveEditorComponentProps, {
+        isOpen: boolean;
+    }> {
+        constructor(props: IAnimationCurveEditorComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IPopupComponentProps {
+        id: string;
+        title: string;
+        size: {
+            width: number;
+            height: number;
+        };
+        onOpen: (window: Window) => void;
+        onClose: (window: Window) => void;
+    }
+    export class PopupComponent extends React.Component<IPopupComponentProps, {
+        isComponentMounted: boolean;
+        blockedByBrowser: boolean;
+    }> {
+        private _container;
+        private _window;
+        constructor(props: IPopupComponentProps);
+        componentDidMount(): void;
+        openPopup(): void;
+        componentWillUnmount(): void;
+        render(): React.ReactPortal | null;
+    }
+}
+declare module INSPECTOR {
     interface IAnimationGridComponentProps {
     interface IAnimationGridComponentProps {
         globalState: GlobalState;
         globalState: GlobalState;
         animatable: BABYLON.IAnimatable;
         animatable: BABYLON.IAnimatable;
@@ -526,6 +563,7 @@ declare module INSPECTOR {
         private _onBeforeRenderObserver;
         private _onBeforeRenderObserver;
         private _isPlaying;
         private _isPlaying;
         private timelineRef;
         private timelineRef;
+        private _isCurveEditorOpen;
         private _animationControl;
         private _animationControl;
         constructor(props: IAnimationGridComponentProps);
         constructor(props: IAnimationGridComponentProps);
         playOrPause(): void;
         playOrPause(): void;
@@ -533,6 +571,8 @@ declare module INSPECTOR {
         componentWillUnmount(): void;
         componentWillUnmount(): void;
         onCurrentFrameChange(value: number): void;
         onCurrentFrameChange(value: number): void;
         onChangeFromOrTo(): void;
         onChangeFromOrTo(): void;
+        onOpenAnimationCurveEditor(): void;
+        onCloseAnimationCurveEditor(window: Window | null): void;
         render(): JSX.Element;
         render(): JSX.Element;
     }
     }
 }
 }
@@ -2126,6 +2166,7 @@ declare module INSPECTOR {
         private _onSelectionChangeObserver;
         private _onSelectionChangeObserver;
         private _onSelectionRenamedObserver;
         private _onSelectionRenamedObserver;
         private _onNewSceneAddedObserver;
         private _onNewSceneAddedObserver;
+        private _onNewSceneObserver;
         private sceneExplorerRef;
         private sceneExplorerRef;
         private _once;
         private _once;
         private _hooked;
         private _hooked;
@@ -2193,6 +2234,7 @@ declare module INSPECTOR {
         static get IsVisible(): boolean;
         static get IsVisible(): boolean;
         static EarlyAttachToLoader(): void;
         static EarlyAttachToLoader(): void;
         static Show(scene: BABYLON.Scene, userOptions: Partial<BABYLON.IInspectorOptions>): void;
         static Show(scene: BABYLON.Scene, userOptions: Partial<BABYLON.IInspectorOptions>): void;
+        static _SetNewScene(scene: BABYLON.Scene): void;
         static _CreateCanvasContainer(parentControl: HTMLElement): void;
         static _CreateCanvasContainer(parentControl: HTMLElement): void;
         private static _DestroyCanvasContainer;
         private static _DestroyCanvasContainer;
         private static _Cleanup;
         private static _Cleanup;

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

@@ -48,6 +48,7 @@ declare module "babylonjs-inspector/components/globalState" {
         onTabChangedObservable: Observable<number>;
         onTabChangedObservable: Observable<number>;
         onSelectionRenamedObservable: Observable<void>;
         onSelectionRenamedObservable: Observable<void>;
         onPluginActivatedObserver: Nullable<Observer<ISceneLoaderPlugin | ISceneLoaderPluginAsync>>;
         onPluginActivatedObserver: Nullable<Observer<ISceneLoaderPlugin | ISceneLoaderPluginAsync>>;
+        onNewSceneObservable: Observable<Scene>;
         sceneImportDefaults: {
         sceneImportDefaults: {
             [key: string]: any;
             [key: string]: any;
         };
         };
@@ -578,6 +579,44 @@ declare module "babylonjs-inspector/components/actionTabs/lines/floatLineCompone
         render(): JSX.Element;
         render(): JSX.Element;
     }
     }
 }
 }
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent" {
+    import * as React from "react";
+    interface IAnimationCurveEditorComponentProps {
+        close: (event: any) => void;
+        title: string;
+    }
+    export class AnimationCurveEditorComponent extends React.Component<IAnimationCurveEditorComponentProps, {
+        isOpen: boolean;
+    }> {
+        constructor(props: IAnimationCurveEditorComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/animations/popupComponent" {
+    import * as React from "react";
+    interface IPopupComponentProps {
+        id: string;
+        title: string;
+        size: {
+            width: number;
+            height: number;
+        };
+        onOpen: (window: Window) => void;
+        onClose: (window: Window) => void;
+    }
+    export class PopupComponent extends React.Component<IPopupComponentProps, {
+        isComponentMounted: boolean;
+        blockedByBrowser: boolean;
+    }> {
+        private _container;
+        private _window;
+        constructor(props: IPopupComponentProps);
+        componentDidMount(): void;
+        openPopup(): void;
+        componentWillUnmount(): void;
+        render(): React.ReactPortal | null;
+    }
+}
 declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/animations/animationPropertyGridComponent" {
 declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/animations/animationPropertyGridComponent" {
     import * as React from "react";
     import * as React from "react";
     import { Observable } from "babylonjs/Misc/observable";
     import { Observable } from "babylonjs/Misc/observable";
@@ -602,6 +641,7 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/ani
         private _onBeforeRenderObserver;
         private _onBeforeRenderObserver;
         private _isPlaying;
         private _isPlaying;
         private timelineRef;
         private timelineRef;
+        private _isCurveEditorOpen;
         private _animationControl;
         private _animationControl;
         constructor(props: IAnimationGridComponentProps);
         constructor(props: IAnimationGridComponentProps);
         playOrPause(): void;
         playOrPause(): void;
@@ -609,6 +649,8 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/ani
         componentWillUnmount(): void;
         componentWillUnmount(): void;
         onCurrentFrameChange(value: number): void;
         onCurrentFrameChange(value: number): void;
         onChangeFromOrTo(): void;
         onChangeFromOrTo(): void;
+        onOpenAnimationCurveEditor(): void;
+        onCloseAnimationCurveEditor(window: Window | null): void;
         render(): JSX.Element;
         render(): JSX.Element;
     }
     }
 }
 }
@@ -2683,6 +2725,7 @@ declare module "babylonjs-inspector/components/sceneExplorer/sceneExplorerCompon
         private _onSelectionChangeObserver;
         private _onSelectionChangeObserver;
         private _onSelectionRenamedObserver;
         private _onSelectionRenamedObserver;
         private _onNewSceneAddedObserver;
         private _onNewSceneAddedObserver;
+        private _onNewSceneObserver;
         private sceneExplorerRef;
         private sceneExplorerRef;
         private _once;
         private _once;
         private _hooked;
         private _hooked;
@@ -2758,6 +2801,7 @@ declare module "babylonjs-inspector/inspector" {
         static get IsVisible(): boolean;
         static get IsVisible(): boolean;
         static EarlyAttachToLoader(): void;
         static EarlyAttachToLoader(): void;
         static Show(scene: Scene, userOptions: Partial<IInspectorOptions>): void;
         static Show(scene: Scene, userOptions: Partial<IInspectorOptions>): void;
+        static _SetNewScene(scene: Scene): void;
         static _CreateCanvasContainer(parentControl: HTMLElement): void;
         static _CreateCanvasContainer(parentControl: HTMLElement): void;
         private static _DestroyCanvasContainer;
         private static _DestroyCanvasContainer;
         private static _Cleanup;
         private static _Cleanup;
@@ -2811,6 +2855,7 @@ declare module INSPECTOR {
         onTabChangedObservable: BABYLON.Observable<number>;
         onTabChangedObservable: BABYLON.Observable<number>;
         onSelectionRenamedObservable: BABYLON.Observable<void>;
         onSelectionRenamedObservable: BABYLON.Observable<void>;
         onPluginActivatedObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>>;
         onPluginActivatedObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>>;
+        onNewSceneObservable: BABYLON.Observable<BABYLON.Scene>;
         sceneImportDefaults: {
         sceneImportDefaults: {
             [key: string]: any;
             [key: string]: any;
         };
         };
@@ -3286,6 +3331,42 @@ declare module INSPECTOR {
     }
     }
 }
 }
 declare module INSPECTOR {
 declare module INSPECTOR {
+    interface IAnimationCurveEditorComponentProps {
+        close: (event: any) => void;
+        title: string;
+    }
+    export class AnimationCurveEditorComponent extends React.Component<IAnimationCurveEditorComponentProps, {
+        isOpen: boolean;
+    }> {
+        constructor(props: IAnimationCurveEditorComponentProps);
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
+    interface IPopupComponentProps {
+        id: string;
+        title: string;
+        size: {
+            width: number;
+            height: number;
+        };
+        onOpen: (window: Window) => void;
+        onClose: (window: Window) => void;
+    }
+    export class PopupComponent extends React.Component<IPopupComponentProps, {
+        isComponentMounted: boolean;
+        blockedByBrowser: boolean;
+    }> {
+        private _container;
+        private _window;
+        constructor(props: IPopupComponentProps);
+        componentDidMount(): void;
+        openPopup(): void;
+        componentWillUnmount(): void;
+        render(): React.ReactPortal | null;
+    }
+}
+declare module INSPECTOR {
     interface IAnimationGridComponentProps {
     interface IAnimationGridComponentProps {
         globalState: GlobalState;
         globalState: GlobalState;
         animatable: BABYLON.IAnimatable;
         animatable: BABYLON.IAnimatable;
@@ -3302,6 +3383,7 @@ declare module INSPECTOR {
         private _onBeforeRenderObserver;
         private _onBeforeRenderObserver;
         private _isPlaying;
         private _isPlaying;
         private timelineRef;
         private timelineRef;
+        private _isCurveEditorOpen;
         private _animationControl;
         private _animationControl;
         constructor(props: IAnimationGridComponentProps);
         constructor(props: IAnimationGridComponentProps);
         playOrPause(): void;
         playOrPause(): void;
@@ -3309,6 +3391,8 @@ declare module INSPECTOR {
         componentWillUnmount(): void;
         componentWillUnmount(): void;
         onCurrentFrameChange(value: number): void;
         onCurrentFrameChange(value: number): void;
         onChangeFromOrTo(): void;
         onChangeFromOrTo(): void;
+        onOpenAnimationCurveEditor(): void;
+        onCloseAnimationCurveEditor(window: Window | null): void;
         render(): JSX.Element;
         render(): JSX.Element;
     }
     }
 }
 }
@@ -4902,6 +4986,7 @@ declare module INSPECTOR {
         private _onSelectionChangeObserver;
         private _onSelectionChangeObserver;
         private _onSelectionRenamedObserver;
         private _onSelectionRenamedObserver;
         private _onNewSceneAddedObserver;
         private _onNewSceneAddedObserver;
+        private _onNewSceneObserver;
         private sceneExplorerRef;
         private sceneExplorerRef;
         private _once;
         private _once;
         private _hooked;
         private _hooked;
@@ -4969,6 +5054,7 @@ declare module INSPECTOR {
         static get IsVisible(): boolean;
         static get IsVisible(): boolean;
         static EarlyAttachToLoader(): void;
         static EarlyAttachToLoader(): void;
         static Show(scene: BABYLON.Scene, userOptions: Partial<BABYLON.IInspectorOptions>): void;
         static Show(scene: BABYLON.Scene, userOptions: Partial<BABYLON.IInspectorOptions>): void;
+        static _SetNewScene(scene: BABYLON.Scene): void;
         static _CreateCanvasContainer(parentControl: HTMLElement): void;
         static _CreateCanvasContainer(parentControl: HTMLElement): void;
         private static _DestroyCanvasContainer;
         private static _DestroyCanvasContainer;
         private static _Cleanup;
         private static _Cleanup;

+ 7 - 7
dist/preview release/inspector/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-inspector",
     "name": "babylonjs-inspector",
     "description": "The Babylon.js inspector.",
     "description": "The Babylon.js inspector.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -29,12 +29,12 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.11",
-        "babylonjs-gui": "4.2.0-alpha.11",
-        "babylonjs-loaders": "4.2.0-alpha.11",
-        "babylonjs-materials": "4.2.0-alpha.11",
-        "babylonjs-serializers": "4.2.0-alpha.11",
-        "babylonjs-gltf2interface": "4.2.0-alpha.11"
+        "babylonjs": "4.2.0-alpha.12",
+        "babylonjs-gui": "4.2.0-alpha.12",
+        "babylonjs-loaders": "4.2.0-alpha.12",
+        "babylonjs-materials": "4.2.0-alpha.12",
+        "babylonjs-serializers": "4.2.0-alpha.12",
+        "babylonjs-gltf2interface": "4.2.0-alpha.12"
     },
     },
     "devDependencies": {
     "devDependencies": {
         "@types/react": "~16.7.3",
         "@types/react": "~16.7.3",

+ 3 - 3
dist/preview release/loaders/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-loaders",
     "name": "babylonjs-loaders",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
     "description": "The Babylon.js file loaders library is an extension you can use to load different 3D file types into a Babylon scene.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs-gltf2interface": "4.2.0-alpha.11",
-        "babylonjs": "4.2.0-alpha.11"
+        "babylonjs-gltf2interface": "4.2.0-alpha.12",
+        "babylonjs": "4.2.0-alpha.12"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

+ 9 - 2
dist/preview release/materialsLibrary/babylon.customMaterial.js

@@ -485,8 +485,10 @@ var CustomMaterial = /** @class */ (function (_super) {
             .replace('#define CUSTOM_FRAGMENT_UPDATE_DIFFUSE', (this.CustomParts.Fragment_Custom_Diffuse ? this.CustomParts.Fragment_Custom_Diffuse : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_DIFFUSE', (this.CustomParts.Fragment_Custom_Diffuse ? this.CustomParts.Fragment_Custom_Diffuse : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_ALPHA', (this.CustomParts.Fragment_Custom_Alpha ? this.CustomParts.Fragment_Custom_Alpha : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_ALPHA', (this.CustomParts.Fragment_Custom_Alpha ? this.CustomParts.Fragment_Custom_Alpha : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
-            .replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', (this.CustomParts.Fragment_Before_Fog ? this.CustomParts.Fragment_Before_Fog : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
+        if (this.CustomParts.Fragment_Before_Fog) {
+            babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore[name + "PixelShader"] = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore[name + "PixelShader"].replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', this.CustomParts.Fragment_Before_Fog);
+        }
         this._isCreatedShader = true;
         this._isCreatedShader = true;
         this._createdShaderName = name;
         this._createdShaderName = name;
         return name;
         return name;
@@ -645,6 +647,9 @@ var PBRCustomMaterial = /** @class */ (function (_super) {
         _this.customShaderNameResolve = _this.Builder;
         _this.customShaderNameResolve = _this.Builder;
         _this.FragmentShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrPixelShader"];
         _this.FragmentShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrPixelShader"];
         _this.VertexShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrVertexShader"];
         _this.VertexShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrVertexShader"];
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockAlbedoOpacity>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockAlbedoOpacity"]);
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockReflectivity>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockReflectivity"]);
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockFinalColorComposition>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockFinalColorComposition"]);
         return _this;
         return _this;
     }
     }
     PBRCustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {
     PBRCustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {
@@ -737,8 +742,10 @@ var PBRCustomMaterial = /** @class */ (function (_super) {
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_METALLICROUGHNESS', (this.CustomParts.Fragment_Custom_MetallicRoughness ? this.CustomParts.Fragment_Custom_MetallicRoughness : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_METALLICROUGHNESS', (this.CustomParts.Fragment_Custom_MetallicRoughness ? this.CustomParts.Fragment_Custom_MetallicRoughness : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_MICROSURFACE', (this.CustomParts.Fragment_Custom_MicroSurface ? this.CustomParts.Fragment_Custom_MicroSurface : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_MICROSURFACE', (this.CustomParts.Fragment_Custom_MicroSurface ? this.CustomParts.Fragment_Custom_MicroSurface : ""))
-            .replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', (this.CustomParts.Fragment_Before_Fog ? this.CustomParts.Fragment_Before_Fog : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
+        if (this.CustomParts.Fragment_Before_Fog) {
+            babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore[name + "PixelShader"] = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore[name + "PixelShader"].replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', this.CustomParts.Fragment_Before_Fog);
+        }
         this._isCreatedShader = true;
         this._isCreatedShader = true;
         this._createdShaderName = name;
         this._createdShaderName = name;
         return name;
         return name;

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


+ 9 - 2
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -873,8 +873,10 @@ var CustomMaterial = /** @class */ (function (_super) {
             .replace('#define CUSTOM_FRAGMENT_UPDATE_DIFFUSE', (this.CustomParts.Fragment_Custom_Diffuse ? this.CustomParts.Fragment_Custom_Diffuse : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_DIFFUSE', (this.CustomParts.Fragment_Custom_Diffuse ? this.CustomParts.Fragment_Custom_Diffuse : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_ALPHA', (this.CustomParts.Fragment_Custom_Alpha ? this.CustomParts.Fragment_Custom_Alpha : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_ALPHA', (this.CustomParts.Fragment_Custom_Alpha ? this.CustomParts.Fragment_Custom_Alpha : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
-            .replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', (this.CustomParts.Fragment_Before_Fog ? this.CustomParts.Fragment_Before_Fog : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
+        if (this.CustomParts.Fragment_Before_Fog) {
+            babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore[name + "PixelShader"] = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore[name + "PixelShader"].replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', this.CustomParts.Fragment_Before_Fog);
+        }
         this._isCreatedShader = true;
         this._isCreatedShader = true;
         this._createdShaderName = name;
         this._createdShaderName = name;
         return name;
         return name;
@@ -1033,6 +1035,9 @@ var PBRCustomMaterial = /** @class */ (function (_super) {
         _this.customShaderNameResolve = _this.Builder;
         _this.customShaderNameResolve = _this.Builder;
         _this.FragmentShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrPixelShader"];
         _this.FragmentShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrPixelShader"];
         _this.VertexShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrVertexShader"];
         _this.VertexShader = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore["pbrVertexShader"];
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockAlbedoOpacity>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockAlbedoOpacity"]);
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockReflectivity>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockReflectivity"]);
+        _this.FragmentShader = _this.FragmentShader.replace(/#include<pbrBlockFinalColorComposition>/g, babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].IncludesShadersStore["pbrBlockFinalColorComposition"]);
         return _this;
         return _this;
     }
     }
     PBRCustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {
     PBRCustomMaterial.prototype.AttachAfterBind = function (mesh, effect) {
@@ -1125,8 +1130,10 @@ var PBRCustomMaterial = /** @class */ (function (_super) {
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_METALLICROUGHNESS', (this.CustomParts.Fragment_Custom_MetallicRoughness ? this.CustomParts.Fragment_Custom_MetallicRoughness : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_METALLICROUGHNESS', (this.CustomParts.Fragment_Custom_MetallicRoughness ? this.CustomParts.Fragment_Custom_MetallicRoughness : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_MICROSURFACE', (this.CustomParts.Fragment_Custom_MicroSurface ? this.CustomParts.Fragment_Custom_MicroSurface : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_MICROSURFACE', (this.CustomParts.Fragment_Custom_MicroSurface ? this.CustomParts.Fragment_Custom_MicroSurface : ""))
-            .replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', (this.CustomParts.Fragment_Before_Fog ? this.CustomParts.Fragment_Before_Fog : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
+        if (this.CustomParts.Fragment_Before_Fog) {
+            babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore[name + "PixelShader"] = babylonjs_Materials_effect__WEBPACK_IMPORTED_MODULE_1__["Effect"].ShadersStore[name + "PixelShader"].replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', this.CustomParts.Fragment_Before_Fog);
+        }
         this._isCreatedShader = true;
         this._isCreatedShader = true;
         this._createdShaderName = name;
         this._createdShaderName = name;
         return name;
         return name;

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/materialsLibrary/babylonjs.materials.min.js


+ 2 - 2
dist/preview release/materialsLibrary/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-materials",
     "name": "babylonjs-materials",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.11"
+        "babylonjs": "4.2.0-alpha.12"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 60 - 39
dist/preview release/nodeEditor/babylon.nodeEditor.d.ts


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 7 - 7
dist/preview release/nodeEditor/babylon.nodeEditor.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 513 - 320
dist/preview release/nodeEditor/babylon.nodeEditor.max.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 137 - 88
dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts


+ 2 - 2
dist/preview release/nodeEditor/package.json

@@ -4,14 +4,14 @@
     },
     },
     "name": "babylonjs-node-editor",
     "name": "babylonjs-node-editor",
     "description": "The Babylon.js node material editor.",
     "description": "The Babylon.js node material editor.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
     },
     },
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.11"
+        "babylonjs": "4.2.0-alpha.12"
     },
     },
     "files": [
     "files": [
         "babylon.nodeEditor.max.js.map",
         "babylon.nodeEditor.max.js.map",

+ 1 - 1
dist/preview release/package.json

@@ -7,7 +7,7 @@
     ],
     ],
     "name": "babylonjs",
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 1 - 1
dist/preview release/packagesSizeBaseLine.json

@@ -1 +1 @@
-{"thinEngineOnly":115611,"engineOnly":152019,"sceneOnly":510942,"minGridMaterial":643640,"minStandardMaterial":785002}
+{"thinEngineOnly":115670,"engineOnly":152078,"sceneOnly":511105,"minGridMaterial":644201,"minStandardMaterial":785874}

+ 2 - 2
dist/preview release/postProcessesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-post-process",
     "name": "babylonjs-post-process",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.11"
+        "babylonjs": "4.2.0-alpha.12"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

+ 2 - 2
dist/preview release/proceduralTexturesLibrary/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-procedural-textures",
     "name": "babylonjs-procedural-textures",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.11"
+        "babylonjs": "4.2.0-alpha.12"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

+ 3 - 3
dist/preview release/serializers/package.json

@@ -4,7 +4,7 @@
     },
     },
     "name": "babylonjs-serializers",
     "name": "babylonjs-serializers",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
     "description": "The Babylon.js serializers library is an extension you can use to serialize Babylon scenes.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     ],
     "license": "Apache-2.0",
     "license": "Apache-2.0",
     "dependencies": {
     "dependencies": {
-        "babylonjs": "4.2.0-alpha.11",
-        "babylonjs-gltf2interface": "4.2.0-alpha.11"
+        "babylonjs": "4.2.0-alpha.12",
+        "babylonjs-gltf2interface": "4.2.0-alpha.12"
     },
     },
     "engines": {
     "engines": {
         "node": "*"
         "node": "*"

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 2687 - 195
dist/preview release/viewer/babylon.module.d.ts


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 190 - 126
dist/preview release/viewer/babylon.viewer.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 1 - 1
dist/preview release/viewer/babylon.viewer.max.js


+ 51 - 22
dist/preview release/what's new.md

@@ -2,19 +2,22 @@
 
 
 ## Major updates
 ## Major updates
 
 
-- Added particle editor to the Inspector ([Deltakosh](https://github.com/deltakosh)
+- Added particle editor to the Inspector ([Deltakosh](https://github.com/deltakosh))
 - Added the `ShadowDepthWrapper` class to support accurate shadow generation for custom as well as node material shaders. [Doc](https://doc.babylonjs.com/babylon101/shadows#custom-shadow-map-shaders) ([Popov72](https://github.com/Popov72))
 - Added the `ShadowDepthWrapper` class to support accurate shadow generation for custom as well as node material shaders. [Doc](https://doc.babylonjs.com/babylon101/shadows#custom-shadow-map-shaders) ([Popov72](https://github.com/Popov72))
 
 
 ## Updates
 ## Updates
 
 
 ### General
 ### General
 
 
-- Refactored React refs from old string API to React.createRef() API ([belfortk](https://github.com/belfortk)
+- Refactored React refs from old string API to React.createRef() API ([belfortk](https://github.com/belfortk))
 - Scale on one axis for `BoundingBoxGizmo` ([cedricguillemet](https://github.com/cedricguillemet))
 - Scale on one axis for `BoundingBoxGizmo` ([cedricguillemet](https://github.com/cedricguillemet))
 - Simplified code contributions by fully automating the dev setup with gitpod ([nisarhassan12](https://github.com/nisarhassan12))
 - Simplified code contributions by fully automating the dev setup with gitpod ([nisarhassan12](https://github.com/nisarhassan12))
 - Add a `CascadedShadowMap.IsSupported` method and log an error instead of throwing an exception when CSM is not supported ([Popov72](https://github.com/Popov72))
 - Add a `CascadedShadowMap.IsSupported` method and log an error instead of throwing an exception when CSM is not supported ([Popov72](https://github.com/Popov72))
 - Added initial code for DeviceInputSystem ([PolygonalSun](https://github.com/PolygonalSun))
 - Added initial code for DeviceInputSystem ([PolygonalSun](https://github.com/PolygonalSun))
 - Added support for `material.disableColorWrite` ([Deltakosh](https://github.com/deltakosh))
 - Added support for `material.disableColorWrite` ([Deltakosh](https://github.com/deltakosh))
+- The Mesh Asset Task also accepts File as sceneInput ([RaananW](https://github.com/RaananW))
+- Added support preserving vert colors for CSG objects ([PirateJC](https://github.com/PirateJC))
+- Added support in `ShadowGenerator` for fast fake soft transparent shadows ([Popov72](https://github.com/Popov72))
 
 
 ### Engine
 ### Engine
 
 
@@ -24,8 +27,10 @@
 
 
 ### NME
 ### NME
 
 
-- Frames are now resizable from the corners ([belfortk](https://github.com/belfortk)
-- Can now rename and re-order frame inputs and outputs ([belfortk](https://github.com/belfortk)
+- Frames are now resizable from the corners ([belfortk](https://github.com/belfortk))
+- Can now rename and re-order frame inputs and outputs ([belfortk](https://github.com/belfortk))
+- Can now edit Node port names ([belfortk](https://github.com/belfortk))
+- Updated which node ports are shown on frames by default so that only node ports connected to outside nodes are by default exposed on the frame ([belfortk](https://github.com/belfortk))
 
 
 ### Inspector
 ### Inspector
 
 
@@ -34,6 +39,8 @@
 - Edit all textures (anisotropic, clear coat, sheen, ...) for the PBR materials ([Popov72](https://github.com/Popov72))
 - Edit all textures (anisotropic, clear coat, sheen, ...) for the PBR materials ([Popov72](https://github.com/Popov72))
 - Added right click options to create PBR and Standard Materials ([Deltakosh](https://github.com/deltakosh))
 - Added right click options to create PBR and Standard Materials ([Deltakosh](https://github.com/deltakosh))
 - Added support for recording GIF ([Deltakosh](https://github.com/deltakosh))
 - Added support for recording GIF ([Deltakosh](https://github.com/deltakosh))
+- Popup Window available (To be used in Curve Editor) ([pixelspace](https://github.com/devpixelspace))
+- Add support to update inspector when switching to new scene ([belfortk](https://github.com/belfortk))
 
 
 ### Cameras
 ### Cameras
 
 
@@ -48,8 +55,10 @@
 ### Physics
 ### Physics
 
 
 - Fixed time steps or delta time with sub time step for Oimo.js and Cannon.js ([cedricguillemet](https://github.com/cedricguillemet))
 - Fixed time steps or delta time with sub time step for Oimo.js and Cannon.js ([cedricguillemet](https://github.com/cedricguillemet))
+- Ammo.js collision group and mask supported by impostor parameters ([cedricguillemet](https://github.com/cedricguillemet))
 - Ammo.js IDL exposed property update and raycast vehicle stablization support ([MackeyK24](https://github.com/MackeyK24))
 - Ammo.js IDL exposed property update and raycast vehicle stablization support ([MackeyK24](https://github.com/MackeyK24))
 - Recast.js plugin nav mesh and crowd agent to ref performance optimizations. ([MackeyK24](https://github.com/MackeyK24))
 - Recast.js plugin nav mesh and crowd agent to ref performance optimizations. ([MackeyK24](https://github.com/MackeyK24))
+- Added `scene.physicsEnabled` boolean ([Deltakosh](https://github.com/deltakosh))
 
 
 ### Loaders
 ### Loaders
 
 
@@ -83,6 +92,10 @@
 - Support for pointer selection and teleportation in right handed systems ([#7967](https://github.com/BabylonJS/Babylon.js/issues/7967)) ([RaananW](https://github.com/RaananW))
 - Support for pointer selection and teleportation in right handed systems ([#7967](https://github.com/BabylonJS/Babylon.js/issues/7967)) ([RaananW](https://github.com/RaananW))
 - Pointer Selection feature now uses `selectstart` and `selectend` events when gamepad and motion controller are not present ([#7989](https://github.com/BabylonJS/Babylon.js/issues/7989)) ([RaananW](https://github.com/RaananW))
 - Pointer Selection feature now uses `selectstart` and `selectend` events when gamepad and motion controller are not present ([#7989](https://github.com/BabylonJS/Babylon.js/issues/7989)) ([RaananW](https://github.com/RaananW))
 - Removed forced `autoClear` = false settings ([RaananW](https://github.com/RaananW))
 - Removed forced `autoClear` = false settings ([RaananW](https://github.com/RaananW))
+- Added a warning that WebXR can only be served over HTTPS ([RaananW](https://github.com/RaananW))
+- Default (XR-global) rendering group ID can be defined when initializing a default experience ([RaananW](https://github.com/RaananW))
+- Added support for (experimental) haptic actuators ([#8068](https://github.com/BabylonJS/Babylon.js/issues/8068)) ([RaananW](https://github.com/RaananW))
+- It is now possible to enable experimental (AR) features using the options of the default xr helper ([RaananW](https://github.com/RaananW))
 
 
 ### Collisions
 ### Collisions
 
 
@@ -93,38 +106,48 @@
 - Added support for Additive Animation Blending. Existing animations can be converted to additive using the new MakeAnimationAdditive method for Skeletons, AnimationGroups and Animations. Animations can be played additively using the new isAdditive input parameter to the begin animation methods. ([c-morten](https://github.com/c-morten))
 - Added support for Additive Animation Blending. Existing animations can be converted to additive using the new MakeAnimationAdditive method for Skeletons, AnimationGroups and Animations. Animations can be played additively using the new isAdditive input parameter to the begin animation methods. ([c-morten](https://github.com/c-morten))
 
 
 ### Maths
 ### Maths
+
 - Added `Vector3.projectOnPlaneToRef` ([Deltakosh](https://github.com/deltakosh))
 - Added `Vector3.projectOnPlaneToRef` ([Deltakosh](https://github.com/deltakosh))
 
 
+### Particles
+
+- Added local space support for GPU particles ([CraigFeldpsar](https://github.com/craigfeldspar))
+- Added ability to update also colors and uvs of solid particle vertices ([jerome](https://github.com/jbousquie))
+
 ### Build
 ### Build
 
 
 - Fixed an issue with gulp webpack, webpack stream and the viewer ([RaananW](https://github.com/RaananW))
 - Fixed an issue with gulp webpack, webpack stream and the viewer ([RaananW](https://github.com/RaananW))
 
 
+### Playground
+
+- Added support for code templates in the playground ([sailro](http://www.github.com/sailro))
+
 ## Bugs
 ## Bugs
 
 
-- Fix infinite loop in `GlowLayer.unReferenceMeshFromUsingItsOwnMaterial` ([Popov72](https://github.com/Popov72)
+- Fix infinite loop in `GlowLayer.unReferenceMeshFromUsingItsOwnMaterial` ([Popov72](https://github.com/Popov72))
 - Fix picking issue in the Solid Particle System when MultiMaterial is enabled ([jerome](https://github.com/jbousquie))
 - Fix picking issue in the Solid Particle System when MultiMaterial is enabled ([jerome](https://github.com/jbousquie))
-- `QuadraticErrorSimplification` was not exported ([RaananW](https://github.com/Raananw)
-- Fix NME Frames bug where collapsing and moving a frame removed the nodes inside ([belfortk](https://github.com/belfortk)
-- Fix moving / disappearing controls when freezing/unfreezing the ScrollViewer ([Popov72](https://github.com/Popov72)
-- Fix: when using instances, master mesh (if displayed) does not have correct instance buffer values ([Popov72](https://github.com/Popov72)
+- Fix picking issue in the Solid Particle System when expandable ([jerome](https://github.com/jbousquie))
+- `QuadraticErrorSimplification` was not exported ([RaananW](https://github.com/Raananw))
+- Fix NME Frames bug where collapsing and moving a frame removed the nodes inside ([belfortk](https://github.com/belfortk))
+- Fix moving / disappearing controls when freezing/unfreezing the ScrollViewer ([Popov72](https://github.com/Popov72))
+- Fix: when using instances, master mesh (if displayed) does not have correct instance buffer values ([Popov72](https://github.com/Popov72))
 - Exit XR will only trigger only if state is IN_XR ([RaananW](https://github.com/RaananW))
 - Exit XR will only trigger only if state is IN_XR ([RaananW](https://github.com/RaananW))
 - Fix improper baking of transformed textures in `KHR_texture_transform` serializer. ([drigax](https://github.com/Drigax))
 - Fix improper baking of transformed textures in `KHR_texture_transform` serializer. ([drigax](https://github.com/Drigax))
 - Fixed NME codegen: missing common properties for float-value input block. ([ycw](https://github.com/ycw))
 - Fixed NME codegen: missing common properties for float-value input block. ([ycw](https://github.com/ycw))
 - Fixed missing options for MeshBuilder.CreateBox. ([ycw](https://github.com/ycw))
 - Fixed missing options for MeshBuilder.CreateBox. ([ycw](https://github.com/ycw))
-- Fix bug in `Plane.transform` when matrix passed in is not a pure rotation ([Popov72](https://github.com/Popov72)
-- Fix bug in PBR when anisotropy is enabled and no bump texture is provided ([Popov72](https://github.com/Popov72)
-- Fix horizon occlusion in PBR materials ([Popov72](https://github.com/Popov72)
+- Fix bug in `Plane.transform` when matrix passed in is not a pure rotation ([Popov72](https://github.com/Popov72))
+- Fix bug in PBR when anisotropy is enabled and no bump texture is provided ([Popov72](https://github.com/Popov72))
+- Fix horizon occlusion in PBR materials ([Popov72](https://github.com/Popov72))
 - Fix wrong relative position in applyImpulse/applyForce for ammojs plugin ([cedricguillemet](https://github.com/cedricguillemet))
 - Fix wrong relative position in applyImpulse/applyForce for ammojs plugin ([cedricguillemet](https://github.com/cedricguillemet))
-- Fixed delay calculation in Animatable.goToFrame when speedRatio != 1 ([Reimund Järnfors](https://github.com/reimund)
-- Fix bug in PBR when translucency is enabled and an irradiance texture is provided ([Popov72](https://github.com/Popov72)
-- Fix bug in PBR with translucency when irradiance texture is 2D ([Popov72](https://github.com/Popov72)
-- Fix bug in PBR when specific combinations of parameters are used ([Popov72](https://github.com/Popov72)
+- Fixed delay calculation in Animatable.goToFrame when speedRatio != 1 ([Reimund Järnfors](https://github.com/reimund))
+- Fix bug in PBR when translucency is enabled and an irradiance texture is provided ([Popov72](https://github.com/Popov72))
+- Fix bug in PBR with translucency when irradiance texture is 2D ([Popov72](https://github.com/Popov72))
+- Fix bug in PBR when specific combinations of parameters are used ([Popov72](https://github.com/Popov72))
 - Fix texture being inverted on the Y axis by default when using TextureAsset or AssetManager ([broederj](https://github.com/broederj))
 - Fix texture being inverted on the Y axis by default when using TextureAsset or AssetManager ([broederj](https://github.com/broederj))
 - Fix `TexturePacker` cross-origin image requests, fix falsy default options ([ludevik](https://github.com/ludevik))
 - Fix `TexturePacker` cross-origin image requests, fix falsy default options ([ludevik](https://github.com/ludevik))
-- Fix freeze (infinite loop) when disposing a scene that loaded some specific gLTF files ([Popov72](https://github.com/Popov72)
-
-- Fix submesh recreation when it should not ([Popov72](https://github.com/Popov72)
-- Fix `CustomMaterial` and `PBRCustomMaterial` not setting uniforms / samplers / attributes ([Popov72](https://github.com/Popov72)
+- Fix freeze (infinite loop) when disposing a scene that loaded some specific gLTF files ([Popov72](https://github.com/Popov72))
+- Fix submesh recreation when it should not ([Popov72](https://github.com/Popov72))
+- Fix `CustomMaterial` and `PBRCustomMaterial` not setting uniforms / samplers / attributes ([Popov72](https://github.com/Popov72))
 - Fix bug in NME where deleting a node from a frame would not remove its ports on the outside of a frame
 - Fix bug in NME where deleting a node from a frame would not remove its ports on the outside of a frame
 - Fix mesh winding order inversion when merging meshes with overridden side orientation ([drigax](https://github.com/Drigax))
 - Fix mesh winding order inversion when merging meshes with overridden side orientation ([drigax](https://github.com/Drigax))
 - Fixed a rendering issue with GearVR in WebXR mode ([RaananW](https://github.com/RaananW))
 - Fixed a rendering issue with GearVR in WebXR mode ([RaananW](https://github.com/RaananW))
@@ -135,10 +158,16 @@
 - Fix bug in NME where collapsed frames didn't redraw output links to outside nodes ([belfortk](https://github.com/belfortk))
 - Fix bug in NME where collapsed frames didn't redraw output links to outside nodes ([belfortk](https://github.com/belfortk))
 - Fix bug in NME where links were not redrawn after moving frame port ([belfortk](https://github.com/belfortk))
 - Fix bug in NME where links were not redrawn after moving frame port ([belfortk](https://github.com/belfortk))
 - Fix bugs in NME that were causing inconsistent behavior displaying Move Node Up and Down buttons on frame ports ([belfortk](https://github.com/belfortk))
 - Fix bugs in NME that were causing inconsistent behavior displaying Move Node Up and Down buttons on frame ports ([belfortk](https://github.com/belfortk))
-- Fix bug in `ShaderMaterial` when using morph targets ([Popov72](https://github.com/Popov72)
-- Fix bug in playground where child NME windows would not close before page unload events ([belfortk](https://github.com/belfortk)
+- Fix bug in `ShaderMaterial` when using morph targets ([Popov72](https://github.com/Popov72))
+- Fix bug in playground where child NME windows would not close before page unload events ([belfortk](https://github.com/belfortk))
 - Fixed an issue with stereoscopic rendering ([#8000](https://github.com/BabylonJS/Babylon.js/issues/8000)) ([RaananW](https://github.com/RaananW))
 - Fixed an issue with stereoscopic rendering ([#8000](https://github.com/BabylonJS/Babylon.js/issues/8000)) ([RaananW](https://github.com/RaananW))
+- Fix bug with multiple scenes when resizing the screen and there's a glow or highlight layer active ([Popov72](https://github.com/Popov72))
+- Fix an error when compiling with the closure compiler ([ageneau](https://github.com/ageneau/))
+- Fix an error in applying texture to sides of `extrudePolygon` using faceUV[1] ([JohnK](https://github.com/BabylonJSGuide/))
+- Playground didn't work if query params were added to the URL ([RaananW](https://github.com/RaananW))
+- Fixed Path3D `_distances` / length computation ([Poolminer](https://github.com/Poolminer))
 
 
 ## Breaking changes
 ## Breaking changes
 
 
 - `EffectRenderer.render` now takes a `RenderTargetTexture` or an `InternalTexture` as the output texture and only a single `EffectWrapper` for its first argument ([Popov72](https://github.com/Popov72))
 - `EffectRenderer.render` now takes a `RenderTargetTexture` or an `InternalTexture` as the output texture and only a single `EffectWrapper` for its first argument ([Popov72](https://github.com/Popov72))
+- Sound's `updateOptions` takes `options.length` and `options.offset` as seconds and not milliseconds ([RaananW](https://github.com/RaananW))

+ 1 - 0
dist/what's new.md

@@ -353,6 +353,7 @@
 - Fix for bug where comments would break out of frames and break resizing of frames ([Kyle Belfort](https://github.com/belfortk))
 - Fix for bug where comments would break out of frames and break resizing of frames ([Kyle Belfort](https://github.com/belfortk))
 - Fix for bug where frames without comments would display undefined at the bottom right corner ([Kyle Belfort](https://github.com/belfortk))
 - Fix for bug where frames without comments would display undefined at the bottom right corner ([Kyle Belfort](https://github.com/belfortk))
 - Fixed an issue in XR where one of the cameras used for rendering got the wrong framebuffer dimensions ([RaananW](https://github.com/RaananW/))
 - Fixed an issue in XR where one of the cameras used for rendering got the wrong framebuffer dimensions ([RaananW](https://github.com/RaananW/))
+- Fix bug in `StandardMaterial` and `PBRMaterial` where the mesh visibility value is not applied correctly when the material is frozen ([Popov72](https://github.com/Popov72))
 
 
 ## Breaking changes
 ## Breaking changes
 
 

+ 1 - 0
gui/src/2D/advancedDynamicTexture.ts

@@ -504,6 +504,7 @@ export class AdvancedDynamicTexture extends DynamicTexture {
         var textureSize = this.getSize();
         var textureSize = this.getSize();
         var renderWidth = engine.getRenderWidth() * this._renderScale;
         var renderWidth = engine.getRenderWidth() * this._renderScale;
         var renderHeight = engine.getRenderHeight() * this._renderScale;
         var renderHeight = engine.getRenderHeight() * this._renderScale;
+
         if (this._renderAtIdealSize) {
         if (this._renderAtIdealSize) {
             if (this._idealWidth) {
             if (this._idealWidth) {
                 renderHeight = (renderHeight * this._idealWidth) / renderWidth;
                 renderHeight = (renderHeight * this._idealWidth) / renderWidth;

+ 9 - 0
gui/src/2D/controls/control.ts

@@ -281,6 +281,11 @@ export class Control {
     public onAfterDrawObservable = new Observable<Control>();
     public onAfterDrawObservable = new Observable<Control>();
 
 
     /**
     /**
+    * An event triggered when the control has been disposed
+    */
+   public onDisposeObservable = new Observable<Control>();
+
+    /**
      * Get the hosting AdvancedDynamicTexture
      * Get the hosting AdvancedDynamicTexture
      */
      */
     public get host(): AdvancedDynamicTexture {
     public get host(): AdvancedDynamicTexture {
@@ -1914,6 +1919,10 @@ export class Control {
                 this.linkWithMesh(null);
                 this.linkWithMesh(null);
             }
             }
         }
         }
+
+        // Callback
+        this.onDisposeObservable.notifyObservers(this);
+        this.onDisposeObservable.clear();
     }
     }
 
 
     // Statics
     // Statics

+ 2 - 0
inspector/src/components/actionTabs/actionTabs.scss

@@ -1009,6 +1009,8 @@ $line-padding-left: 2px;
                         grid-column: 1;
                         grid-column: 1;
                         opacity: 1;
                         opacity: 1;
                         border: 3px solid red;
                         border: 3px solid red;
+                        margin-bottom: -5px;
+                        z-index: 100;
                         transition: opacity 250ms;
                         transition: opacity 250ms;
                         pointer-events: none;
                         pointer-events: none;
                         
                         

+ 1 - 0
inspector/src/components/actionTabs/tabs/debugTabComponent.tsx

@@ -79,6 +79,7 @@ export class DebugTabComponent extends PaneComponent {
                 </LineContainerComponent>
                 </LineContainerComponent>
                 <LineContainerComponent globalState={this.props.globalState} title="FEATURES">
                 <LineContainerComponent globalState={this.props.globalState} title="FEATURES">
                     <CheckBoxLineComponent label="Animations" isSelected={() => scene.animationsEnabled} onSelect={() => scene.animationsEnabled = !scene.animationsEnabled} />
                     <CheckBoxLineComponent label="Animations" isSelected={() => scene.animationsEnabled} onSelect={() => scene.animationsEnabled = !scene.animationsEnabled} />
+                    <CheckBoxLineComponent label="Physics" isSelected={() => scene.physicsEnabled} onSelect={() => scene.physicsEnabled = !scene.physicsEnabled} />
                     <CheckBoxLineComponent label="Collisions" isSelected={() => scene.collisionsEnabled} onSelect={() => scene.collisionsEnabled = !scene.collisionsEnabled} />
                     <CheckBoxLineComponent label="Collisions" isSelected={() => scene.collisionsEnabled} onSelect={() => scene.collisionsEnabled = !scene.collisionsEnabled} />
                     <CheckBoxLineComponent label="Fog" isSelected={() => scene.fogEnabled} onSelect={() => scene.fogEnabled = !scene.fogEnabled} />
                     <CheckBoxLineComponent label="Fog" isSelected={() => scene.fogEnabled} onSelect={() => scene.fogEnabled = !scene.fogEnabled} />
                     <CheckBoxLineComponent label="Lens flares" isSelected={() => scene.lensFlaresEnabled} onSelect={() => scene.lensFlaresEnabled = !scene.lensFlaresEnabled} />
                     <CheckBoxLineComponent label="Lens flares" isSelected={() => scene.lensFlaresEnabled} onSelect={() => scene.lensFlaresEnabled = !scene.lensFlaresEnabled} />

+ 28 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationCurveEditorComponent.tsx

@@ -0,0 +1,28 @@
+import * as React from "react";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faTimes } from "@fortawesome/free-solid-svg-icons";
+
+interface IAnimationCurveEditorComponentProps {
+    close: (event: any) => void;
+    title: string;
+}
+
+export class AnimationCurveEditorComponent extends React.Component<IAnimationCurveEditorComponentProps, { isOpen: boolean }> {
+
+    constructor(props: IAnimationCurveEditorComponentProps) {
+        super(props);
+    }
+
+    render() {
+        return (
+            <div>
+                <div className="header">
+                    <div>{this.props.title}</div>
+                    <div style={{width:48, height:48}} className="close" onClick={(event: React.MouseEvent<HTMLDivElement, MouseEvent>) => this.props.close(event)}>
+                        <FontAwesomeIcon icon={faTimes} />
+                    </div>
+                </div>
+            </div>
+        );
+    }
+}

+ 55 - 26
inspector/src/components/actionTabs/tabs/propertyGrids/animations/animationPropertyGridComponent.tsx

@@ -18,6 +18,8 @@ import { Nullable } from 'babylonjs/types';
 import { FloatLineComponent } from '../../../lines/floatLineComponent';
 import { FloatLineComponent } from '../../../lines/floatLineComponent';
 import { TextLineComponent } from '../../../lines/textLineComponent';
 import { TextLineComponent } from '../../../lines/textLineComponent';
 import { IAnimatable } from 'babylonjs/Animations/animatable.interface';
 import { IAnimatable } from 'babylonjs/Animations/animatable.interface';
+import { AnimationCurveEditorComponent } from '../animations/animationCurveEditorComponent';
+import { PopupComponent } from '../animations/popupComponent';
 
 
 interface IAnimationGridComponentProps {
 interface IAnimationGridComponentProps {
     globalState: GlobalState;
     globalState: GlobalState;
@@ -34,6 +36,7 @@ export class AnimationGridComponent extends React.Component<IAnimationGridCompon
     private _onBeforeRenderObserver: Nullable<Observer<Scene>>;
     private _onBeforeRenderObserver: Nullable<Observer<Scene>>;
     private _isPlaying = false;
     private _isPlaying = false;
     private timelineRef: React.RefObject<SliderLineComponent>;
     private timelineRef: React.RefObject<SliderLineComponent>;
+    private _isCurveEditorOpen = false;
     private _animationControl = {
     private _animationControl = {
         from: 0,
         from: 0,
         to: 0,
         to: 0,
@@ -58,7 +61,7 @@ export class AnimationGridComponent extends React.Component<IAnimationGridCompon
                 }
                 }
             });
             });
 
 
-            if (animatableAsAny.animations) {                
+            if (animatableAsAny.animations) {
                 this._animations!.push(...animatableAsAny.animations);
                 this._animations!.push(...animatableAsAny.animations);
             }
             }
 
 
@@ -128,6 +131,19 @@ export class AnimationGridComponent extends React.Component<IAnimationGridCompon
         }
         }
     }
     }
 
 
+    onOpenAnimationCurveEditor() {
+        this._isCurveEditorOpen = true;
+    }
+
+    onCloseAnimationCurveEditor(window: Window | null) {
+        this._isCurveEditorOpen = false;
+        if (window === null) {
+            console.log("Window already closed");
+        } else {
+            window.close();
+        }
+    }
+
     render() {
     render() {
         const animatable = this.props.animatable;
         const animatable = this.props.animatable;
         const animatableAsAny = this.props.animatable as any;
         const animatableAsAny = this.props.animatable as any;
@@ -170,7 +186,7 @@ export class AnimationGridComponent extends React.Component<IAnimationGridCompon
                     <>
                     <>
                         <LineContainerComponent globalState={this.props.globalState} title="ANIMATIONS">
                         <LineContainerComponent globalState={this.props.globalState} title="ANIMATIONS">
                             <TextLineComponent label="Count" value={animations.length.toString()} />
                             <TextLineComponent label="Count" value={animations.length.toString()} />
-                            <ButtonLineComponent label="Edit" onClick={() => {}} />
+                            <ButtonLineComponent label="Edit" onClick={() => this.onOpenAnimationCurveEditor()} />
                             {
                             {
                                 animations.map((anim, i) => {
                                 animations.map((anim, i) => {
                                     return (
                                     return (
@@ -178,10 +194,23 @@ export class AnimationGridComponent extends React.Component<IAnimationGridCompon
                                     )
                                     )
                                 })
                                 })
                             }
                             }
+
+                            {
+
+                                this._isCurveEditorOpen && <PopupComponent
+                                    id="curve-editor"
+                                    title="Curve Animation Editor"
+                                    size={{ width: 800, height: 600 }}
+                                    onOpen={(window: Window) => { window.console.log("Window opened!!") }}
+                                    onClose={(window: Window) => this.onCloseAnimationCurveEditor(window)}>
+
+                                    <AnimationCurveEditorComponent title="Animations Curve Editor" close={(event) => this.onCloseAnimationCurveEditor(event.view)}/>
+                                </PopupComponent>
+                            }
                         </LineContainerComponent>
                         </LineContainerComponent>
                         <LineContainerComponent globalState={this.props.globalState} title="ANIMATION GENERAL CONTROL">
                         <LineContainerComponent globalState={this.props.globalState} title="ANIMATION GENERAL CONTROL">
-                            <FloatLineComponent lockObject={this.props.lockObject} isInteger={true} label="From" target={this._animationControl} propertyName="from" onChange={()=> this.onChangeFromOrTo()} />
-                            <FloatLineComponent lockObject={this.props.lockObject} isInteger={true} label="To" target={this._animationControl} propertyName="to" onChange={()=> this.onChangeFromOrTo()}/>
+                            <FloatLineComponent lockObject={this.props.lockObject} isInteger={true} label="From" target={this._animationControl} propertyName="from" onChange={() => this.onChangeFromOrTo()} />
+                            <FloatLineComponent lockObject={this.props.lockObject} isInteger={true} label="To" target={this._animationControl} propertyName="to" onChange={() => this.onChangeFromOrTo()} />
                             <CheckBoxLineComponent label="Loop" onSelect={value => this._animationControl.loop = value} isSelected={() => this._animationControl.loop} />
                             <CheckBoxLineComponent label="Loop" onSelect={value => this._animationControl.loop = value} isSelected={() => this._animationControl.loop} />
                             {
                             {
                                 this._isPlaying &&
                                 this._isPlaying &&
@@ -189,32 +218,32 @@ export class AnimationGridComponent extends React.Component<IAnimationGridCompon
                                     step={(this._animationControl.to - this._animationControl.from) / 1000.0} directValue={this.state.currentFrame}
                                     step={(this._animationControl.to - this._animationControl.from) / 1000.0} directValue={this.state.currentFrame}
                                     onInput={value => this.onCurrentFrameChange(value)}
                                     onInput={value => this.onCurrentFrameChange(value)}
                                 />
                                 />
-                            }                         
-                            <ButtonLineComponent label={this._isPlaying ? "Stop" : "Play"} onClick={() => this.playOrPause()} />                        
+                            }
+                            <ButtonLineComponent label={this._isPlaying ? "Stop" : "Play"} onClick={() => this.playOrPause()} />
                             {
                             {
                                 (this._ranges.length > 0 || this._animations && this._animations.length > 0) &&
                                 (this._ranges.length > 0 || this._animations && this._animations.length > 0) &&
-                                    <>
-                                        <CheckBoxLineComponent label="Enable override" onSelect={value => {
-                                            if (value) {
-                                                animatableAsAny.animationPropertiesOverride = new AnimationPropertiesOverride();
-                                                animatableAsAny.animationPropertiesOverride.blendingSpeed = 0.05;
-                                            } else {
-                                                animatableAsAny.animationPropertiesOverride = null;
-                                            }
-                                            this.forceUpdate();
-                                        }} isSelected={() => animatableAsAny.animationPropertiesOverride != null}
-                                            onValueChanged={() => this.forceUpdate()}
-                                        />
-                                        {
-                                            animatableAsAny.animationPropertiesOverride != null &&
-                                            <div>
-                                                <CheckBoxLineComponent label="Enable blending" target={animatableAsAny.animationPropertiesOverride} propertyName="enableBlending" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                                                <SliderLineComponent label="Blending speed" target={animatableAsAny.animationPropertiesOverride} propertyName="blendingSpeed" minimum={0} maximum={0.1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
-                                            </div>
+                                <>
+                                    <CheckBoxLineComponent label="Enable override" onSelect={value => {
+                                        if (value) {
+                                            animatableAsAny.animationPropertiesOverride = new AnimationPropertiesOverride();
+                                            animatableAsAny.animationPropertiesOverride.blendingSpeed = 0.05;
+                                        } else {
+                                            animatableAsAny.animationPropertiesOverride = null;
                                         }
                                         }
-                                    </>
+                                        this.forceUpdate();
+                                    }} isSelected={() => animatableAsAny.animationPropertiesOverride != null}
+                                        onValueChanged={() => this.forceUpdate()}
+                                    />
+                                    {
+                                        animatableAsAny.animationPropertiesOverride != null &&
+                                        <div>
+                                            <CheckBoxLineComponent label="Enable blending" target={animatableAsAny.animationPropertiesOverride} propertyName="enableBlending" onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                                            <SliderLineComponent label="Blending speed" target={animatableAsAny.animationPropertiesOverride} propertyName="blendingSpeed" minimum={0} maximum={0.1} step={0.01} onPropertyChangedObservable={this.props.onPropertyChangedObservable} />
+                                        </div>
+                                    }
+                                </>
                             }
                             }
-                        </LineContainerComponent>    
+                        </LineContainerComponent>
                     </>
                     </>
                 }
                 }
             </div>
             </div>

+ 84 - 0
inspector/src/components/actionTabs/tabs/propertyGrids/animations/popupComponent.tsx

@@ -0,0 +1,84 @@
+import * as React from "react";
+import * as ReactDOM from 'react-dom';
+
+interface IPopupComponentProps {
+    id: string,
+    title: string,
+    size: { width: number, height: number },
+    onOpen: (window: Window) => void,
+    onClose: (window: Window) => void,
+}
+
+export class PopupComponent extends React.Component<IPopupComponentProps, { isComponentMounted: boolean, blockedByBrowser: boolean }> {
+
+    private _container: HTMLDivElement;
+    private _window: Window | null;
+
+    constructor(props: IPopupComponentProps) {
+        super(props);
+
+        this._container = document.createElement('div')
+        this._container.id = this.props.id;
+        this._window;
+
+        this.state = {
+            isComponentMounted: false,
+            blockedByBrowser: false,
+        }
+    }
+
+    componentDidMount() {
+        this.openPopup()
+        this.setState({ isComponentMounted: true });
+    }
+
+    openPopup() {
+        const { title, size, onOpen, onClose } = this.props
+
+        const windowCreationOptionsList = {
+            width: size.width,
+            height: size.height,
+            top: (window.innerHeight - size.width) / 2 + window.screenY,
+            left: (window.innerWidth - size.height) / 2 + window.screenX
+        };
+
+        var windowCreationOptions = Object.keys(windowCreationOptionsList)
+            .map(
+                (key) => key + '=' + (windowCreationOptionsList as any)[key]
+            )
+            .join(',');
+
+        this._window = window.open("", title, windowCreationOptions);
+
+        if (this._window) {
+            this._window.document.title = title;
+            this._window.document.body.appendChild(this._container);
+            onOpen(this._window);
+            this._window.addEventListener('beforeunload', () => this._window && onClose(this._window));
+
+        } else {
+
+            if (!this._window) {
+                this.setState({ blockedByBrowser: true }, () => {
+                    if (this.state.blockedByBrowser) {
+                        alert("You might have blocked popups in your browser");
+                        console.warn("Popup window couldn't be created");
+                    }
+                });
+            }
+        }
+
+    }
+
+    componentWillUnmount() {
+        if (this._window) {
+            this._window.close()
+        }
+    }
+
+    render() {
+        if (!this.state.isComponentMounted) return null
+        return ReactDOM.createPortal(this.props.children, this._container)
+    }
+
+}

+ 1 - 1
inspector/src/components/globalState.ts

@@ -20,7 +20,7 @@ export class GlobalState {
     public onTabChangedObservable = new Observable<number>();
     public onTabChangedObservable = new Observable<number>();
     public onSelectionRenamedObservable = new Observable<void>();
     public onSelectionRenamedObservable = new Observable<void>();
     public onPluginActivatedObserver: Nullable<Observer<ISceneLoaderPlugin | ISceneLoaderPluginAsync>>;
     public onPluginActivatedObserver: Nullable<Observer<ISceneLoaderPlugin | ISceneLoaderPluginAsync>>;
-
+    public onNewSceneObservable = new Observable<Scene>();
     public sceneImportDefaults: { [key: string]: any } = {};
     public sceneImportDefaults: { [key: string]: any } = {};
 
 
     public validationResults: Nullable<IGLTFValidationResults> = null;
     public validationResults: Nullable<IGLTFValidationResults> = null;

+ 10 - 0
inspector/src/components/sceneExplorer/sceneExplorerComponent.tsx

@@ -63,6 +63,7 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
     private _onSelectionChangeObserver: Nullable<Observer<any>>;
     private _onSelectionChangeObserver: Nullable<Observer<any>>;
     private _onSelectionRenamedObserver: Nullable<Observer<void>>;
     private _onSelectionRenamedObserver: Nullable<Observer<void>>;
     private _onNewSceneAddedObserver: Nullable<Observer<Scene>>;
     private _onNewSceneAddedObserver: Nullable<Observer<Scene>>;
+    private _onNewSceneObserver: Nullable<Observer<Scene>>;
     private sceneExplorerRef: React.RefObject<Resizable>;
     private sceneExplorerRef: React.RefObject<Resizable>;
 
 
 
 
@@ -79,6 +80,11 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
         this.sceneMutationFunc = this.processMutation.bind(this);
         this.sceneMutationFunc = this.processMutation.bind(this);
 
 
         this.sceneExplorerRef = React.createRef();
         this.sceneExplorerRef = React.createRef();
+        this._onNewSceneObserver = this.props.globalState.onNewSceneObservable.add((scene: Scene) => {
+            this.setState({
+                scene
+            });
+        })
     }
     }
 
 
     processMutation() {
     processMutation() {
@@ -114,6 +120,10 @@ export class SceneExplorerComponent extends React.Component<ISceneExplorerCompon
             EngineStore.LastCreatedEngine!.onNewSceneAddedObservable.remove(this._onNewSceneAddedObserver);
             EngineStore.LastCreatedEngine!.onNewSceneAddedObservable.remove(this._onNewSceneAddedObserver);
         }
         }
 
 
+        if(this._onNewSceneObserver){
+            this.props.globalState.onNewSceneObservable.remove(this._onNewSceneObserver);
+        }
+
         const scene = this.state.scene;
         const scene = this.state.scene;
 
 
         scene.onNewSkeletonAddedObservable.removeCallback(this.sceneMutationFunc);
         scene.onNewSkeletonAddedObservable.removeCallback(this.sceneMutationFunc);

+ 5 - 0
inspector/src/inspector.ts

@@ -417,6 +417,11 @@ export class Inspector {
         }
         }
     }
     }
 
 
+    public static _SetNewScene(scene: Scene) {
+        this._Scene = scene;
+        this._GlobalState.onNewSceneObservable.notifyObservers(scene);
+    }
+
     public static _CreateCanvasContainer(parentControl: HTMLElement) {
     public static _CreateCanvasContainer(parentControl: HTMLElement) {
         // Create a container for previous elements
         // Create a container for previous elements
         this._NewCanvasContainer = parentControl.ownerDocument!.createElement("div");
         this._NewCanvasContainer = parentControl.ownerDocument!.createElement("div");

+ 4 - 1
materialsLibrary/src/custom/customMaterial.ts

@@ -159,9 +159,12 @@ export class CustomMaterial extends StandardMaterial {
             .replace('#define CUSTOM_FRAGMENT_UPDATE_DIFFUSE', (this.CustomParts.Fragment_Custom_Diffuse ? this.CustomParts.Fragment_Custom_Diffuse : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_DIFFUSE', (this.CustomParts.Fragment_Custom_Diffuse ? this.CustomParts.Fragment_Custom_Diffuse : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_ALPHA', (this.CustomParts.Fragment_Custom_Alpha ? this.CustomParts.Fragment_Custom_Alpha : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_ALPHA', (this.CustomParts.Fragment_Custom_Alpha ? this.CustomParts.Fragment_Custom_Alpha : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
-            .replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', (this.CustomParts.Fragment_Before_Fog ? this.CustomParts.Fragment_Before_Fog : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
 
 
+        if (this.CustomParts.Fragment_Before_Fog) {
+            Effect.ShadersStore[name + "PixelShader"] = Effect.ShadersStore[name + "PixelShader"].replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', this.CustomParts.Fragment_Before_Fog);
+        }
+
         this._isCreatedShader = true;
         this._isCreatedShader = true;
         this._createdShaderName = name;
         this._createdShaderName = name;
 
 

+ 8 - 1
materialsLibrary/src/custom/pbrCustomMaterial.ts

@@ -157,9 +157,12 @@ export class PBRCustomMaterial extends PBRMaterial {
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_LIGHTS', (this.CustomParts.Fragment_Before_Lights ? this.CustomParts.Fragment_Before_Lights : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_METALLICROUGHNESS', (this.CustomParts.Fragment_Custom_MetallicRoughness ? this.CustomParts.Fragment_Custom_MetallicRoughness : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_METALLICROUGHNESS', (this.CustomParts.Fragment_Custom_MetallicRoughness ? this.CustomParts.Fragment_Custom_MetallicRoughness : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_MICROSURFACE', (this.CustomParts.Fragment_Custom_MicroSurface ? this.CustomParts.Fragment_Custom_MicroSurface : ""))
             .replace('#define CUSTOM_FRAGMENT_UPDATE_MICROSURFACE', (this.CustomParts.Fragment_Custom_MicroSurface ? this.CustomParts.Fragment_Custom_MicroSurface : ""))
-            .replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', (this.CustomParts.Fragment_Before_Fog ? this.CustomParts.Fragment_Before_Fog : ""))
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
             .replace('#define CUSTOM_FRAGMENT_BEFORE_FRAGCOLOR', (this.CustomParts.Fragment_Before_FragColor ? this.CustomParts.Fragment_Before_FragColor : ""));
 
 
+        if (this.CustomParts.Fragment_Before_Fog) {
+            Effect.ShadersStore[name + "PixelShader"] = Effect.ShadersStore[name + "PixelShader"].replace('#define CUSTOM_FRAGMENT_BEFORE_FOG', this.CustomParts.Fragment_Before_Fog);
+        }
+
         this._isCreatedShader = true;
         this._isCreatedShader = true;
         this._createdShaderName = name;
         this._createdShaderName = name;
 
 
@@ -173,6 +176,10 @@ export class PBRCustomMaterial extends PBRMaterial {
 
 
         this.FragmentShader = Effect.ShadersStore["pbrPixelShader"];
         this.FragmentShader = Effect.ShadersStore["pbrPixelShader"];
         this.VertexShader = Effect.ShadersStore["pbrVertexShader"];
         this.VertexShader = Effect.ShadersStore["pbrVertexShader"];
+
+        this.FragmentShader = this.FragmentShader.replace(/#include<pbrBlockAlbedoOpacity>/g, Effect.IncludesShadersStore["pbrBlockAlbedoOpacity"]);
+        this.FragmentShader = this.FragmentShader.replace(/#include<pbrBlockReflectivity>/g, Effect.IncludesShadersStore["pbrBlockReflectivity"]);
+        this.FragmentShader = this.FragmentShader.replace(/#include<pbrBlockFinalColorComposition>/g, Effect.IncludesShadersStore["pbrBlockFinalColorComposition"]);
     }
     }
 
 
     public AddUniform(name: string, kind: string, param: any): PBRCustomMaterial {
     public AddUniform(name: string, kind: string, param: any): PBRCustomMaterial {

+ 104 - 77
nodeEditor/src/blockTools.ts

@@ -62,20 +62,29 @@ import { DerivativeBlock } from 'babylonjs/Materials/Node/Blocks/Fragment/deriva
 import { RefractBlock } from 'babylonjs/Materials/Node/Blocks/refractBlock';
 import { RefractBlock } from 'babylonjs/Materials/Node/Blocks/refractBlock';
 import { ReflectBlock } from 'babylonjs/Materials/Node/Blocks/reflectBlock';
 import { ReflectBlock } from 'babylonjs/Materials/Node/Blocks/reflectBlock';
 import { DesaturateBlock } from 'babylonjs/Materials/Node/Blocks/desaturateBlock';
 import { DesaturateBlock } from 'babylonjs/Materials/Node/Blocks/desaturateBlock';
+import { PBRMetallicRoughnessBlock } from 'babylonjs/Materials/Node/Blocks/PBR/pbrMetallicRoughnessBlock';
+import { SheenBlock } from 'babylonjs/Materials/Node/Blocks/PBR/sheenBlock';
+import { AmbientOcclusionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/ambientOcclusionBlock';
+import { ReflectivityBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectivityBlock';
+import { AnisotropyBlock } from 'babylonjs/Materials/Node/Blocks/PBR/anisotropyBlock';
+import { ReflectionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectionBlock';
+import { ClearCoatBlock } from 'babylonjs/Materials/Node/Blocks/PBR/clearCoatBlock';
+import { RefractionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/refractionBlock';
+import { SubSurfaceBlock } from 'babylonjs/Materials/Node/Blocks/PBR/subSurfaceBlock';
 
 
 export class BlockTools {
 export class BlockTools {
     public static GetBlockFromString(data: string, scene: Scene, nodeMaterial: NodeMaterial) {
     public static GetBlockFromString(data: string, scene: Scene, nodeMaterial: NodeMaterial) {
         switch (data) {
         switch (data) {
             case "DesaturateBlock":
             case "DesaturateBlock":
-                return new DesaturateBlock("Desaturate");                  
+                return new DesaturateBlock("Desaturate");
             case "RefractBlock":
             case "RefractBlock":
-                return new RefractBlock("Refract");               
+                return new RefractBlock("Refract");
             case "ReflectBlock":
             case "ReflectBlock":
-                return new ReflectBlock("Reflect");              
+                return new ReflectBlock("Reflect");
             case "DerivativeBlock":
             case "DerivativeBlock":
-                return new DerivativeBlock("Derivative");               
+                return new DerivativeBlock("Derivative");
             case "Rotate2dBlock":
             case "Rotate2dBlock":
-                return new Rotate2dBlock("Rotate2d");            
+                return new Rotate2dBlock("Rotate2d");
             case "NormalBlendBlock":
             case "NormalBlendBlock":
                 return new NormalBlendBlock("NormalBlend");
                 return new NormalBlendBlock("NormalBlend");
             case "WorleyNoise3DBlock":
             case "WorleyNoise3DBlock":
@@ -95,7 +104,7 @@ export class BlockTools {
             case "ColorMergerBlock":
             case "ColorMergerBlock":
                 return new ColorMergerBlock("ColorMerger");
                 return new ColorMergerBlock("ColorMerger");
             case "VectorMergerBlock":
             case "VectorMergerBlock":
-                return new VectorMergerBlock("VectorMerger");                
+                return new VectorMergerBlock("VectorMerger");
             case "ColorSplitterBlock":
             case "ColorSplitterBlock":
                 return new ColorSplitterBlock("ColorSplitter");
                 return new ColorSplitterBlock("ColorSplitter");
             case "VectorSplitterBlock":
             case "VectorSplitterBlock":
@@ -103,7 +112,7 @@ export class BlockTools {
             case "TextureBlock":
             case "TextureBlock":
                 return new TextureBlock("Texture");
                 return new TextureBlock("Texture");
             case "ReflectionTextureBlock":
             case "ReflectionTextureBlock":
-                return new ReflectionTextureBlock("Reflection texture");                
+                return new ReflectionTextureBlock("Reflection texture");
             case "LightBlock":
             case "LightBlock":
                 return new LightBlock("Lights");
                 return new LightBlock("Lights");
             case "FogBlock":
             case "FogBlock":
@@ -143,45 +152,45 @@ export class BlockTools {
             case "DivideBlock":
             case "DivideBlock":
                 return new DivideBlock("Divide");
                 return new DivideBlock("Divide");
             case "SubtractBlock":
             case "SubtractBlock":
-                return new SubtractBlock("Subtract"); 
+                return new SubtractBlock("Subtract");
             case "StepBlock":
             case "StepBlock":
-                return new StepBlock("Step");        
+                return new StepBlock("Step");
             case "SmoothStepBlock":
             case "SmoothStepBlock":
-                return new SmoothStepBlock("Smooth step");        
+                return new SmoothStepBlock("Smooth step");
             case "OneMinusBlock":
             case "OneMinusBlock":
-                return new OneMinusBlock("One minus");          
+                return new OneMinusBlock("One minus");
             case "ReciprocalBlock":
             case "ReciprocalBlock":
-                return new ReciprocalBlock("Reciprocal");    
+                return new ReciprocalBlock("Reciprocal");
             case "ViewDirectionBlock":
             case "ViewDirectionBlock":
-                return new ViewDirectionBlock("View direction");    
+                return new ViewDirectionBlock("View direction");
             case "LightInformationBlock":
             case "LightInformationBlock":
                 let lightInformationBlock = new LightInformationBlock("Light information");
                 let lightInformationBlock = new LightInformationBlock("Light information");
                 lightInformationBlock.light = scene.lights.length ? scene.lights[0] : null;
                 lightInformationBlock.light = scene.lights.length ? scene.lights[0] : null;
                 return lightInformationBlock;
                 return lightInformationBlock;
             case "MaxBlock":
             case "MaxBlock":
-                return new MaxBlock("Max");       
+                return new MaxBlock("Max");
             case "MinBlock":
             case "MinBlock":
-                return new MinBlock("Min");      
+                return new MinBlock("Min");
             case "LengthBlock":
             case "LengthBlock":
-                return new LengthBlock("Length");   
+                return new LengthBlock("Length");
             case "DistanceBlock":
             case "DistanceBlock":
-                return new DistanceBlock("Distance");     
+                return new DistanceBlock("Distance");
             case "NegateBlock":
             case "NegateBlock":
-                return new NegateBlock("Negate");                                     
-            case "PerturbNormalBlock":                                          
-                return new PerturbNormalBlock("Perturb normal");                     
-            case "RandomNumberBlock":                                          
-                return new RandomNumberBlock("Random number");         
-            case "ReplaceColorBlock":                                          
-                return new ReplaceColorBlock("Replace color");      
-            case "PosterizeBlock":                                          
-                return new PosterizeBlock("Posterize");                              
-            case "ArcTan2Block":                                          
-                return new ArcTan2Block("ArcTan2");                            
-            case "GradientBlock":                                          
-                return new GradientBlock("Gradient");                             
-            case "FrontFacingBlock":                                          
-                return new FrontFacingBlock("Front facing");            
+                return new NegateBlock("Negate");
+            case "PerturbNormalBlock":
+                return new PerturbNormalBlock("Perturb normal");
+            case "RandomNumberBlock":
+                return new RandomNumberBlock("Random number");
+            case "ReplaceColorBlock":
+                return new ReplaceColorBlock("Replace color");
+            case "PosterizeBlock":
+                return new PosterizeBlock("Posterize");
+            case "ArcTan2Block":
+                return new ArcTan2Block("ArcTan2");
+            case "GradientBlock":
+                return new GradientBlock("Gradient");
+            case "FrontFacingBlock":
+                return new FrontFacingBlock("Front facing");
             case "CosBlock": {
             case "CosBlock": {
                 let cosBlock = new TrigonometryBlock("Cos");
                 let cosBlock = new TrigonometryBlock("Cos");
                 cosBlock.operation = TrigonometryBlockOperations.Cos;
                 cosBlock.operation = TrigonometryBlockOperations.Cos;
@@ -196,7 +205,7 @@ export class BlockTools {
                 let absBlock = new TrigonometryBlock("Abs");
                 let absBlock = new TrigonometryBlock("Abs");
                 absBlock.operation = TrigonometryBlockOperations.Abs;
                 absBlock.operation = TrigonometryBlockOperations.Abs;
                 return absBlock;
                 return absBlock;
-            }            
+            }
             case "SqrtBlock": {
             case "SqrtBlock": {
                 let sqrtBlock = new TrigonometryBlock("Sqrt");
                 let sqrtBlock = new TrigonometryBlock("Sqrt");
                 sqrtBlock.operation = TrigonometryBlockOperations.Sqrt;
                 sqrtBlock.operation = TrigonometryBlockOperations.Sqrt;
@@ -231,12 +240,12 @@ export class BlockTools {
                 let signBlock = new TrigonometryBlock("Sign");
                 let signBlock = new TrigonometryBlock("Sign");
                 signBlock.operation = TrigonometryBlockOperations.Sign;
                 signBlock.operation = TrigonometryBlockOperations.Sign;
                 return signBlock;
                 return signBlock;
-            }            
+            }
             case "LogBlock": {
             case "LogBlock": {
                 let logBlock = new TrigonometryBlock("Log");
                 let logBlock = new TrigonometryBlock("Log");
                 logBlock.operation = TrigonometryBlockOperations.Log;
                 logBlock.operation = TrigonometryBlockOperations.Log;
                 return logBlock;
                 return logBlock;
-            }                                                            
+            }
             case "ExpBlock": {
             case "ExpBlock": {
                 let expBlock = new TrigonometryBlock("Exp");
                 let expBlock = new TrigonometryBlock("Exp");
                 expBlock.operation = TrigonometryBlockOperations.Exp;
                 expBlock.operation = TrigonometryBlockOperations.Exp;
@@ -256,7 +265,7 @@ export class BlockTools {
                 let radiansToDegreesBlock = new TrigonometryBlock("Radians to degrees");
                 let radiansToDegreesBlock = new TrigonometryBlock("Radians to degrees");
                 radiansToDegreesBlock.operation = TrigonometryBlockOperations.Degrees;
                 radiansToDegreesBlock.operation = TrigonometryBlockOperations.Degrees;
                 return radiansToDegreesBlock;
                 return radiansToDegreesBlock;
-            }                        
+            }
             case "RoundBlock": {
             case "RoundBlock": {
                 let roundBlock = new TrigonometryBlock("Round");
                 let roundBlock = new TrigonometryBlock("Round");
                 roundBlock.operation = TrigonometryBlockOperations.Round;
                 roundBlock.operation = TrigonometryBlockOperations.Round;
@@ -266,22 +275,22 @@ export class BlockTools {
                 let ceilingBlock = new TrigonometryBlock("Ceiling");
                 let ceilingBlock = new TrigonometryBlock("Ceiling");
                 ceilingBlock.operation = TrigonometryBlockOperations.Ceiling;
                 ceilingBlock.operation = TrigonometryBlockOperations.Ceiling;
                 return ceilingBlock;
                 return ceilingBlock;
-            }     
+            }
             case "FloorBlock": {
             case "FloorBlock": {
                 let floorBlock = new TrigonometryBlock("Floor");
                 let floorBlock = new TrigonometryBlock("Floor");
                 floorBlock.operation = TrigonometryBlockOperations.Floor;
                 floorBlock.operation = TrigonometryBlockOperations.Floor;
                 return floorBlock;
                 return floorBlock;
-            }       
+            }
             case "SawToothWaveBlock": {
             case "SawToothWaveBlock": {
                 let sawToothWaveBlock = new WaveBlock("SawTooth wave");
                 let sawToothWaveBlock = new WaveBlock("SawTooth wave");
                 sawToothWaveBlock.kind = WaveBlockKind.SawTooth;
                 sawToothWaveBlock.kind = WaveBlockKind.SawTooth;
                 return sawToothWaveBlock;
                 return sawToothWaveBlock;
-            }     
+            }
             case "SquareWaveBlock": {
             case "SquareWaveBlock": {
                 let squareWaveBlock = new WaveBlock("Square wave");
                 let squareWaveBlock = new WaveBlock("Square wave");
                 squareWaveBlock.kind = WaveBlockKind.Square;
                 squareWaveBlock.kind = WaveBlockKind.Square;
                 return squareWaveBlock;
                 return squareWaveBlock;
-            }     
+            }
             case "TriangleWaveBlock": {
             case "TriangleWaveBlock": {
                 let triangleWaveBlock = new WaveBlock("Triangle wave");
                 let triangleWaveBlock = new WaveBlock("Triangle wave");
                 triangleWaveBlock.kind = WaveBlockKind.Triangle;
                 triangleWaveBlock.kind = WaveBlockKind.Triangle;
@@ -291,95 +300,95 @@ export class BlockTools {
                 let worldMatrixBlock = new InputBlock("World");
                 let worldMatrixBlock = new InputBlock("World");
                 worldMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.World);
                 worldMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.World);
                 return worldMatrixBlock;
                 return worldMatrixBlock;
-            }             
+            }
             case "WorldViewMatrixBlock": {
             case "WorldViewMatrixBlock": {
                 let worldViewMatrixBlock = new InputBlock("World x View");
                 let worldViewMatrixBlock = new InputBlock("World x View");
                 worldViewMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.WorldView);
                 worldViewMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.WorldView);
                 return worldViewMatrixBlock;
                 return worldViewMatrixBlock;
-            }             
+            }
             case "WorldViewProjectionMatrixBlock": {
             case "WorldViewProjectionMatrixBlock": {
                 let worldViewProjectionMatrixBlock = new InputBlock("World x View x Projection");
                 let worldViewProjectionMatrixBlock = new InputBlock("World x View x Projection");
                 worldViewProjectionMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.WorldViewProjection);
                 worldViewProjectionMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.WorldViewProjection);
                 return worldViewProjectionMatrixBlock;
                 return worldViewProjectionMatrixBlock;
-            }                    
+            }
             case "ViewMatrixBlock": {
             case "ViewMatrixBlock": {
                 let viewMatrixBlock = new InputBlock("View");
                 let viewMatrixBlock = new InputBlock("View");
                 viewMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.View);
                 viewMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.View);
                 return viewMatrixBlock;
                 return viewMatrixBlock;
-            }                          
+            }
             case "ViewProjectionMatrixBlock": {
             case "ViewProjectionMatrixBlock": {
                 let viewProjectionMatrixBlock = new InputBlock("View x Projection");
                 let viewProjectionMatrixBlock = new InputBlock("View x Projection");
                 viewProjectionMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.ViewProjection);
                 viewProjectionMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.ViewProjection);
                 return viewProjectionMatrixBlock;
                 return viewProjectionMatrixBlock;
-            }                              
+            }
             case "ProjectionMatrixBlock": {
             case "ProjectionMatrixBlock": {
                 let projectionMatrixBlock = new InputBlock("Projection");
                 let projectionMatrixBlock = new InputBlock("Projection");
                 projectionMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.Projection);
                 projectionMatrixBlock.setAsSystemValue(NodeMaterialSystemValues.Projection);
                 return projectionMatrixBlock;
                 return projectionMatrixBlock;
-            }                                 
+            }
             case "CameraPositionBlock": {
             case "CameraPositionBlock": {
                 let cameraPosition = new InputBlock("Camera position");
                 let cameraPosition = new InputBlock("Camera position");
                 cameraPosition.setAsSystemValue(NodeMaterialSystemValues.CameraPosition);
                 cameraPosition.setAsSystemValue(NodeMaterialSystemValues.CameraPosition);
                 return cameraPosition;
                 return cameraPosition;
-            }                              
+            }
             case "FogColorBlock": {
             case "FogColorBlock": {
                 let FogColor = new InputBlock("Fog color");
                 let FogColor = new InputBlock("Fog color");
                 FogColor.setAsSystemValue(NodeMaterialSystemValues.FogColor);
                 FogColor.setAsSystemValue(NodeMaterialSystemValues.FogColor);
                 return FogColor;
                 return FogColor;
-            }                                   
+            }
             case "PositionBlock": {
             case "PositionBlock": {
                 let meshPosition = new InputBlock("position");
                 let meshPosition = new InputBlock("position");
                 meshPosition.setAsAttribute("position");
                 meshPosition.setAsAttribute("position");
                 return meshPosition;
                 return meshPosition;
-            }                                        
+            }
             case "UVBlock": {
             case "UVBlock": {
                 let meshUV = new InputBlock("uv");
                 let meshUV = new InputBlock("uv");
                 meshUV.setAsAttribute("uv");
                 meshUV.setAsAttribute("uv");
                 return meshUV;
                 return meshUV;
-            }                                         
+            }
             case "ColorBlock": {
             case "ColorBlock": {
                 let meshColor = new InputBlock("color");
                 let meshColor = new InputBlock("color");
                 meshColor.setAsAttribute("color");
                 meshColor.setAsAttribute("color");
                 return meshColor;
                 return meshColor;
-            }                                              
+            }
             case "NormalBlock": {
             case "NormalBlock": {
                 let meshNormal = new InputBlock("normal");
                 let meshNormal = new InputBlock("normal");
                 meshNormal.setAsAttribute("normal");
                 meshNormal.setAsAttribute("normal");
                 return meshNormal;
                 return meshNormal;
-            }                                                 
+            }
             case "TangentBlock": {
             case "TangentBlock": {
                 let meshTangent = new InputBlock("tangent");
                 let meshTangent = new InputBlock("tangent");
                 meshTangent.setAsAttribute("tangent");
                 meshTangent.setAsAttribute("tangent");
                 return meshTangent;
                 return meshTangent;
-            }                                                  
+            }
             case "MatrixIndicesBlock": {
             case "MatrixIndicesBlock": {
                 let meshMatrixIndices = new InputBlock("matricesIndices");
                 let meshMatrixIndices = new InputBlock("matricesIndices");
                 meshMatrixIndices.setAsAttribute("matricesIndices");
                 meshMatrixIndices.setAsAttribute("matricesIndices");
                 return meshMatrixIndices;
                 return meshMatrixIndices;
-            }                                                    
+            }
             case "MatrixWeightsBlock": {
             case "MatrixWeightsBlock": {
                 let meshMatrixWeights = new InputBlock("matricesWeights");
                 let meshMatrixWeights = new InputBlock("matricesWeights");
                 meshMatrixWeights.setAsAttribute("matricesWeights");
                 meshMatrixWeights.setAsAttribute("matricesWeights");
                 return meshMatrixWeights;
                 return meshMatrixWeights;
-            }                                                     
+            }
             case "TimeBlock": {
             case "TimeBlock": {
                 let timeBlock = new InputBlock("Time", undefined, NodeMaterialBlockConnectionPointTypes.Float);
                 let timeBlock = new InputBlock("Time", undefined, NodeMaterialBlockConnectionPointTypes.Float);
                 timeBlock.animationType = AnimatedInputBlockTypes.Time;
                 timeBlock.animationType = AnimatedInputBlockTypes.Time;
                 return timeBlock;
                 return timeBlock;
-            }   
+            }
             case "DeltaTimeBlock": {
             case "DeltaTimeBlock": {
-                let deltaTimeBlock = new InputBlock("Delta time");                
+                let deltaTimeBlock = new InputBlock("Delta time");
                 deltaTimeBlock.setAsSystemValue(NodeMaterialSystemValues.DeltaTime);
                 deltaTimeBlock.setAsSystemValue(NodeMaterialSystemValues.DeltaTime);
                 return deltaTimeBlock;
                 return deltaTimeBlock;
-            }      
+            }
             case "WorldPositionBlock": {
             case "WorldPositionBlock": {
-                let worldPositionBlock = nodeMaterial.getInputBlockByPredicate(b => b.isAttribute && b.name === "position");                
+                let worldPositionBlock = nodeMaterial.getInputBlockByPredicate((b) => b.isAttribute && b.name === "position");
                 if (!worldPositionBlock) {
                 if (!worldPositionBlock) {
                     worldPositionBlock = new InputBlock("position");
                     worldPositionBlock = new InputBlock("position");
                     worldPositionBlock.setAsAttribute("position");
                     worldPositionBlock.setAsAttribute("position");
                 }
                 }
 
 
-                let worldMatrixBlock = nodeMaterial.getInputBlockByPredicate(b => b.isSystemValue && b.systemValue === NodeMaterialSystemValues.World);  
+                let worldMatrixBlock = nodeMaterial.getInputBlockByPredicate((b) => b.isSystemValue && b.systemValue === NodeMaterialSystemValues.World);
 
 
                 if (!worldMatrixBlock) {
                 if (!worldMatrixBlock) {
                     worldMatrixBlock = new InputBlock("World");
                     worldMatrixBlock = new InputBlock("World");
@@ -391,15 +400,15 @@ export class BlockTools {
                 worldMatrixBlock.connectTo(transformBlock);
                 worldMatrixBlock.connectTo(transformBlock);
 
 
                 return transformBlock;
                 return transformBlock;
-            }        
+            }
             case "WorldNormalBlock": {
             case "WorldNormalBlock": {
-                let worldNormalBlock = nodeMaterial.getInputBlockByPredicate(b => b.isAttribute && b.name === "normal");                
+                let worldNormalBlock = nodeMaterial.getInputBlockByPredicate((b) => b.isAttribute && b.name === "normal");
                 if (!worldNormalBlock) {
                 if (!worldNormalBlock) {
                     worldNormalBlock = new InputBlock("normal");
                     worldNormalBlock = new InputBlock("normal");
                     worldNormalBlock.setAsAttribute("normal");
                     worldNormalBlock.setAsAttribute("normal");
                 }
                 }
 
 
-                let worldMatrixBlock = nodeMaterial.getInputBlockByPredicate(b => b.isSystemValue && b.systemValue === NodeMaterialSystemValues.World);  
+                let worldMatrixBlock = nodeMaterial.getInputBlockByPredicate((b) => b.isSystemValue && b.systemValue === NodeMaterialSystemValues.World);
 
 
                 if (!worldMatrixBlock) {
                 if (!worldMatrixBlock) {
                     worldMatrixBlock = new InputBlock("World");
                     worldMatrixBlock = new InputBlock("World");
@@ -411,15 +420,15 @@ export class BlockTools {
                 worldMatrixBlock.connectTo(transformBlock);
                 worldMatrixBlock.connectTo(transformBlock);
 
 
                 return transformBlock;
                 return transformBlock;
-            }     
+            }
             case "WorldTangentBlock": {
             case "WorldTangentBlock": {
-                let worldTangentBlock = nodeMaterial.getInputBlockByPredicate(b => b.isAttribute && b.name === "tangent");                
+                let worldTangentBlock = nodeMaterial.getInputBlockByPredicate((b) => b.isAttribute && b.name === "tangent");
                 if (!worldTangentBlock) {
                 if (!worldTangentBlock) {
                     worldTangentBlock = new InputBlock("tangent");
                     worldTangentBlock = new InputBlock("tangent");
                     worldTangentBlock.setAsAttribute("tangent");
                     worldTangentBlock.setAsAttribute("tangent");
                 }
                 }
 
 
-                let worldMatrixBlock = nodeMaterial.getInputBlockByPredicate(b => b.isSystemValue && b.systemValue === NodeMaterialSystemValues.World);  
+                let worldMatrixBlock = nodeMaterial.getInputBlockByPredicate((b) => b.isSystemValue && b.systemValue === NodeMaterialSystemValues.World);
 
 
                 if (!worldMatrixBlock) {
                 if (!worldMatrixBlock) {
                     worldMatrixBlock = new InputBlock("World");
                     worldMatrixBlock = new InputBlock("World");
@@ -431,7 +440,25 @@ export class BlockTools {
                 worldMatrixBlock.connectTo(transformBlock);
                 worldMatrixBlock.connectTo(transformBlock);
 
 
                 return transformBlock;
                 return transformBlock;
-            }              
+            }
+            case "PBRMetallicRoughnessBlock":
+                return new PBRMetallicRoughnessBlock("PBRMetallicRoughness");
+            case "SheenBlock":
+                return new SheenBlock("Sheen");
+            case "AmbientOcclusionBlock":
+                return new AmbientOcclusionBlock("AmbientOcclusion");
+            case "ReflectivityBlock":
+                return new ReflectivityBlock("Reflectivity");
+            case "AnisotropyBlock":
+                return new AnisotropyBlock("Anisotropy");
+            case "ReflectionBlock":
+                return new ReflectionBlock("Reflection");
+            case "ClearCoatBlock":
+                return new ClearCoatBlock("ClearCoat");
+            case "RefractionBlock":
+                return new RefractionBlock("Refraction");
+            case "SubSurfaceBlock":
+                return new SubSurfaceBlock("SubSurface");
         }
         }
 
 
         return null;
         return null;
@@ -441,21 +468,21 @@ export class BlockTools {
         let color = "#880000";
         let color = "#880000";
         switch (type) {
         switch (type) {
             case NodeMaterialBlockConnectionPointTypes.Float:
             case NodeMaterialBlockConnectionPointTypes.Float:
-				color = "#cb9e27";
+                color = "#cb9e27";
                 break;
                 break;
-            case NodeMaterialBlockConnectionPointTypes.Vector2:                
-				color = "#16bcb1";
+            case NodeMaterialBlockConnectionPointTypes.Vector2:
+                color = "#16bcb1";
                 break;
                 break;
-            case NodeMaterialBlockConnectionPointTypes.Vector3:                
-            case NodeMaterialBlockConnectionPointTypes.Color3:                
+            case NodeMaterialBlockConnectionPointTypes.Vector3:
+            case NodeMaterialBlockConnectionPointTypes.Color3:
                 color = "#b786cb";
                 color = "#b786cb";
                 break;
                 break;
-            case NodeMaterialBlockConnectionPointTypes.Vector4:                
-            case NodeMaterialBlockConnectionPointTypes.Color4:                
-				color = "#be5126";
+            case NodeMaterialBlockConnectionPointTypes.Vector4:
+            case NodeMaterialBlockConnectionPointTypes.Color4:
+                color = "#be5126";
                 break;
                 break;
-            case NodeMaterialBlockConnectionPointTypes.Matrix:                
-				color = "#591990";
+            case NodeMaterialBlockConnectionPointTypes.Matrix:
+                color = "#591990";
                 break;
                 break;
         }
         }
 
 

+ 23 - 13
nodeEditor/src/components/nodeList/nodeListComponent.tsx

@@ -12,7 +12,7 @@ interface INodeListComponentProps {
 
 
 export class NodeListComponent extends React.Component<INodeListComponentProps, {filter: string}> {
 export class NodeListComponent extends React.Component<INodeListComponentProps, {filter: string}> {
 
 
-    private static _Tooltips:{[key: string]: string} = {
+    private static _Tooltips: {[key: string]: string} = {
         "BonesBlock": "Provides a world matrix for each vertex, based on skeletal (bone/joint) animation",
         "BonesBlock": "Provides a world matrix for each vertex, based on skeletal (bone/joint) animation",
         "MorphTargetsBlock": "Provides the final positions, normals, tangents, and uvs based on morph targets in a mesh",
         "MorphTargetsBlock": "Provides the final positions, normals, tangents, and uvs based on morph targets in a mesh",
         "AddBlock": "Adds the left and right inputs of the same type together",
         "AddBlock": "Adds the left and right inputs of the same type together",
@@ -79,7 +79,7 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
         "CameraPositionBlock": "Outputs a Vector3 position of the active scene camera",
         "CameraPositionBlock": "Outputs a Vector3 position of the active scene camera",
         "FogBlock": "Applies fog to the scene with an increasing opacity based on distance from the camera",
         "FogBlock": "Applies fog to the scene with an increasing opacity based on distance from the camera",
         "FogColorBlock": "The system value for fog color pulled from the scene",
         "FogColorBlock": "The system value for fog color pulled from the scene",
-        "ImageProcessingBlock": "Provides access to all of the Babylon image processing properties",        
+        "ImageProcessingBlock": "Provides access to all of the Babylon image processing properties",
         "LightBlock": "Outputs diffuse and specular contributions from one or more scene lights",
         "LightBlock": "Outputs diffuse and specular contributions from one or more scene lights",
         "LightInformationBlock": "Provides the direction, color and intensity of a selected light based on its world position",
         "LightInformationBlock": "Provides the direction, color and intensity of a selected light based on its world position",
         "ReflectionTextureBlock": "Creates a reflection from the input texture",
         "ReflectionTextureBlock": "Creates a reflection from the input texture",
@@ -115,9 +115,18 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
         "SimplexPerlin3DBlock": "Creates a type of gradient noise with few directional artifacts.",
         "SimplexPerlin3DBlock": "Creates a type of gradient noise with few directional artifacts.",
         "WorleyNoise3DBlock": "Creates a random pattern resembling cells.",
         "WorleyNoise3DBlock": "Creates a random pattern resembling cells.",
         "ReflectBlock": "Outputs the direction of the input vector reflected across the surface normal.",
         "ReflectBlock": "Outputs the direction of the input vector reflected across the surface normal.",
-        "RefractBlock": "Outputs a direction simulating a deflection of the input vector.", 
-        "Rotate2dBlock": "Rotates UV coordinates around the W axis."
-    }
+        "RefractBlock": "Outputs a direction simulating a deflection of the input vector.",
+        "Rotate2dBlock": "Rotates UV coordinates around the W axis.",
+        "PBRMetallicRoughnessBlock": "PBR metallic/roughness material",
+        "SheenBlock": "PBR Sheen block",
+        "AmbientOcclusionBlock": "PBR Ambient occlusion block",
+        "ReflectivityBlock": "PBR Reflectivity block",
+        "AnisotropyBlock": "PBR Anisotropy block",
+        "ReflectionBlock": "PBR Reflection block",
+        "ClearCoatBlock": "PBR ClearCoat block",
+        "RefractionBlock": "PBR Refraction block",
+        "SubSurfaceBlock": "PBR SubSurface block",
+    };
 
 
     constructor(props: INodeListComponentProps) {
     constructor(props: INodeListComponentProps) {
         super(props);
         super(props);
@@ -132,33 +141,34 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
     render() {
     render() {
         // Block types used to create the menu from
         // Block types used to create the menu from
         const allBlocks = {
         const allBlocks = {
-            
+
             Animation: ["BonesBlock", "MorphTargetsBlock"],
             Animation: ["BonesBlock", "MorphTargetsBlock"],
             Color_Management: ["ReplaceColorBlock", "PosterizeBlock", "GradientBlock", "DesaturateBlock"],
             Color_Management: ["ReplaceColorBlock", "PosterizeBlock", "GradientBlock", "DesaturateBlock"],
             Conversion_Blocks: ["ColorMergerBlock", "ColorSplitterBlock", "VectorMergerBlock", "VectorSplitterBlock"],
             Conversion_Blocks: ["ColorMergerBlock", "ColorSplitterBlock", "VectorMergerBlock", "VectorSplitterBlock"],
             Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "TextureBlock", "ReflectionTextureBlock", "TimeBlock", "DeltaTimeBlock"],
             Inputs: ["Float", "Vector2", "Vector3", "Vector4", "Color3", "Color4", "TextureBlock", "ReflectionTextureBlock", "TimeBlock", "DeltaTimeBlock"],
             Interpolation: ["LerpBlock", "StepBlock", "SmoothStepBlock", "NLerpBlock"],
             Interpolation: ["LerpBlock", "StepBlock", "SmoothStepBlock", "NLerpBlock"],
-            Math__Standard: ["AddBlock", "DivideBlock", "MaxBlock", "MinBlock", "MultiplyBlock", "NegateBlock", "OneMinusBlock", "ReciprocalBlock", "ScaleBlock", "SignBlock", "SqrtBlock", "SubtractBlock"], 
+            Math__Standard: ["AddBlock", "DivideBlock", "MaxBlock", "MinBlock", "MultiplyBlock", "NegateBlock", "OneMinusBlock", "ReciprocalBlock", "ScaleBlock", "SignBlock", "SqrtBlock", "SubtractBlock"],
             Math__Scientific: ["AbsBlock", "ArcCosBlock", "ArcSinBlock", "ArcTanBlock", "ArcTan2Block", "CosBlock", "DegreesToRadiansBlock", "ExpBlock", "Exp2Block", "FractBlock", "LogBlock", "PowBlock", "RadiansToDegreesBlock", "SawToothWaveBlock", "SinBlock", "SquareWaveBlock", "TanBlock", "TriangleWaveBlock"],
             Math__Scientific: ["AbsBlock", "ArcCosBlock", "ArcSinBlock", "ArcTanBlock", "ArcTan2Block", "CosBlock", "DegreesToRadiansBlock", "ExpBlock", "Exp2Block", "FractBlock", "LogBlock", "PowBlock", "RadiansToDegreesBlock", "SawToothWaveBlock", "SinBlock", "SquareWaveBlock", "TanBlock", "TriangleWaveBlock"],
             Math__Vector: ["CrossBlock", "DerivativeBlock", "DistanceBlock", "DotBlock", "FresnelBlock", "LengthBlock", "ReflectBlock", "RefractBlock", "Rotate2dBlock", "TransformBlock", ],
             Math__Vector: ["CrossBlock", "DerivativeBlock", "DistanceBlock", "DotBlock", "FresnelBlock", "LengthBlock", "ReflectBlock", "RefractBlock", "Rotate2dBlock", "TransformBlock", ],
             Matrices: ["Matrix", "WorldMatrixBlock", "WorldViewMatrixBlock", "WorldViewProjectionMatrixBlock", "ViewMatrixBlock", "ViewProjectionMatrixBlock", "ProjectionMatrixBlock"],
             Matrices: ["Matrix", "WorldMatrixBlock", "WorldViewMatrixBlock", "WorldViewProjectionMatrixBlock", "ViewMatrixBlock", "ViewProjectionMatrixBlock", "ProjectionMatrixBlock"],
-            Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "PerturbNormalBlock", "NormalBlendBlock" , "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "WorldTangentBlock", "FrontFacingBlock"], 
+            Mesh: ["InstancesBlock", "PositionBlock", "UVBlock", "ColorBlock", "NormalBlock", "PerturbNormalBlock", "NormalBlendBlock" , "TangentBlock", "MatrixIndicesBlock", "MatrixWeightsBlock", "WorldPositionBlock", "WorldNormalBlock", "WorldTangentBlock", "FrontFacingBlock"],
             Noises: ["RandomNumberBlock", "SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Noises: ["RandomNumberBlock", "SimplexPerlin3DBlock", "WorleyNoise3DBlock"],
             Output_Nodes: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
             Output_Nodes: ["VertexOutputBlock", "FragmentOutputBlock", "DiscardBlock"],
+            PBR: ["PBRMetallicRoughnessBlock", "AmbientOcclusionBlock", "AnisotropyBlock", "ClearCoatBlock", "ReflectionBlock", "ReflectivityBlock", "RefractionBlock", "SheenBlock", "SubSurfaceBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
             Range: ["ClampBlock", "RemapBlock", "NormalizeBlock"],
             Round: ["RoundBlock", "CeilingBlock", "FloorBlock"],
             Round: ["RoundBlock", "CeilingBlock", "FloorBlock"],
             Scene: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ViewDirectionBlock"],
             Scene: ["FogBlock", "CameraPositionBlock", "FogColorBlock", "ImageProcessingBlock", "LightBlock", "LightInformationBlock", "ViewDirectionBlock"],
-        }
+        };
 
 
         // Create node menu
         // Create node menu
-        var blockMenu = []
+        var blockMenu = [];
         for (var key in allBlocks) {
         for (var key in allBlocks) {
             var blockList = (allBlocks as any)[key].filter((b: string) => !this.state.filter || b.toLowerCase().indexOf(this.state.filter.toLowerCase()) !== -1)
             var blockList = (allBlocks as any)[key].filter((b: string) => !this.state.filter || b.toLowerCase().indexOf(this.state.filter.toLowerCase()) !== -1)
             .sort((a: string, b: string) => a.localeCompare(b))
             .sort((a: string, b: string) => a.localeCompare(b))
             .map((block: any, i: number) => {
             .map((block: any, i: number) => {
                 let tooltip = NodeListComponent._Tooltips[block] || "";
                 let tooltip = NodeListComponent._Tooltips[block] || "";
 
 
-                return <DraggableLineComponent key={block} data={block} tooltip={tooltip}/>
+                return <DraggableLineComponent key={block} data={block} tooltip={tooltip}/>;
             });
             });
 
 
             if (blockList.length) {
             if (blockList.length) {
@@ -175,9 +185,9 @@ export class NodeListComponent extends React.Component<INodeListComponentProps,
                 <div className="panes">
                 <div className="panes">
                     <div className="pane">
                     <div className="pane">
                         <div className="filter">
                         <div className="filter">
-                            <input type="text" placeholder="Filter" 
+                            <input type="text" placeholder="Filter"
                                 onFocus={() => this.props.globalState.blockKeyboardEvents = true}
                                 onFocus={() => this.props.globalState.blockKeyboardEvents = true}
-                                onBlur={evt => {
+                                onBlur={(evt) => {
                                     this.props.globalState.blockKeyboardEvents = false;
                                     this.props.globalState.blockKeyboardEvents = false;
                                 }}
                                 }}
                                 onChange={(evt) => this.filterContent(evt.target.value)} />
                                 onChange={(evt) => this.filterContent(evt.target.value)} />

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

@@ -486,6 +486,22 @@
                 background: rgb(22, 73, 117);
                 background: rgb(22, 73, 117);
             }
             }
 
 
+            .cbx:checked ~ label.disabled { 
+                background: rgb(22, 73, 117);
+                cursor: pointer;
+            }
+
+            .cbx:checked ~ label.disabled:after {
+                left: 20px;
+                background: rgb(85, 85, 85);
+                cursor: pointer;
+            }
+
+            .cbx ~ label.disabled {
+                background: rgb(85, 85, 85);
+                cursor: pointer;
+            }
+
             .hidden { 
             .hidden { 
                 display: none; 
                 display: none; 
             }               
             }               

+ 24 - 7
nodeEditor/src/components/propertyTab/propertyTabComponent.tsx

@@ -17,6 +17,7 @@ import { TextLineComponent } from '../../sharedComponents/textLineComponent';
 import { Engine } from 'babylonjs/Engines/engine';
 import { Engine } from 'babylonjs/Engines/engine';
 import { FramePropertyTabComponent } from '../../diagram/properties/framePropertyComponent';
 import { FramePropertyTabComponent } from '../../diagram/properties/framePropertyComponent';
 import { FrameNodePortPropertyTabComponent } from '../../diagram/properties/frameNodePortPropertyComponent';
 import { FrameNodePortPropertyTabComponent } from '../../diagram/properties/frameNodePortPropertyComponent';
+import { NodePortPropertyTabComponent } from '../../diagram/properties/nodePortPropertyComponent';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes';
 import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes';
 import { Color3LineComponent } from '../../sharedComponents/color3LineComponent';
 import { Color3LineComponent } from '../../sharedComponents/color3LineComponent';
@@ -28,6 +29,7 @@ import { Vector4LineComponent } from '../../sharedComponents/vector4LineComponen
 import { Observer } from 'babylonjs/Misc/observable';
 import { Observer } from 'babylonjs/Misc/observable';
 import { NodeMaterial } from 'babylonjs/Materials/Node/nodeMaterial';
 import { NodeMaterial } from 'babylonjs/Materials/Node/nodeMaterial';
 import { FrameNodePort } from '../../diagram/frameNodePort';
 import { FrameNodePort } from '../../diagram/frameNodePort';
+import { NodePort } from '../../diagram/nodePort';
 import { isFramePortData } from '../../diagram/graphCanvas';
 import { isFramePortData } from '../../diagram/graphCanvas';
 require("./propertyTab.scss");
 require("./propertyTab.scss");
 
 
@@ -35,25 +37,34 @@ interface IPropertyTabComponentProps {
     globalState: GlobalState;
     globalState: GlobalState;
 }
 }
 
 
-export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, { currentNode: Nullable<GraphNode>, currentFrame: Nullable<GraphFrame>, currentFrameNodePort: Nullable<FrameNodePort> }> {
+interface IPropertyTabComponentState { 
+    currentNode: Nullable<GraphNode>, 
+    currentFrame: Nullable<GraphFrame>, 
+    currentFrameNodePort: Nullable<FrameNodePort>,
+    currentNodePort: Nullable<NodePort>
+ }
+
+export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, IPropertyTabComponentState> {
     private _onBuiltObserver: Nullable<Observer<void>>;
     private _onBuiltObserver: Nullable<Observer<void>>;
 
 
     constructor(props: IPropertyTabComponentProps) {
     constructor(props: IPropertyTabComponentProps) {
         super(props)
         super(props)
 
 
-        this.state = { currentNode: null, currentFrame: null, currentFrameNodePort: null };
+        this.state = { currentNode: null, currentFrame: null, currentFrameNodePort: null, currentNodePort: null };
     }
     }
 
 
     componentDidMount() {
     componentDidMount() {
         this.props.globalState.onSelectionChangedObservable.add(selection => {
         this.props.globalState.onSelectionChangedObservable.add(selection => {
             if (selection instanceof GraphNode) {
             if (selection instanceof GraphNode) {
-                this.setState({ currentNode: selection, currentFrame: null, currentFrameNodePort: null });
+                this.setState({ currentNode: selection, currentFrame: null, currentFrameNodePort: null, currentNodePort: null });
             } else if (selection instanceof GraphFrame) {
             } else if (selection instanceof GraphFrame) {
-                this.setState({ currentNode: null, currentFrame: selection, currentFrameNodePort: null });
+                this.setState({ currentNode: null, currentFrame: selection, currentFrameNodePort: null, currentNodePort: null });
             } else if(isFramePortData(selection)) {
             } else if(isFramePortData(selection)) {
-                this.setState({ currentNode: null, currentFrame: selection.frame, currentFrameNodePort: selection.port });
+                this.setState({ currentNode: null, currentFrame: selection.frame, currentFrameNodePort: selection.port, currentNodePort: null });
+            } else if (selection instanceof NodePort && selection.hasLabel()) {
+                this.setState({ currentNode: null, currentFrame: null, currentFrameNodePort: null, currentNodePort: selection})
             } else {
             } else {
-                this.setState({ currentNode: null, currentFrame: null, currentFrameNodePort: null });
+                this.setState({ currentNode: null, currentFrame: null, currentFrameNodePort: null, currentNodePort: null });
             }
             }
         });
         });
 
 
@@ -240,7 +251,7 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
                             NODE MATERIAL EDITOR
                             NODE MATERIAL EDITOR
                         </div>
                         </div>
                     </div>
                     </div>
-                    {this.state.currentNode.renderProperties()}
+                    {this.state.currentNode?.renderProperties() || this.state.currentNodePort?.node.renderProperties()}
                 </div>
                 </div>
             );
             );
         }
         }
@@ -251,6 +262,12 @@ export class PropertyTabComponent extends React.Component<IPropertyTabComponentP
             );
             );
         }
         }
 
 
+        if (this.state.currentNodePort) {
+            return (
+                <NodePortPropertyTabComponent globalState={this.props.globalState} nodePort={this.state.currentNodePort}/>
+            );
+        }
+
         if (this.state.currentFrame) {
         if (this.state.currentFrame) {
             return (
             return (
                 <FramePropertyTabComponent globalState={this.props.globalState} frame={this.state.currentFrame}/>
                 <FramePropertyTabComponent globalState={this.props.globalState} frame={this.state.currentFrame}/>

+ 2 - 1
nodeEditor/src/diagram/display/textureDisplayManager.ts

@@ -1,6 +1,7 @@
 import { IDisplayManager } from './displayManager';
 import { IDisplayManager } from './displayManager';
 import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
 import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
 import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/textureBlock';
 import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/textureBlock';
+import { RefractionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/refractionBlock';
 import { ReflectionTextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/reflectionTextureBlock';
 import { ReflectionTextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/reflectionTextureBlock';
 import { TextureLineComponent } from '../../sharedComponents/textureLineComponent';
 import { TextureLineComponent } from '../../sharedComponents/textureLineComponent';
 
 
@@ -25,7 +26,7 @@ export class TextureDisplayManager implements IDisplayManager {
     }
     }
 
 
     public updatePreviewContent(block: NodeMaterialBlock, contentArea: HTMLDivElement): void {       
     public updatePreviewContent(block: NodeMaterialBlock, contentArea: HTMLDivElement): void {       
-        const textureBlock = block as TextureBlock | ReflectionTextureBlock;
+        const textureBlock = block as TextureBlock | ReflectionTextureBlock | RefractionBlock;
 
 
         if (!this._previewCanvas) {
         if (!this._previewCanvas) {
             contentArea.classList.add("texture-block");
             contentArea.classList.add("texture-block");

+ 2 - 0
nodeEditor/src/diagram/displayLedger.ts

@@ -20,4 +20,6 @@ DisplayLedger.RegisteredControls["RemapBlock"] = RemapDisplayManager;
 DisplayLedger.RegisteredControls["TrigonometryBlock"] = TrigonometryDisplayManager;
 DisplayLedger.RegisteredControls["TrigonometryBlock"] = TrigonometryDisplayManager;
 DisplayLedger.RegisteredControls["TextureBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["TextureBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["ReflectionTextureBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["ReflectionTextureBlock"] = TextureDisplayManager;
+DisplayLedger.RegisteredControls["ReflectionBlock"] = TextureDisplayManager;
+DisplayLedger.RegisteredControls["RefractionBlock"] = TextureDisplayManager;
 DisplayLedger.RegisteredControls["DiscardBlock"] = DiscardDisplayManager;
 DisplayLedger.RegisteredControls["DiscardBlock"] = DiscardDisplayManager;

+ 5 - 12
nodeEditor/src/diagram/frameNodePort.ts

@@ -9,7 +9,6 @@ import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMateri
 import { FramePortData, isFramePortData } from './graphCanvas';
 import { FramePortData, isFramePortData } from './graphCanvas';
 
 
 export class FrameNodePort extends NodePort {
 export class FrameNodePort extends NodePort {
-    private _portLabel: Element;
     private _parentFrameId: number;
     private _parentFrameId: number;
     private _isInput: boolean;
     private _isInput: boolean;
     private _framePortPosition: FramePortPosition
     private _framePortPosition: FramePortPosition
@@ -28,25 +27,16 @@ export class FrameNodePort extends NodePort {
         return this._isInput;
         return this._isInput;
     }
     }
 
 
-    public get portLabel() {
-        return this._portLabel.innerHTML;
-    }
-
     public get framePortId() {
     public get framePortId() {
         return this._framePortId;
         return this._framePortId;
     }
     }
 
 
-    public set portLabel(newLabel: string) {
-        this._portLabel.innerHTML = newLabel;
-    }
-
     public get framePortPosition() {
     public get framePortPosition() {
         return this._framePortPosition;
         return this._framePortPosition;
     }
     }
 
 
     public set framePortPosition(position: FramePortPosition) {
     public set framePortPosition(position: FramePortPosition) {
         this._framePortPosition = position;
         this._framePortPosition = position;
-        console.log(this.onFramePortPositionChangedObservable.observers);
         this.onFramePortPositionChangedObservable.notifyObservers(this);
         this.onFramePortPositionChangedObservable.notifyObservers(this);
     }
     }
 
 
@@ -54,7 +44,6 @@ export class FrameNodePort extends NodePort {
         super(portContainer, connectionPoint,node, globalState);
         super(portContainer, connectionPoint,node, globalState);
 
 
         this._parentFrameId = parentFrameId;
         this._parentFrameId = parentFrameId;
-        this._portLabel = portContainer.children[0];
         this._isInput = isInput;
         this._isInput = isInput;
         this._framePortId = framePortId;
         this._framePortId = framePortId;
 
 
@@ -83,7 +72,11 @@ export class FrameNodePort extends NodePort {
         if (!displayManager || displayManager.shouldDisplayPortLabels(block)) {
         if (!displayManager || displayManager.shouldDisplayPortLabels(block)) {
             let portLabel = root.ownerDocument!.createElement("div");
             let portLabel = root.ownerDocument!.createElement("div");
             portLabel.classList.add("port-label");
             portLabel.classList.add("port-label");
-            portLabel.innerHTML = connectionPoint.name;        
+            let portName = connectionPoint.displayName || connectionPoint.name;
+            if (connectionPoint.ownerBlock.isInput) {
+                portName = node.name;
+            }
+            portLabel.innerHTML = portName;       
             portContainer.appendChild(portLabel);
             portContainer.appendChild(portLabel);
         }
         }
 
 

+ 15 - 2
nodeEditor/src/diagram/graphCanvas.tsx

@@ -198,6 +198,8 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
                     } else {                    
                     } else {                    
                         this._selectedNodes = [selection];
                         this._selectedNodes = [selection];
                     }
                     }
+                } else if(selection instanceof NodePort && !selection.hasLabel()){ // if node port is uneditable, select graphNode instead
+                    props.globalState.onSelectionChangedObservable.notifyObservers(selection.node)
                 } else if(selection instanceof NodePort){
                 } else if(selection instanceof NodePort){
                     this._selectedNodes = [];
                     this._selectedNodes = [];
                     this._selectedFrame = null;
                     this._selectedFrame = null;
@@ -625,6 +627,8 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
                         }
                         }
                         this.props.globalState.onSelectionChangedObservable.notifyObservers(data);
                         this.props.globalState.onSelectionChangedObservable.notifyObservers(data);
                     }
                     }
+                } else if(this._candidateLink.portA instanceof NodePort){
+                    this.props.globalState.onSelectionChangedObservable.notifyObservers(this._candidateLink.portA );
                 }
                 }
             }
             }
             this._candidateLink.dispose();
             this._candidateLink.dispose();
@@ -735,9 +739,15 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
             }
             }
 
 
             // No destination so let's spin a new input block
             // No destination so let's spin a new input block
-            let inputBlock = new InputBlock(NodeMaterialBlockConnectionPointTypes[this._candidateLink!.portA.connectionPoint.type], undefined, this._candidateLink!.portA.connectionPoint.type);
+            let pointName = "output", inputBlock;
+            let customInputBlock = this._candidateLink!.portA.connectionPoint.createCustomInputBlock();
+            if (!customInputBlock) {
+                inputBlock = new InputBlock(NodeMaterialBlockConnectionPointTypes[this._candidateLink!.portA.connectionPoint.type], undefined, this._candidateLink!.portA.connectionPoint.type);
+            } else {
+                [inputBlock, pointName] = customInputBlock;
+            }
             this.props.globalState.nodeMaterial.attachedBlocks.push(inputBlock);
             this.props.globalState.nodeMaterial.attachedBlocks.push(inputBlock);
-            pointA = inputBlock.output;
+            pointA = (inputBlock as any)[pointName];
             nodeA = this.appendBlock(inputBlock);
             nodeA = this.appendBlock(inputBlock);
             
             
             nodeA.x = this._dropPointX - 200;
             nodeA.x = this._dropPointX - 200;
@@ -773,6 +783,9 @@ export class GraphCanvasComponent extends React.Component<IGraphCanvasComponentP
         // Check compatibility
         // Check compatibility
         let isFragmentOutput = pointB.ownerBlock.getClassName() === "FragmentOutputBlock";
         let isFragmentOutput = pointB.ownerBlock.getClassName() === "FragmentOutputBlock";
         let compatibilityState = pointA.checkCompatibilityState(pointB);
         let compatibilityState = pointA.checkCompatibilityState(pointB);
+        if ((pointA.needDualDirectionValidation || pointB.needDualDirectionValidation) && compatibilityState === NodeMaterialConnectionPointCompatibilityStates.Compatible && !(pointA instanceof InputBlock)) {
+            compatibilityState = pointB.checkCompatibilityState(pointA);
+        }
         if (compatibilityState === NodeMaterialConnectionPointCompatibilityStates.Compatible) {
         if (compatibilityState === NodeMaterialConnectionPointCompatibilityStates.Compatible) {
             if (isFragmentOutput) {
             if (isFragmentOutput) {
                 let fragmentBlock = pointB.ownerBlock as FragmentOutputBlock;
                 let fragmentBlock = pointB.ownerBlock as FragmentOutputBlock;

+ 140 - 78
nodeEditor/src/diagram/graphFrame.ts

@@ -53,6 +53,8 @@ export class GraphFrame {
     private _mouseStartPointY: Nullable<number> = null;
     private _mouseStartPointY: Nullable<number> = null;
     private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphFrame | GraphNode | NodeLink | NodePort | FramePortData>>>;
     private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphFrame | GraphNode | NodeLink | NodePort | FramePortData>>>;
     private _onGraphNodeRemovalObserver: Nullable<Observer<GraphNode>>; 
     private _onGraphNodeRemovalObserver: Nullable<Observer<GraphNode>>; 
+    private _onExposePortOnFrameObserver: Nullable<Observer<GraphNode>>;
+    private _onNodeLinkDisposedObservers: Nullable<Observer<NodeLink>>[] = [];
     private _isCollapsed = false;
     private _isCollapsed = false;
     private _frameInPorts: FrameNodePort[] = [];
     private _frameInPorts: FrameNodePort[] = [];
     private _frameOutPorts: FrameNodePort[] = [];
     private _frameOutPorts: FrameNodePort[] = [];
@@ -87,101 +89,148 @@ export class GraphFrame {
         this._controlledPorts.push(port);
         this._controlledPorts.push(port);
     }
     }
 
 
-    public set isCollapsed(value: boolean) {
-        if (this._isCollapsed === value) {
-            return;
+    // Mark ports with FramePortPosition for re-arrangement support
+    private _markFramePortPositions() {
+        // mark FrameInPorts 
+         if(this._frameInPorts.length == 2){
+            this._frameInPorts[0].framePortPosition = FramePortPosition.Top;
+            this._frameInPorts[1].framePortPosition = FramePortPosition.Bottom;
+        } else {
+            for(let i = 0; i < this._frameInPorts.length; i++) {
+                const port = this._frameInPorts[i];
+                if(i === 0){
+                    port.framePortPosition = FramePortPosition.Top;
+                } else if(i === this._frameInPorts.length -1){
+                    port.framePortPosition = FramePortPosition.Bottom;
+                } else {
+                    port.framePortPosition = FramePortPosition.Middle;
+                }
+            }
         }
         }
 
 
-        this._isCollapsed = value;
-        this._ownerCanvas._frameIsMoving = true;
-
-        // Need to delegate the outside ports to the frame
-        if (value) {
-            this.element.classList.add("collapsed");
-
-            this._moveFrame((this.width - this.CollapsedWidth) / 2, 0);
-
-            for (var node of this._nodes) {
-                node.isVisible = false;
-                for (var port of node.outputPorts) { // Output
-                    if (port.connectionPoint.hasEndpoints) {
-                        let portAdded = false;
+        // mark FrameOutPorts
+        if(this._frameOutPorts.length == 2){
+            this._frameOutPorts[0].framePortPosition = FramePortPosition.Top;
+            this._frameOutPorts[1].framePortPosition = FramePortPosition.Bottom;
+        } else {
+            for(let i = 0; i < this._frameOutPorts.length; i++) {
+                const port = this._frameOutPorts[i];
+                if(i === 0){
+                    port.framePortPosition = FramePortPosition.Top
+                } else if(i === this._frameInPorts.length -1){
+                    port.framePortPosition = FramePortPosition.Bottom
+                } else {
+                    port.framePortPosition = FramePortPosition.Middle
+                }
+            }
+        }
+    }
 
 
-                        for (var link of node.links) {
-                            if (link.portA === port && this.nodes.indexOf(link.nodeB!) === -1) {
-                                let localPort: FrameNodePort;
+    private _createFramePorts() {
+        for (var node of this._nodes) {
+            node.isVisible = false;
+            for (var port of node.outputPorts) { // Output
+                if (port.connectionPoint.hasEndpoints) {
+                    let portAdded = false;
 
 
-                                if (!portAdded) {
-                                    portAdded = true;
-                                    localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++, this.id);
-                                    this._frameOutPorts.push(localPort);
+                    for (var link of node.links) {
+                        if (link.portA === port && this.nodes.indexOf(link.nodeB!) === -1 || (link.portA === port && port.exposedOnFrame)) {
+                            let localPort: FrameNodePort;
 
 
-                                    link.isVisible = true;
+                            if (!portAdded) {
+                                portAdded = true;
+                                localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, link.nodeB!, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++, this.id);
+                                this._frameOutPorts.push(localPort);
 
 
-                                } else {
-                                    localPort = this.ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
-                                }
+                                link.isVisible = true;
 
 
-                                port.delegatedPort = localPort;
-                                this._controlledPorts.push(port);
-                            }
-                        }
-                    } else {
-                        let localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++, this.id);
-                        this._frameOutPorts.push(localPort);
-                        port.delegatedPort = localPort;
-                        this._controlledPorts.push(port);
+                                const onLinkDisposedObserver = link.onDisposedObservable.add((nodeLink: NodeLink) => {
+                                    this._redrawFramePorts();
+                                });
 
 
-                    }
-                }
+                                this._onNodeLinkDisposedObservers.push(onLinkDisposedObserver); 
 
 
-                for (var port of node.inputPorts) { // Input
-                    if (port.connectionPoint.isConnected) {
-                        for (var link of node.links) {
-                            if (link.portB === port && this.nodes.indexOf(link.nodeA) === -1) {
-                                this._createInputPort(port, node);
+                            } else if (this.nodes.indexOf(link.nodeB!) === -1) {
                                 link.isVisible = true;
                                 link.isVisible = true;
+                                localPort = this.ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
+                            } else {
+                                localPort = this.ports.filter(p => p.connectionPoint === port.connectionPoint)[0];
                             }
                             }
+
+                            port.delegatedPort = localPort;
+                            this._controlledPorts.push(port);
                         }
                         }
-                    } else {
-                        this._createInputPort(port, node);
                     }
                     }
+                } else if(port.exposedOnFrame) {
+                    let localPort = FrameNodePort.CreateFrameNodePortElement(port.connectionPoint, node, this._outputPortContainer, null, this._ownerCanvas.globalState, false, GraphFrame._FramePortCounter++, this.id);
+                    this._frameOutPorts.push(localPort);
+                    port.delegatedPort = localPort;
+                    this._controlledPorts.push(port);
                 }
                 }
             }
             }
 
 
-            // mark FrameInPorts with position
-            if(this._frameInPorts.length == 2){
-                this._frameInPorts[0].framePortPosition = FramePortPosition.Top;
-                this._frameInPorts[1].framePortPosition = FramePortPosition.Bottom;
-            } else {
-                for(let i = 0; i < this._frameInPorts.length; i++) {
-                    const port = this._frameInPorts[i];
-                    if(i === 0){
-                        port.framePortPosition = FramePortPosition.Top;
-                    } else if(i === this._frameInPorts.length -1){
-                        port.framePortPosition = FramePortPosition.Bottom;
-                    } else {
-                        port.framePortPosition = FramePortPosition.Middle;
+            for (var port of node.inputPorts) { // Input
+                if (port.connectionPoint.isConnected) {
+                    for (var link of node.links) {
+                        if (link.portB === port && this.nodes.indexOf(link.nodeA) === -1) {
+                            this._createInputPort(port, node);
+                            link.isVisible = true;
+                            
+                            const onLinkDisposedObserver = link.onDisposedObservable.add((nodeLink: NodeLink) => {
+                                this._redrawFramePorts();
+                            });
+
+                            this._onNodeLinkDisposedObservers.push(onLinkDisposedObserver);
+                        }
                     }
                     }
+                } else if(port.exposedOnFrame) {
+                    this._createInputPort(port, node);
                 }
                 }
             }
             }
+        }
+    }
+    
+    private _redrawFramePorts() {
+        if(!this.isCollapsed) {
+            return;
+        }
 
 
-            // mark FrameOutPorts with position
-            if(this._frameOutPorts.length == 2){
-                this._frameOutPorts[0].framePortPosition = FramePortPosition.Top;
-                this._frameOutPorts[1].framePortPosition = FramePortPosition.Bottom;
-            } else {
-                for(let i = 0; i < this._frameOutPorts.length; i++) {
-                    const port = this._frameOutPorts[i];
-                    if(i === 0){
-                        port.framePortPosition = FramePortPosition.Top
-                    } else if(i === this._frameInPorts.length -1){
-                        port.framePortPosition = FramePortPosition.Bottom
-                    } else {
-                        port.framePortPosition = FramePortPosition.Middle
-                    }
-                }
-            }
+        this._outputPortContainer.innerHTML = "";
+        this._inputPortContainer.innerHTML = "";
+        this.ports.forEach((framePort:FrameNodePort) => {
+            framePort.dispose();
+        });
+
+        this._controlledPorts.forEach(port => {
+            port.delegatedPort = null;
+            port.refresh();
+        })
+
+        this._frameInPorts = [];
+        this._frameOutPorts = [];
+        this._controlledPorts = [];
+
+        this._createFramePorts();
+        this.ports.forEach((framePort: FrameNodePort) => framePort.node._refreshLinks());
+    }
+
+    public set isCollapsed(value: boolean) {
+        if (this._isCollapsed === value) {
+            return;
+        }
+
+        this._isCollapsed = value;
+        this._ownerCanvas._frameIsMoving = true;
+
+        // Need to delegate the outside ports to the frame
+        if (value) {
+            this.element.classList.add("collapsed");
+
+            this._moveFrame((this.width - this.CollapsedWidth) / 2, 0);
+
+            this._createFramePorts()
+
+            this._markFramePortPositions()
 
 
         } else {
         } else {
             this.element.classList.remove("collapsed");
             this.element.classList.remove("collapsed");
@@ -204,6 +253,7 @@ export class GraphFrame {
             this._frameInPorts = [];
             this._frameInPorts = [];
             this._frameOutPorts = [];
             this._frameOutPorts = [];
             this._controlledPorts = [];
             this._controlledPorts = [];
+            this._onNodeLinkDisposedObservers = [];
 
 
             for (var node of this._nodes) {
             for (var node of this._nodes) {
                 node.isVisible = true;
                 node.isVisible = true;
@@ -225,7 +275,7 @@ export class GraphFrame {
         }
         }
 
 
         this.onExpandStateChanged.notifyObservers(this);
         this.onExpandStateChanged.notifyObservers(this);
-    }
+    }     
 
 
     public get nodes() {
     public get nodes() {
         return this._nodes;
         return this._nodes;
@@ -487,6 +537,13 @@ export class GraphFrame {
             }
             }
         });
         });
 
 
+        this._onExposePortOnFrameObserver = canvas.globalState.onExposePortOnFrameObservable.add((node: GraphNode) => {
+            if (this.nodes.indexOf(node) === -1) {
+                return;
+            }
+            this._redrawFramePorts();
+        });
+
         this._commentsElement = document.createElement('div');
         this._commentsElement = document.createElement('div');
         this._commentsElement.className = 'frame-comments';
         this._commentsElement.className = 'frame-comments';
         this._commentsElement.style.color = 'white';
         this._commentsElement.style.color = 'white';
@@ -1209,11 +1266,15 @@ export class GraphFrame {
 
 
         if (this._onSelectionChangedObserver) {
         if (this._onSelectionChangedObserver) {
             this._ownerCanvas.globalState.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
             this._ownerCanvas.globalState.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
-        }
+        };
 
 
         if(this._onGraphNodeRemovalObserver) {
         if(this._onGraphNodeRemovalObserver) {
             this._ownerCanvas.globalState.onGraphNodeRemovalObservable.remove(this._onGraphNodeRemovalObserver);
             this._ownerCanvas.globalState.onGraphNodeRemovalObservable.remove(this._onGraphNodeRemovalObserver);
-        }
+        };
+
+        if(this._onExposePortOnFrameObserver) {
+            this._ownerCanvas.globalState.onExposePortOnFrameObservable.remove(this._onExposePortOnFrameObserver);
+        };
 
 
         this.element.parentElement!.removeChild(this.element);
         this.element.parentElement!.removeChild(this.element);
 
 
@@ -1261,6 +1322,7 @@ export class GraphFrame {
 
 
                 if (node.length) {
                 if (node.length) {
                     newFrame.nodes.push(node[0]);
                     newFrame.nodes.push(node[0]);
+                    node[0].enclosingFrameId = newFrame.id;
                 }
                 }
             }
             }
         } else {
         } else {

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

@@ -6,7 +6,7 @@ import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMateri
 import { GraphCanvasComponent, FramePortData } from './graphCanvas';
 import { GraphCanvasComponent, FramePortData } from './graphCanvas';
 import { PropertyLedger } from './propertyLedger';
 import { PropertyLedger } from './propertyLedger';
 import * as React from 'react';
 import * as React from 'react';
-import { GenericPropertyTabComponent } from './properties/genericNodePropertyComponent';
+import { GenericPropertyComponent } from './properties/genericNodePropertyComponent';
 import { DisplayLedger } from './displayLedger';
 import { DisplayLedger } from './displayLedger';
 import { IDisplayManager } from './display/displayManager';
 import { IDisplayManager } from './display/displayManager';
 import { NodeLink } from './nodeLink';
 import { NodeLink } from './nodeLink';
@@ -39,6 +39,7 @@ export class GraphNode {
     private _isSelected: boolean;
     private _isSelected: boolean;
     private _displayManager: Nullable<IDisplayManager> = null;
     private _displayManager: Nullable<IDisplayManager> = null;
     private _isVisible = true;
     private _isVisible = true;
+    private _enclosingFrameId: number;
 
 
     public get isVisible() {
     public get isVisible() {
         return this._isVisible;
         return this._isVisible;
@@ -51,6 +52,7 @@ export class GraphNode {
             this._visual.classList.add("hidden");
             this._visual.classList.add("hidden");
         } else {
         } else {
             this._visual.classList.remove("hidden");
             this._visual.classList.remove("hidden");
+            this._upateNodePortNames();
         }
         }
 
 
         for (var link of this._links) {
         for (var link of this._links) {
@@ -60,6 +62,14 @@ export class GraphNode {
         this._refreshLinks();
         this._refreshLinks();
     }
     }
 
 
+    private _upateNodePortNames(){
+        for (var port of this._inputPorts.concat(this._outputPorts)) {
+            if(port.hasLabel()){
+                port.portName = port.connectionPoint.displayName || port.connectionPoint.name;
+            }
+        }
+    }
+
     public get outputPorts() {
     public get outputPorts() {
         return this._outputPorts;
         return this._outputPorts;
     }
     }
@@ -135,6 +145,14 @@ export class GraphNode {
         return this._isSelected;
         return this._isSelected;
     }
     }
 
 
+    public get enclosingFrameId() {
+        return this._enclosingFrameId;
+    }
+
+    public set enclosingFrameId(value: number) {
+        this._enclosingFrameId = value;
+    }
+
     public set isSelected(value: boolean) {
     public set isSelected(value: boolean) {
         if (this._isSelected === value) {
         if (this._isSelected === value) {
             return;            
             return;            
@@ -202,10 +220,15 @@ export class GraphNode {
         rect1.width -= 5;
         rect1.width -= 5;
         rect1.height -= 5;
         rect1.height -= 5;
 
 
-        return !(rect1.right < rect2.left || 
+        const isOverlappingFrame = !(rect1.right < rect2.left || 
             rect1.left > rect2.right || 
             rect1.left > rect2.right || 
             rect1.bottom < rect2.top || 
             rect1.bottom < rect2.top || 
             rect1.top > rect2.bottom);
             rect1.top > rect2.bottom);
+
+        if (isOverlappingFrame) {
+            this.enclosingFrameId = frame.id;
+        }
+        return isOverlappingFrame;
     }
     }
 
 
     public getPortForConnectionPoint(point: NodeMaterialConnectionPoint) {
     public getPortForConnectionPoint(point: NodeMaterialConnectionPoint) {
@@ -344,7 +367,7 @@ export class GraphNode {
         let control = PropertyLedger.RegisteredControls[this.block.getClassName()];
         let control = PropertyLedger.RegisteredControls[this.block.getClassName()];
 
 
         if (!control) {
         if (!control) {
-            control = GenericPropertyTabComponent;
+            control = GenericPropertyComponent;
         }
         }
 
 
         return React.createElement(control, {
         return React.createElement(control, {

+ 2 - 0
nodeEditor/src/diagram/nodeLink.ts

@@ -148,5 +148,7 @@ export class NodeLink {
         }
         }
 
 
         this.onDisposedObservable.notifyObservers(this);
         this.onDisposedObservable.notifyObservers(this);
+
+        this.onDisposedObservable.clear();
     }
     }
 }
 }

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 81 - 2
nodeEditor/src/diagram/nodePort.ts


+ 0 - 24
nodeEditor/src/diagram/properties/PerturbNormalNodePropertyComponent.tsx

@@ -1,24 +0,0 @@
-
-import * as React from "react";
-import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
-import { IPropertyComponentProps } from './propertyComponentProps';
-import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
-
-export class PerturbNormalPropertyTabComponent extends React.Component<IPropertyComponentProps> {
-    constructor(props: IPropertyComponentProps) {
-        super(props)
-    }
-
-    render() {
-        return (
-            <>                
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
-                <LineContainerComponent title="PROPERTIES">
-                    <CheckBoxLineComponent label="Invert X axis" target={this.props.block} propertyName="invertX" onValueChanged={() => this.props.globalState.onRebuildRequiredObservable.notifyObservers()} />
-                    <CheckBoxLineComponent label="Invert Y axis" target={this.props.block} propertyName="invertY" onValueChanged={() => this.props.globalState.onRebuildRequiredObservable.notifyObservers()}/>                    
-                </LineContainerComponent>        
-            </>
-        );
-    }
-}

+ 0 - 33
nodeEditor/src/diagram/properties/clampNodePropertyComponent.tsx

@@ -1,33 +0,0 @@
-
-import * as React from "react";
-import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
-import { FloatLineComponent } from '../../sharedComponents/floatLineComponent';
-import { IPropertyComponentProps } from './propertyComponentProps';
-import { ClampBlock } from 'babylonjs/Materials/Node/Blocks/clampBlock';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
-
-export class ClampPropertyTabComponent extends React.Component<IPropertyComponentProps> {
-
-    constructor(props: IPropertyComponentProps) {
-        super(props)
-    }
-
-    forceRebuild() {
-        this.props.globalState.onUpdateRequiredObservable.notifyObservers();
-        this.props.globalState.onRebuildRequiredObservable.notifyObservers();
-    }
-
-    render() {
-        let clampBlock = this.props.block as ClampBlock
-      
-        return (
-            <div>
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
-                <LineContainerComponent title="PROPERTIES">
-                  <FloatLineComponent globalState={this.props.globalState} label="Minimum" propertyName="minimum" target={clampBlock} onChange={() => this.forceRebuild()} />
-                  <FloatLineComponent globalState={this.props.globalState} label="Maximum" propertyName="maximum" target={clampBlock} onChange={() => this.forceRebuild()} />
-                </LineContainerComponent>
-            </div>
-        );
-    }
-}

+ 1 - 1
nodeEditor/src/diagram/properties/frameNodePortPropertyComponent.tsx

@@ -62,7 +62,7 @@ export class FrameNodePortPropertyTabComponent extends React.Component<IFrameNod
                 </div>
                 </div>
                 <div>
                 <div>
                     <LineContainerComponent title="GENERAL">
                     <LineContainerComponent title="GENERAL">
-                        <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portLabel" target={this.props.frameNodePort} />
+                        <TextInputLineComponent globalState={this.props.globalState} label="Port Name" propertyName="portName" target={this.props.frameNodePort} />
                         {this.props.frameNodePort.framePortPosition !== FramePortPosition.Top && <ButtonLineComponent label="Move Port Up" onClick={() => {
                         {this.props.frameNodePort.framePortPosition !== FramePortPosition.Top && <ButtonLineComponent label="Move Port Up" onClick={() => {
                             this.props.frame.moveFramePortUp(this.props.frameNodePort);
                             this.props.frame.moveFramePortUp(this.props.frameNodePort);
                         }} />}
                         }} />}

+ 113 - 5
nodeEditor/src/diagram/properties/genericNodePropertyComponent.tsx

@@ -4,11 +4,32 @@ import { LineContainerComponent } from '../../sharedComponents/lineContainerComp
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
 import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
 import { TextLineComponent } from '../../sharedComponents/textLineComponent';
 import { TextLineComponent } from '../../sharedComponents/textLineComponent';
+import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
+import { FloatLineComponent } from '../../sharedComponents/floatLineComponent';
+import { SliderLineComponent } from '../../sharedComponents/sliderLineComponent';
+import { Vector2LineComponent } from '../../sharedComponents/vector2LineComponent';
+import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
+import { PropertyTypeForEdition, IPropertyDescriptionForEdition, IEditablePropertyListOption } from 'babylonjs/Materials/Node/nodeMaterialDecorator';
 
 
-export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
+export class GenericPropertyComponent extends React.Component<IPropertyComponentProps> {
+    constructor(props: IPropertyComponentProps) {
+        super(props);
+    }
+
+    render() {
+        return (
+            <>
+                <GeneralPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
+                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
+            </>
+        );
+    }
+}
+
+export class GeneralPropertyTabComponent extends React.Component<IPropertyComponentProps> {
     constructor(props: IPropertyComponentProps) {
     constructor(props: IPropertyComponentProps) {
-        super(props)
+        super(props);
     }
     }
 
 
     render() {
     render() {
@@ -17,13 +38,100 @@ export class GenericPropertyTabComponent extends React.Component<IPropertyCompon
                 <LineContainerComponent title="GENERAL">
                 <LineContainerComponent title="GENERAL">
                     {
                     {
                         (!this.props.block.isInput || !(this.props.block as InputBlock).isAttribute) &&
                         (!this.props.block.isInput || !(this.props.block as InputBlock).isAttribute) &&
-                        <TextInputLineComponent globalState={this.props.globalState} label="Name" propertyName="name" target={this.props.block} 
+                        <TextInputLineComponent globalState={this.props.globalState} label="Name" propertyName="name" target={this.props.block}
                             onChange={() => this.props.globalState.onUpdateRequiredObservable.notifyObservers()} />
                             onChange={() => this.props.globalState.onUpdateRequiredObservable.notifyObservers()} />
                     }
                     }
                     <TextLineComponent label="Type" value={this.props.block.getClassName()} />
                     <TextLineComponent label="Type" value={this.props.block.getClassName()} />
-                    <TextInputLineComponent globalState={this.props.globalState} label="Comments" propertyName="comments" target={this.props.block} 
+                    <TextInputLineComponent globalState={this.props.globalState} label="Comments" propertyName="comments" target={this.props.block}
                             onChange={() => this.props.globalState.onUpdateRequiredObservable.notifyObservers()} />
                             onChange={() => this.props.globalState.onUpdateRequiredObservable.notifyObservers()} />
-                </LineContainerComponent>         
+                </LineContainerComponent>
+            </>
+        );
+    }
+}
+
+export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
+    constructor(props: IPropertyComponentProps) {
+        super(props);
+    }
+
+    forceRebuild(notifiers?: { "rebuild"?: boolean; "update"?: boolean; }) {
+        if (!notifiers || notifiers.update) {
+            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+        }
+
+        if (!notifiers || notifiers.rebuild) {
+            this.props.globalState.onRebuildRequiredObservable.notifyObservers();
+        }
+    }
+
+    render() {
+        const block = this.props.block,
+              propStore: IPropertyDescriptionForEdition[] = (block as any)._propStore;
+
+        if (!propStore) {
+            return (
+                <>
+                </>
+            );
+        }
+
+        const componentList: { [groupName: string]: JSX.Element[]} = {},
+              groups: string[] = [];
+
+        for (const { propertyName, displayName, type, groupName, options } of propStore) {
+            let components = componentList[groupName];
+
+            if (!components) {
+                components = [];
+                componentList[groupName] = components;
+                groups.push(groupName);
+            }
+
+            switch (type) {
+                case PropertyTypeForEdition.Boolean: {
+                    components.push(
+                        <CheckBoxLineComponent label={displayName} target={this.props.block} propertyName={propertyName} onValueChanged={() => this.forceRebuild(options.notifiers)} />
+                    );
+                    break;
+                }
+                case PropertyTypeForEdition.Float: {
+                    let cantDisplaySlider = (isNaN(options.min as number) || isNaN(options.max as number) || options.min === options.max);
+                    if (cantDisplaySlider) {
+                        components.push(
+                            <FloatLineComponent globalState={this.props.globalState} label={displayName} propertyName={propertyName} target={this.props.block} onChange={() => this.forceRebuild(options.notifiers)} />
+                        );
+                    } else {
+                        components.push(
+                            <SliderLineComponent label={displayName} target={this.props.block} propertyName={propertyName} step={Math.abs((options.max as number) - (options.min as number)) / 100.0} minimum={Math.min(options.min as number, options.max as number)} maximum={options.max as number} onChange={() => this.forceRebuild(options.notifiers)}/>
+                        );
+                    }
+                    break;
+                }
+                case PropertyTypeForEdition.Vector2: {
+                    components.push(
+                        <Vector2LineComponent globalState={this.props.globalState} label={displayName} propertyName={propertyName} target={this.props.block} onChange={() => this.forceRebuild(options.notifiers)} />
+                    );
+                    break;
+                }
+                case PropertyTypeForEdition.List: {
+                    components.push(
+                        <OptionsLineComponent label={displayName} options={options.options as IEditablePropertyListOption[]} target={this.props.block} propertyName={propertyName} onSelect={() => this.forceRebuild(options.notifiers)} />
+                    );
+                    break;
+                }
+            }
+        }
+
+        return (
+            <>
+            {
+                groups.map((group) =>
+                    <LineContainerComponent title={group}>
+                        {componentList[group]}
+                    </LineContainerComponent>
+                )
+            }
             </>
             </>
         );
         );
     }
     }

+ 2 - 2
nodeEditor/src/diagram/properties/gradientNodePropertyComponent.tsx

@@ -6,7 +6,7 @@ import { GradientStepComponent } from './gradientStepComponent';
 import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
 import { ButtonLineComponent } from '../../sharedComponents/buttonLineComponent';
 import { Color3 } from 'babylonjs/Maths/math.color';
 import { Color3 } from 'babylonjs/Maths/math.color';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { IPropertyComponentProps } from './propertyComponentProps';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
+import { GeneralPropertyTabComponent } from './genericNodePropertyComponent';
 
 
 export class GradientPropertyTabComponent extends React.Component<IPropertyComponentProps> {
 export class GradientPropertyTabComponent extends React.Component<IPropertyComponentProps> {
 
 
@@ -64,7 +64,7 @@ export class GradientPropertyTabComponent extends React.Component<IPropertyCompo
       
       
         return (
         return (
             <div>
             <div>
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
+                <GeneralPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
                 <LineContainerComponent title="STEPS">
                 <LineContainerComponent title="STEPS">
                     <ButtonLineComponent label="Add new step" onClick={() => this.addNewStep()} />
                     <ButtonLineComponent label="Add new step" onClick={() => this.addNewStep()} />
                     {
                     {

+ 2 - 2
nodeEditor/src/diagram/properties/inputNodePropertyComponent.tsx

@@ -16,7 +16,7 @@ import { NodeMaterialSystemValues } from 'babylonjs/Materials/Node/Enums/nodeMat
 import { AnimatedInputBlockTypes } from 'babylonjs/Materials/Node/Blocks/Input/animatedInputBlockTypes';
 import { AnimatedInputBlockTypes } from 'babylonjs/Materials/Node/Blocks/Input/animatedInputBlockTypes';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
 import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
+import { GeneralPropertyTabComponent } from './genericNodePropertyComponent';
 import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
 import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
 import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
 import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
 import { Color4PropertyTabComponent } from '../../components/propertyTab/properties/color4PropertyTabComponent';
 import { Color4PropertyTabComponent } from '../../components/propertyTab/properties/color4PropertyTabComponent';
@@ -206,7 +206,7 @@ export class InputPropertyTabComponent extends React.Component<IPropertyComponen
 
 
         return (
         return (
             <div>
             <div>
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
+                <GeneralPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
                 <LineContainerComponent title="PROPERTIES">
                 <LineContainerComponent title="PROPERTIES">
                     {
                     {
                         inputBlock.isUniform && !inputBlock.isSystemValue && inputBlock.animationType === AnimatedInputBlockTypes.None &&
                         inputBlock.isUniform && !inputBlock.isSystemValue && inputBlock.animationType === AnimatedInputBlockTypes.None &&

+ 2 - 2
nodeEditor/src/diagram/properties/lightInformationPropertyTabComponent.tsx

@@ -4,7 +4,7 @@ import { LineContainerComponent } from '../../sharedComponents/lineContainerComp
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { LightInformationBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/lightInformationBlock';
 import { LightInformationBlock } from 'babylonjs/Materials/Node/Blocks/Vertex/lightInformationBlock';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
+import { GeneralPropertyTabComponent } from './genericNodePropertyComponent';
 
 
 export class LightInformationPropertyTabComponent extends React.Component<IPropertyComponentProps> {
 export class LightInformationPropertyTabComponent extends React.Component<IPropertyComponentProps> {
 
 
@@ -18,7 +18,7 @@ export class LightInformationPropertyTabComponent extends React.Component<IPrope
 
 
         return (
         return (
             <div>               
             <div>               
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
+                <GeneralPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
                 <LineContainerComponent title="PROPERTIES">
                 <LineContainerComponent title="PROPERTIES">
                     <OptionsLineComponent label="Light" noDirectUpdate={true} valuesAreStrings={true} options={lightOptions} target={lightInformationBlock} propertyName="name" onSelect={(name: any) => {
                     <OptionsLineComponent label="Light" noDirectUpdate={true} valuesAreStrings={true} options={lightOptions} target={lightInformationBlock} propertyName="name" onSelect={(name: any) => {
                         lightInformationBlock.light = scene.getLightByName(name);
                         lightInformationBlock.light = scene.getLightByName(name);

+ 2 - 2
nodeEditor/src/diagram/properties/lightPropertyTabComponent.tsx

@@ -4,7 +4,7 @@ import { LineContainerComponent } from '../../sharedComponents/lineContainerComp
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { LightBlock } from 'babylonjs/Materials/Node/Blocks/Dual/lightBlock';
 import { LightBlock } from 'babylonjs/Materials/Node/Blocks/Dual/lightBlock';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
+import { GeneralPropertyTabComponent } from './genericNodePropertyComponent';
 
 
 export class LightPropertyTabComponent extends React.Component<IPropertyComponentProps> {
 export class LightPropertyTabComponent extends React.Component<IPropertyComponentProps> {
 
 
@@ -20,7 +20,7 @@ export class LightPropertyTabComponent extends React.Component<IPropertyComponen
 
 
         return (
         return (
             <div>                
             <div>                
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
+                <GeneralPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
                 <LineContainerComponent title="PROPERTIES">
                 <LineContainerComponent title="PROPERTIES">
                     <OptionsLineComponent label="Light" defaultIfNull={0} noDirectUpdate={true} valuesAreStrings={true} options={lightOptions} target={lightBlock} propertyName="name" onSelect={(name: any) => {
                     <OptionsLineComponent label="Light" defaultIfNull={0} noDirectUpdate={true} valuesAreStrings={true} options={lightOptions} target={lightBlock} propertyName="name" onSelect={(name: any) => {
                         if (name === "") {
                         if (name === "") {

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

@@ -0,0 +1,54 @@
+
+import * as React from "react";
+import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
+import { GlobalState } from '../../globalState';
+import { TextInputLineComponent } from '../../sharedComponents/textInputLineComponent';
+import {  GraphFrame } from '../graphFrame';
+import { Nullable } from 'babylonjs/types';
+import { Observer } from 'babylonjs/Misc/observable';
+import { NodePort } from '../nodePort';
+import { GraphNode } from '../graphNode';
+import { NodeLink } from '../nodeLink';
+import { FramePortData } from '../graphCanvas';
+import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
+
+export interface IFrameNodePortPropertyTabComponentProps {
+    globalState: GlobalState
+    nodePort: NodePort;
+}
+
+export class NodePortPropertyTabComponent extends React.Component<IFrameNodePortPropertyTabComponentProps> {
+    private _onSelectionChangedObserver: Nullable<Observer<Nullable<GraphFrame | NodePort | GraphNode | NodeLink | FramePortData>>>;
+
+    constructor(props: IFrameNodePortPropertyTabComponentProps) {
+        super(props);
+    }
+
+    componentWillUnmount() {
+        this.props.globalState.onSelectionChangedObservable.remove(this._onSelectionChangedObserver);
+    }
+
+    toggleExposeOnFrame(value: boolean){
+        this.props.nodePort.exposedOnFrame = value;
+        this.props.globalState.onExposePortOnFrameObservable.notifyObservers(this.props.nodePort.node);
+    }
+
+    render() {
+        return (
+            <div id="propertyTab">
+                <div id="header">
+                    <img id="logo" src="https://www.babylonjs.com/Assets/logo-babylonjs-social-twitter.png" />
+                    <div id="title">
+                        NODE MATERIAL EDITOR
+                </div>
+                </div>
+                <div>
+                    <LineContainerComponent title="GENERAL">
+                        {this.props.nodePort.hasLabel() && <TextInputLineComponent globalState={this.props.globalState} label="Port Label" propertyName="portName" target={this.props.nodePort} />}
+                        {this.props.nodePort.node.enclosingFrameId !== undefined && <CheckBoxLineComponent label= "Expose Port on Frame" target={this.props.nodePort} isSelected={() => this.props.nodePort.exposedOnFrame} onSelect={(value: boolean) => this.toggleExposeOnFrame(value)}  propertyName="exposedOnFrame" disabled={this.props.nodePort.disabled} />}
+                    </LineContainerComponent>
+                </div>
+            </div>
+        );
+    }
+}

+ 0 - 33
nodeEditor/src/diagram/properties/remapNodePropertyComponent.tsx

@@ -1,33 +0,0 @@
-
-import * as React from "react";
-import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
-import { Vector2LineComponent } from '../../sharedComponents/vector2LineComponent';
-import { IPropertyComponentProps } from './propertyComponentProps';
-import { RemapBlock } from 'babylonjs/Materials/Node/Blocks/remapBlock';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
-
-export class RemapPropertyTabComponent extends React.Component<IPropertyComponentProps> {
-
-    constructor(props: IPropertyComponentProps) {
-        super(props)
-    }
-
-    forceRebuild() {
-        this.props.globalState.onUpdateRequiredObservable.notifyObservers();
-        this.props.globalState.onRebuildRequiredObservable.notifyObservers();
-    }
-
-    render() {
-        let remapBlock = this.props.block as RemapBlock;
-      
-        return (
-            <div>                
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
-                <LineContainerComponent title="PROPERTIES">
-                  <Vector2LineComponent globalState={this.props.globalState} label="From" propertyName="sourceRange" target={remapBlock} onChange={() => this.forceRebuild()} />
-                  <Vector2LineComponent globalState={this.props.globalState} label="To" propertyName="targetRange" target={remapBlock} onChange={() => this.forceRebuild()} />
-                </LineContainerComponent>
-            </div>
-        );
-    }
-}

+ 19 - 8
nodeEditor/src/diagram/properties/texturePropertyTabComponent.tsx

@@ -14,13 +14,17 @@ import { CubeTexture } from 'babylonjs/Materials/Textures/cubeTexture';
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { ReflectionTextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/reflectionTextureBlock';
 import { ReflectionTextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/reflectionTextureBlock';
+import { ReflectionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/reflectionBlock';
+import { RefractionBlock } from 'babylonjs/Materials/Node/Blocks/PBR/refractionBlock';
 import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/textureBlock';
 import { TextureBlock } from 'babylonjs/Materials/Node/Blocks/Dual/textureBlock';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
+import { GeneralPropertyTabComponent, GenericPropertyTabComponent } from './genericNodePropertyComponent';
+
+type ReflectionTexture = ReflectionTextureBlock | ReflectionBlock | RefractionBlock;
 
 
 export class TexturePropertyTabComponent extends React.Component<IPropertyComponentProps, {isEmbedded: boolean, loadAsCubeTexture: boolean}> {
 export class TexturePropertyTabComponent extends React.Component<IPropertyComponentProps, {isEmbedded: boolean, loadAsCubeTexture: boolean}> {
 
 
-    get textureBlock(): TextureBlock | ReflectionTextureBlock {
-        return this.props.block as TextureBlock | ReflectionTextureBlock;
+    get textureBlock(): TextureBlock | ReflectionTexture {
+        return this.props.block as TextureBlock | ReflectionTexture;
     }
     }
 
 
     constructor(props: IPropertyComponentProps) {
     constructor(props: IPropertyComponentProps) {
@@ -33,7 +37,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
 
 
     UNSAFE_componentWillUpdate(nextProps: IPropertyComponentProps, nextState: {isEmbedded: boolean, loadAsCubeTexture: boolean}) {
     UNSAFE_componentWillUpdate(nextProps: IPropertyComponentProps, nextState: {isEmbedded: boolean, loadAsCubeTexture: boolean}) {
         if (nextProps.block !== this.props.block) {
         if (nextProps.block !== this.props.block) {
-            let texture = (nextProps.block as TextureBlock | ReflectionTextureBlock).texture as BaseTexture;
+            let texture = (nextProps.block as TextureBlock | ReflectionTexture).texture as BaseTexture;
 
 
             nextState.isEmbedded = !texture || texture.name.substring(0, 4) === "data";
             nextState.isEmbedded = !texture || texture.name.substring(0, 4) === "data";
             nextState.loadAsCubeTexture = texture && texture.isCube;
             nextState.loadAsCubeTexture = texture && texture.isCube;
@@ -76,7 +80,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
 
 
         if (!texture) {
         if (!texture) {
             if (!this.state.loadAsCubeTexture) {
             if (!this.state.loadAsCubeTexture) {
-                this.textureBlock.texture = new Texture(null, this.props.globalState.nodeMaterial.getScene(), false, this.textureBlock instanceof ReflectionTextureBlock);
+                this.textureBlock.texture = new Texture(null, this.props.globalState.nodeMaterial.getScene(), false, this.textureBlock instanceof ReflectionTextureBlock || this.textureBlock instanceof ReflectionBlock || this.textureBlock instanceof RefractionBlock);
                 texture = this.textureBlock.texture;
                 texture = this.textureBlock.texture;
                 texture.coordinatesMode = Texture.EQUIRECTANGULAR_MODE;
                 texture.coordinatesMode = Texture.EQUIRECTANGULAR_MODE;
             } else {
             } else {
@@ -119,7 +123,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
         this._prepareTexture();
         this._prepareTexture();
 
 
         let texture = this.textureBlock.texture as BaseTexture;       
         let texture = this.textureBlock.texture as BaseTexture;       
-        if (texture.isCube || this.textureBlock instanceof ReflectionTextureBlock) {
+        if (texture.isCube || this.textureBlock instanceof ReflectionTextureBlock || this.textureBlock instanceof ReflectionBlock || this.textureBlock instanceof RefractionBlock) {
             let extension: string | undefined = undefined;
             let extension: string | undefined = undefined;
             if (url.toLowerCase().indexOf(".dds") > 0) {
             if (url.toLowerCase().indexOf(".dds") > 0) {
                 extension = ".dds";
                 extension = ".dds";
@@ -143,7 +147,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
 
 
         url = url.replace(/\?nocache=\d+/, "");
         url = url.replace(/\?nocache=\d+/, "");
 
 
-        let isInReflectionMode = this.textureBlock instanceof ReflectionTextureBlock;
+        let isInReflectionMode = this.textureBlock instanceof ReflectionTextureBlock || this.textureBlock instanceof ReflectionBlock || this.textureBlock instanceof RefractionBlock;
 
 
         var reflectionModeOptions: {label: string, value: number}[] = [
         var reflectionModeOptions: {label: string, value: number}[] = [
             {
             {
@@ -177,7 +181,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
         
         
         return (
         return (
             <div>                
             <div>                
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
+                <GeneralPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
                 <LineContainerComponent title="PROPERTIES">
                 <LineContainerComponent title="PROPERTIES">
                     <CheckBoxLineComponent label="Auto select UV" propertyName="autoSelectUV" target={this.props.block} onValueChanged={() => {                        
                     <CheckBoxLineComponent label="Auto select UV" propertyName="autoSelectUV" target={this.props.block} onValueChanged={() => {                        
                         this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         this.props.globalState.onUpdateRequiredObservable.notifyObservers();
@@ -189,6 +193,12 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
                         }}/>
                         }}/>
                     }
                     }
                     {
                     {
+                        texture && !isInReflectionMode &&
+                        <CheckBoxLineComponent label="Convert to linear space" propertyName="convertToLinearSpace" target={this.props.block} onValueChanged={() => {                        
+                            this.props.globalState.onUpdateRequiredObservable.notifyObservers();
+                        }}/>
+                    }
+                    {
                         texture && isInReflectionMode &&
                         texture && isInReflectionMode &&
                         <OptionsLineComponent label="Reflection mode" options={reflectionModeOptions} target={texture} propertyName="coordinatesMode" onSelect={(value: any) => {
                         <OptionsLineComponent label="Reflection mode" options={reflectionModeOptions} target={texture} propertyName="coordinatesMode" onSelect={(value: any) => {
                             texture.coordinatesMode = value;
                             texture.coordinatesMode = value;
@@ -293,6 +303,7 @@ export class TexturePropertyTabComponent extends React.Component<IPropertyCompon
                         <ButtonLineComponent label="Remove" onClick={() => this.removeTexture()}/>
                         <ButtonLineComponent label="Remove" onClick={() => this.removeTexture()}/>
                     }
                     }
                 </LineContainerComponent>
                 </LineContainerComponent>
+                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
             </div>
             </div>
         );
         );
     }
     }

+ 2 - 2
nodeEditor/src/diagram/properties/transformNodePropertyComponent.tsx

@@ -4,7 +4,7 @@ import { LineContainerComponent } from '../../sharedComponents/lineContainerComp
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
 import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
 import { TransformBlock } from 'babylonjs/Materials/Node/Blocks/transformBlock';
 import { TransformBlock } from 'babylonjs/Materials/Node/Blocks/transformBlock';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
+import { GeneralPropertyTabComponent } from './genericNodePropertyComponent';
 
 
 export class TransformPropertyTabComponent extends React.Component<IPropertyComponentProps> {
 export class TransformPropertyTabComponent extends React.Component<IPropertyComponentProps> {
     constructor(props: IPropertyComponentProps) {
     constructor(props: IPropertyComponentProps) {
@@ -14,7 +14,7 @@ export class TransformPropertyTabComponent extends React.Component<IPropertyComp
     render() {
     render() {
         return (
         return (
             <>                
             <>                
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
+                <GeneralPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
                 <LineContainerComponent title="PROPERTIES">
                 <LineContainerComponent title="PROPERTIES">
                     <CheckBoxLineComponent label="Transform as direction" onSelect={value => {
                     <CheckBoxLineComponent label="Transform as direction" onSelect={value => {
                         let transformBlock = this.props.block as TransformBlock;
                         let transformBlock = this.props.block as TransformBlock;

+ 2 - 2
nodeEditor/src/diagram/properties/trigonometryNodePropertyComponent.tsx

@@ -4,7 +4,7 @@ import { LineContainerComponent } from '../../sharedComponents/lineContainerComp
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { OptionsLineComponent } from '../../sharedComponents/optionsLineComponent';
 import { TrigonometryBlockOperations, TrigonometryBlock } from 'babylonjs/Materials/Node/Blocks/trigonometryBlock';
 import { TrigonometryBlockOperations, TrigonometryBlock } from 'babylonjs/Materials/Node/Blocks/trigonometryBlock';
 import { IPropertyComponentProps } from './propertyComponentProps';
 import { IPropertyComponentProps } from './propertyComponentProps';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
+import { GeneralPropertyTabComponent } from './genericNodePropertyComponent';
 
 
 export class TrigonometryPropertyTabComponent extends React.Component<IPropertyComponentProps> {
 export class TrigonometryPropertyTabComponent extends React.Component<IPropertyComponentProps> {
 
 
@@ -41,7 +41,7 @@ export class TrigonometryPropertyTabComponent extends React.Component<IPropertyC
         
         
         return (
         return (
             <div>                
             <div>                
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
+                <GeneralPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
                 <LineContainerComponent title="PROPERTIES">  
                 <LineContainerComponent title="PROPERTIES">  
                     <OptionsLineComponent label="Operation" options={operationOptions} target={trigonometryBlock} propertyName="operation" onSelect={(value: any) => {
                     <OptionsLineComponent label="Operation" options={operationOptions} target={trigonometryBlock} propertyName="operation" onSelect={(value: any) => {
                         this.props.globalState.onUpdateRequiredObservable.notifyObservers();
                         this.props.globalState.onUpdateRequiredObservable.notifyObservers();

+ 0 - 23
nodeEditor/src/diagram/properties/worleyNoise3DNodePropertyComponent.tsx

@@ -1,23 +0,0 @@
-
-import * as React from "react";
-import { LineContainerComponent } from '../../sharedComponents/lineContainerComponent';
-import { IPropertyComponentProps } from './propertyComponentProps';
-import { CheckBoxLineComponent } from '../../sharedComponents/checkBoxLineComponent';
-import { GenericPropertyTabComponent } from './genericNodePropertyComponent';
-
-export class WorleyNoise3DNodePropertyComponent extends React.Component<IPropertyComponentProps> {
-    constructor(props: IPropertyComponentProps) {
-        super(props)
-    }
-
-    render() {
-        return (
-            <>
-                <GenericPropertyTabComponent globalState={this.props.globalState} block={this.props.block}/>
-                <LineContainerComponent title="PROPERTIES">
-                    <CheckBoxLineComponent label="Use Manhattan Distance" target={this.props.block} propertyName="manhattanDistance" onValueChanged={() => this.props.globalState.onRebuildRequiredObservable.notifyObservers()} />              
-                </LineContainerComponent>        
-            </>
-        );
-    }
-}

+ 2 - 8
nodeEditor/src/diagram/propertyLedger.ts

@@ -2,13 +2,9 @@ import { ComponentClass } from 'react';
 import { InputPropertyTabComponent } from './properties/inputNodePropertyComponent';
 import { InputPropertyTabComponent } from './properties/inputNodePropertyComponent';
 import { IPropertyComponentProps } from './properties/propertyComponentProps';
 import { IPropertyComponentProps } from './properties/propertyComponentProps';
 import { TransformPropertyTabComponent } from './properties/transformNodePropertyComponent';
 import { TransformPropertyTabComponent } from './properties/transformNodePropertyComponent';
-import { PerturbNormalPropertyTabComponent } from './properties/PerturbNormalNodePropertyComponent';
-import { WorleyNoise3DNodePropertyComponent } from './properties/worleyNoise3DNodePropertyComponent';
-import { ClampPropertyTabComponent } from './properties/clampNodePropertyComponent';
 import { GradientPropertyTabComponent } from './properties/gradientNodePropertyComponent';
 import { GradientPropertyTabComponent } from './properties/gradientNodePropertyComponent';
 import { LightPropertyTabComponent } from './properties/lightPropertyTabComponent';
 import { LightPropertyTabComponent } from './properties/lightPropertyTabComponent';
 import { LightInformationPropertyTabComponent } from './properties/lightInformationPropertyTabComponent';
 import { LightInformationPropertyTabComponent } from './properties/lightInformationPropertyTabComponent';
-import { RemapPropertyTabComponent } from './properties/remapNodePropertyComponent';
 import { TexturePropertyTabComponent } from './properties/texturePropertyTabComponent';
 import { TexturePropertyTabComponent } from './properties/texturePropertyTabComponent';
 import { TrigonometryPropertyTabComponent } from './properties/trigonometryNodePropertyComponent';
 import { TrigonometryPropertyTabComponent } from './properties/trigonometryNodePropertyComponent';
 
 
@@ -18,13 +14,11 @@ export class PropertyLedger {
 
 
 PropertyLedger.RegisteredControls["TransformBlock"] = TransformPropertyTabComponent;
 PropertyLedger.RegisteredControls["TransformBlock"] = TransformPropertyTabComponent;
 PropertyLedger.RegisteredControls["InputBlock"] = InputPropertyTabComponent;
 PropertyLedger.RegisteredControls["InputBlock"] = InputPropertyTabComponent;
-PropertyLedger.RegisteredControls["PerturbNormalBlock"] = PerturbNormalPropertyTabComponent;
-PropertyLedger.RegisteredControls["WorleyNoise3DBlock"] = WorleyNoise3DNodePropertyComponent;
-PropertyLedger.RegisteredControls["ClampBlock"] = ClampPropertyTabComponent;
 PropertyLedger.RegisteredControls["GradientBlock"] = GradientPropertyTabComponent;
 PropertyLedger.RegisteredControls["GradientBlock"] = GradientPropertyTabComponent;
 PropertyLedger.RegisteredControls["LightBlock"] = LightPropertyTabComponent;
 PropertyLedger.RegisteredControls["LightBlock"] = LightPropertyTabComponent;
 PropertyLedger.RegisteredControls["LightInformationBlock"] = LightInformationPropertyTabComponent;
 PropertyLedger.RegisteredControls["LightInformationBlock"] = LightInformationPropertyTabComponent;
-PropertyLedger.RegisteredControls["RemapBlock"] = RemapPropertyTabComponent;
 PropertyLedger.RegisteredControls["TextureBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["TextureBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["ReflectionTextureBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["ReflectionTextureBlock"] = TexturePropertyTabComponent;
+PropertyLedger.RegisteredControls["ReflectionBlock"] = TexturePropertyTabComponent;
+PropertyLedger.RegisteredControls["RefractionBlock"] = TexturePropertyTabComponent;
 PropertyLedger.RegisteredControls["TrigonometryBlock"] = TrigonometryPropertyTabComponent;
 PropertyLedger.RegisteredControls["TrigonometryBlock"] = TrigonometryPropertyTabComponent;

+ 1 - 0
nodeEditor/src/globalState.ts

@@ -42,6 +42,7 @@ export class GlobalState {
     onGraphNodeRemovalObservable = new Observable<GraphNode>();
     onGraphNodeRemovalObservable = new Observable<GraphNode>();
     onGetNodeFromBlock: (block: NodeMaterialBlock) => GraphNode;
     onGetNodeFromBlock: (block: NodeMaterialBlock) => GraphNode;
     onGridSizeChanged = new Observable<void>();
     onGridSizeChanged = new Observable<void>();
+    onExposePortOnFrameObservable = new Observable<GraphNode>();
     previewMeshType: PreviewMeshType;
     previewMeshType: PreviewMeshType;
     previewMeshFile: File;
     previewMeshFile: File;
     listOfCustomPreviewMeshFiles: File[] = [];
     listOfCustomPreviewMeshFiles: File[] = [];

+ 15 - 5
nodeEditor/src/sharedComponents/checkBoxLineComponent.tsx

@@ -10,9 +10,10 @@ export interface ICheckBoxLineComponentProps {
     onSelect?: (value: boolean) => void;
     onSelect?: (value: boolean) => void;
     onValueChanged?: () => void;
     onValueChanged?: () => void;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
     onPropertyChangedObservable?: Observable<PropertyChangedEvent>;
+    disabled?: boolean;
 }
 }
 
 
-export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, { isSelected: boolean }> {
+export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponentProps, { isSelected: boolean, isDisabled?: boolean }> {
     private static _UniqueIdSeed = 0;
     private static _UniqueIdSeed = 0;
     private _uniqueId: number;
     private _uniqueId: number;
     private _localChange = false;
     private _localChange = false;
@@ -26,9 +27,13 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
         } else {
         } else {
             this.state = { isSelected: this.props.target[this.props.propertyName!] == true };
             this.state = { isSelected: this.props.target[this.props.propertyName!] == true };
         }
         }
+
+        if (this.props.disabled) {
+            this.state = { ...this.state, isDisabled: this.props.disabled };
+        }
     }
     }
 
 
-    shouldComponentUpdate(nextProps: ICheckBoxLineComponentProps, nextState: { isSelected: boolean }) {
+    shouldComponentUpdate(nextProps: ICheckBoxLineComponentProps, nextState: { isSelected: boolean, isDisabled: boolean }) {
         var currentState: boolean;
         var currentState: boolean;
 
 
         if (nextProps.isSelected) {
         if (nextProps.isSelected) {
@@ -42,7 +47,12 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
             this._localChange = false;
             this._localChange = false;
             return true;
             return true;
         }
         }
-        return nextProps.label !== this.props.label;
+
+        if(nextProps.disabled !== !!nextState.isDisabled){
+            return true;
+        }
+        
+        return nextProps.label !== this.props.label || nextProps.target !== this.props.target;
     }
     }
 
 
     onChange() {
     onChange() {
@@ -76,8 +86,8 @@ export class CheckBoxLineComponent extends React.Component<ICheckBoxLineComponen
                     {this.props.label}
                     {this.props.label}
                 </div>
                 </div>
                 <div className="checkBox">
                 <div className="checkBox">
-                    <input type="checkbox" id={"checkbox" + this._uniqueId} className="cbx hidden" checked={this.state.isSelected} onChange={() => this.onChange()} />
-                    <label htmlFor={"checkbox" + this._uniqueId} className="lbl"></label>
+                    <input type="checkbox" id={"checkbox" + this._uniqueId} className="cbx hidden" checked={this.state.isSelected} onChange={() => this.onChange()} disabled={!!this.props.disabled}/>
+                    <label htmlFor={"checkbox" + this._uniqueId} className={`lbl${!!this.props.disabled ? ' disabled' : ''}`}></label>
                 </div>
                 </div>
             </div>
             </div>
         );
         );

+ 1 - 1
package.json

@@ -7,7 +7,7 @@
     ],
     ],
     "name": "babylonjs",
     "name": "babylonjs",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
     "description": "Babylon.js is a JavaScript 3D engine based on webgl.",
-    "version": "4.2.0-alpha.11",
+    "version": "4.2.0-alpha.12",
     "repository": {
     "repository": {
         "type": "git",
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
         "url": "https://github.com/BabylonJS/Babylon.js.git"

+ 13 - 13
src/Audio/sound.ts

@@ -216,14 +216,14 @@ export class Sound {
             if (options.volume !== undefined) {
             if (options.volume !== undefined) {
                 this._volume = options.volume;
                 this._volume = options.volume;
             }
             }
-            this.spatialSound = options.spatialSound || false;
-            this.maxDistance = options.maxDistance || 100;
-            this.useCustomAttenuation = options.useCustomAttenuation || false;
+            this.spatialSound = options.spatialSound ?? false;
+            this.maxDistance = options.maxDistance ?? 100;
+            this.useCustomAttenuation = options.useCustomAttenuation ?? false;
             this.rolloffFactor = options.rolloffFactor || 1;
             this.rolloffFactor = options.rolloffFactor || 1;
             this.refDistance = options.refDistance || 1;
             this.refDistance = options.refDistance || 1;
             this.distanceModel = options.distanceModel || "linear";
             this.distanceModel = options.distanceModel || "linear";
             this._playbackRate = options.playbackRate || 1;
             this._playbackRate = options.playbackRate || 1;
-            this._streaming = options.streaming || false;
+            this._streaming = options.streaming ?? false;
             this._length = options.length;
             this._length = options.length;
             this._offset = options.offset;
             this._offset = options.offset;
         }
         }
@@ -452,15 +452,15 @@ export class Sound {
      */
      */
     public updateOptions(options: ISoundOptions): void {
     public updateOptions(options: ISoundOptions): void {
         if (options) {
         if (options) {
-            this.loop = options.loop || this.loop;
-            this.maxDistance = options.maxDistance || this.maxDistance;
-            this.useCustomAttenuation = options.useCustomAttenuation || this.useCustomAttenuation;
-            this.rolloffFactor = options.rolloffFactor || this.rolloffFactor;
-            this.refDistance = options.refDistance || this.refDistance;
-            this.distanceModel = options.distanceModel || this.distanceModel;
-            this._playbackRate = options.playbackRate || this._playbackRate;
-            this._length = options.length ? options.length / 1000 : undefined;
-            this._offset = options.offset ? options.offset / 1000 : undefined;
+            this.loop = options.loop ?? this.loop;
+            this.maxDistance = options.maxDistance ?? this.maxDistance;
+            this.useCustomAttenuation = options.useCustomAttenuation ?? this.useCustomAttenuation;
+            this.rolloffFactor = options.rolloffFactor ?? this.rolloffFactor;
+            this.refDistance = options.refDistance ?? this.refDistance;
+            this.distanceModel = options.distanceModel ?? this.distanceModel;
+            this._playbackRate = options.playbackRate ?? this._playbackRate;
+            this._length = options.length ?? undefined;
+            this._offset = options.offset ?? undefined;
             this._updateSpatialParameters();
             this._updateSpatialParameters();
             if (this.isPlaying) {
             if (this.isPlaying) {
                 if (this._streaming && this._htmlAudioElement) {
                 if (this._streaming && this._htmlAudioElement) {

+ 9 - 0
src/Debug/debugLayer.ts

@@ -263,6 +263,15 @@ export class DebugLayer {
     }
     }
 
 
     /**
     /**
+     * Update the scene in the inspector
+     */
+    public setAsActiveScene() {
+        if (this.BJSINSPECTOR) {
+            this.BJSINSPECTOR.Inspector._SetNewScene(this._scene);
+        }
+    }
+
+    /**
       * Launch the debugLayer.
       * Launch the debugLayer.
       * @param config Define the configuration of the inspector
       * @param config Define the configuration of the inspector
       * @return a promise fulfilled when the debug layer is visible
       * @return a promise fulfilled when the debug layer is visible

+ 7 - 7
src/Engines/Extensions/engine.rawTexture.ts

@@ -105,7 +105,7 @@ declare module "../../Engines/thinEngine" {
          * @param onError defines a callback called if there is an error
          * @param onError defines a callback called if there is an error
          * @returns the cube texture as an InternalTexture
          * @returns the cube texture as an InternalTexture
          */
          */
-        createRawCubeTextureFromUrl(url: string, scene: Scene, size: number, format: number, type: number, noMipmap: boolean,
+        createRawCubeTextureFromUrl(url: string, scene: Nullable<Scene>, size: number, format: number, type: number, noMipmap: boolean,
             callback: (ArrayBuffer: ArrayBuffer) => Nullable<ArrayBufferView[]>,
             callback: (ArrayBuffer: ArrayBuffer) => Nullable<ArrayBufferView[]>,
             mipmapGenerator: Nullable<((faces: ArrayBufferView[]) => ArrayBufferView[][])>,
             mipmapGenerator: Nullable<((faces: ArrayBufferView[]) => ArrayBufferView[][])>,
             onLoad: Nullable<() => void>,
             onLoad: Nullable<() => void>,
@@ -127,7 +127,7 @@ declare module "../../Engines/thinEngine" {
          * @param invertY defines if data must be stored with Y axis inverted
          * @param invertY defines if data must be stored with Y axis inverted
          * @returns the cube texture as an InternalTexture
          * @returns the cube texture as an InternalTexture
          */
          */
-        createRawCubeTextureFromUrl(url: string, scene: Scene, size: number, format: number, type: number, noMipmap: boolean,
+        createRawCubeTextureFromUrl(url: string, scene: Nullable<Scene>, size: number, format: number, type: number, noMipmap: boolean,
             callback: (ArrayBuffer: ArrayBuffer) => Nullable<ArrayBufferView[]>,
             callback: (ArrayBuffer: ArrayBuffer) => Nullable<ArrayBufferView[]>,
             mipmapGenerator: Nullable<((faces: ArrayBufferView[]) => ArrayBufferView[][])>,
             mipmapGenerator: Nullable<((faces: ArrayBufferView[]) => ArrayBufferView[][])>,
             onLoad: Nullable<() => void>,
             onLoad: Nullable<() => void>,
@@ -410,7 +410,7 @@ ThinEngine.prototype.updateRawCubeTexture = function(texture: InternalTexture, d
     texture.isReady = true;
     texture.isReady = true;
 };
 };
 
 
-ThinEngine.prototype.createRawCubeTextureFromUrl = function(url: string, scene: Scene, size: number, format: number, type: number, noMipmap: boolean,
+ThinEngine.prototype.createRawCubeTextureFromUrl = function(url: string, scene: Nullable<Scene>, size: number, format: number, type: number, noMipmap: boolean,
     callback: (ArrayBuffer: ArrayBuffer) => Nullable<ArrayBufferView[]>,
     callback: (ArrayBuffer: ArrayBuffer) => Nullable<ArrayBufferView[]>,
     mipmapGenerator: Nullable<((faces: ArrayBufferView[]) => ArrayBufferView[][])>,
     mipmapGenerator: Nullable<((faces: ArrayBufferView[]) => ArrayBufferView[][])>,
     onLoad: Nullable<() => void> = null,
     onLoad: Nullable<() => void> = null,
@@ -420,12 +420,12 @@ ThinEngine.prototype.createRawCubeTextureFromUrl = function(url: string, scene:
 
 
     var gl = this._gl;
     var gl = this._gl;
     var texture = this.createRawCubeTexture(null, size, format, type, !noMipmap, invertY, samplingMode, null);
     var texture = this.createRawCubeTexture(null, size, format, type, !noMipmap, invertY, samplingMode, null);
-    scene._addPendingData(texture);
+    scene?._addPendingData(texture);
     texture.url = url;
     texture.url = url;
     this._internalTexturesCache.push(texture);
     this._internalTexturesCache.push(texture);
 
 
     var onerror = (request?: IWebRequest, exception?: any) => {
     var onerror = (request?: IWebRequest, exception?: any) => {
-        scene._removePendingData(texture);
+        scene?._removePendingData(texture);
         if (onError && request) {
         if (onError && request) {
             onError(request.status + " " + request.statusText, exception);
             onError(request.status + " " + request.statusText, exception);
         }
         }
@@ -474,7 +474,7 @@ ThinEngine.prototype.createRawCubeTextureFromUrl = function(url: string, scene:
 
 
         texture.isReady = true;
         texture.isReady = true;
         // this.resetTextureCache();
         // this.resetTextureCache();
-        scene._removePendingData(texture);
+        scene?._removePendingData(texture);
 
 
         if (onLoad) {
         if (onLoad) {
             onLoad();
             onLoad();
@@ -483,7 +483,7 @@ ThinEngine.prototype.createRawCubeTextureFromUrl = function(url: string, scene:
 
 
     this._loadFile(url, (data) => {
     this._loadFile(url, (data) => {
         internalCallback(data);
         internalCallback(data);
-    }, undefined, scene.offlineProvider, true, onerror);
+    }, undefined, scene?.offlineProvider, true, onerror);
 
 
     return texture;
     return texture;
 };
 };

+ 52 - 0
src/Engines/Extensions/engine.readTexture.ts

@@ -0,0 +1,52 @@
+import { ThinEngine } from "../../Engines/thinEngine";
+import { InternalTexture } from '../../Materials/Textures/internalTexture';
+import { Nullable } from '../../types';
+
+declare module "../../Engines/thinEngine" {
+    export interface ThinEngine {
+        /** @hidden */
+        _readTexturePixels(texture: InternalTexture, width: number, height: number, faceIndex?: number, level?: number, buffer?: Nullable<ArrayBufferView>): ArrayBufferView;
+    }
+}
+
+ThinEngine.prototype._readTexturePixels = function(texture: InternalTexture, width: number, height: number, faceIndex = -1, level = 0, buffer: Nullable<ArrayBufferView> = null): ArrayBufferView {
+    let gl = this._gl;
+    if (!this._dummyFramebuffer) {
+        let dummy = gl.createFramebuffer();
+
+        if (!dummy) {
+            throw new Error("Unable to create dummy framebuffer");
+        }
+
+        this._dummyFramebuffer = dummy;
+    }
+    gl.bindFramebuffer(gl.FRAMEBUFFER, this._dummyFramebuffer);
+
+    if (faceIndex > -1) {
+        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_CUBE_MAP_POSITIVE_X + faceIndex, texture._webGLTexture, level);
+    } else {
+        gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture._webGLTexture, level);
+    }
+
+    let readType = (texture.type !== undefined) ? this._getWebGLTextureType(texture.type) : gl.UNSIGNED_BYTE;
+
+    switch (readType) {
+        case gl.UNSIGNED_BYTE:
+            if (!buffer) {
+                buffer = new Uint8Array(4 * width * height);
+            }
+            readType = gl.UNSIGNED_BYTE;
+            break;
+        default:
+            if (!buffer) {
+                buffer = new Float32Array(4 * width * height);
+            }
+            readType = gl.FLOAT;
+            break;
+    }
+
+    gl.readPixels(0, 0, width, height, gl.RGBA, readType, <DataView>buffer);
+    gl.bindFramebuffer(gl.FRAMEBUFFER, this._currentFramebuffer);
+
+    return buffer;
+};

+ 5 - 0
src/Engines/Extensions/engine.views.ts

@@ -139,6 +139,11 @@ Engine.prototype._renderViews = function() {
             canvas.height = canvas.clientHeight;
             canvas.height = canvas.clientHeight;
             parent.width = canvas.clientWidth;
             parent.width = canvas.clientWidth;
             parent.height = canvas.clientHeight;
             parent.height = canvas.clientHeight;
+            this.resize();
+        }
+
+        if (!parent.width || !parent.height) {
+            return false;
         }
         }
 
 
         // Render the frame
         // Render the frame

+ 1 - 0
src/Engines/Extensions/index.ts

@@ -12,6 +12,7 @@ export * from "./engine.renderTargetCube";
 export * from "./engine.webVR";
 export * from "./engine.webVR";
 export * from "./engine.uniformBuffer";
 export * from "./engine.uniformBuffer";
 export * from "./engine.views";
 export * from "./engine.views";
+export * from "./engine.readTexture";
 
 
 // must import first since nothing references the exports
 // must import first since nothing references the exports
 import "./engine.textureSelector";
 import "./engine.textureSelector";

+ 0 - 0
src/Engines/engine.ts


Vissa filer visades inte eftersom för många filer har ändrats