Browse Source

Merge branch 'master' of https://github.com/BabylonJS/Babylon.js into drigax/AddSkeletalAnimationGroupSerialization

Nicholas Barlow 5 years ago
parent
commit
9b55ae8710
100 changed files with 16140 additions and 6368 deletions
  1. 2 1
      .vscode/settings.json
  2. 49 38
      Playground/js/frame.js
  3. 8 7
      Playground/js/main.js
  4. 17 4
      Playground/js/monacoCreator.js
  5. 65 0
      Playground/js/utils.js
  6. 639 0
      Playground/scripts/spriteMap.js
  7. 420 0
      Playground/textures/spriteMap/none_trimmed/Legends_Level_A.json
  8. BIN
      Playground/textures/spriteMap/none_trimmed/Legends_Level_A.png
  9. 2 0
      Playground/textures/spriteMap/none_trimmed/levelStage.tilemaps
  10. 1225 105
      dist/preview release/babylon.d.ts
  11. 1 1
      dist/preview release/babylon.js
  12. 2660 464
      dist/preview release/babylon.max.js
  13. 1 1
      dist/preview release/babylon.max.js.map
  14. 2439 203
      dist/preview release/babylon.module.d.ts
  15. 1314 126
      dist/preview release/documentation.d.ts
  16. 1 1
      dist/preview release/glTF2Interface/package.json
  17. 9 1
      dist/preview release/gui/babylon.gui.d.ts
  18. 102 16
      dist/preview release/gui/babylon.gui.js
  19. 1 1
      dist/preview release/gui/babylon.gui.js.map
  20. 1 1
      dist/preview release/gui/babylon.gui.min.js
  21. 18 2
      dist/preview release/gui/babylon.gui.module.d.ts
  22. 2 2
      dist/preview release/gui/package.json
  23. 8 8
      dist/preview release/inspector/babylon.inspector.bundle.js
  24. 616 1696
      dist/preview release/inspector/babylon.inspector.bundle.max.js
  25. 1 1
      dist/preview release/inspector/babylon.inspector.bundle.max.js.map
  26. 22 1
      dist/preview release/inspector/babylon.inspector.d.ts
  27. 48 3
      dist/preview release/inspector/babylon.inspector.module.d.ts
  28. 7 7
      dist/preview release/inspector/package.json
  29. 3 3
      dist/preview release/loaders/babylon.glTF1FileLoader.js
  30. 2 2
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  31. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.js.map
  32. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  33. 5 5
      dist/preview release/loaders/babylon.glTFFileLoader.js
  34. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.js.map
  35. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  36. 5 5
      dist/preview release/loaders/babylonjs.loaders.js
  37. 1 1
      dist/preview release/loaders/babylonjs.loaders.js.map
  38. 1 1
      dist/preview release/loaders/babylonjs.loaders.min.js
  39. 3 3
      dist/preview release/loaders/package.json
  40. 3 3
      dist/preview release/materialsLibrary/babylon.cellMaterial.js
  41. 3 3
      dist/preview release/materialsLibrary/babylon.customMaterial.js
  42. 1 1
      dist/preview release/materialsLibrary/babylon.customMaterial.min.js
  43. 3 3
      dist/preview release/materialsLibrary/babylon.fireMaterial.js
  44. 3 3
      dist/preview release/materialsLibrary/babylon.furMaterial.js
  45. 3 3
      dist/preview release/materialsLibrary/babylon.gradientMaterial.js
  46. 3 3
      dist/preview release/materialsLibrary/babylon.gridMaterial.js
  47. 3 3
      dist/preview release/materialsLibrary/babylon.lavaMaterial.js
  48. 3 3
      dist/preview release/materialsLibrary/babylon.mixMaterial.js
  49. 3 3
      dist/preview release/materialsLibrary/babylon.normalMaterial.js
  50. 3 3
      dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js
  51. 3 3
      dist/preview release/materialsLibrary/babylon.simpleMaterial.js
  52. 3 3
      dist/preview release/materialsLibrary/babylon.skyMaterial.js
  53. 3 3
      dist/preview release/materialsLibrary/babylon.terrainMaterial.js
  54. 3 3
      dist/preview release/materialsLibrary/babylon.triPlanarMaterial.js
  55. 3 3
      dist/preview release/materialsLibrary/babylon.waterMaterial.js
  56. 3 3
      dist/preview release/materialsLibrary/babylonjs.materials.js
  57. 1 1
      dist/preview release/materialsLibrary/babylonjs.materials.min.js
  58. 2 2
      dist/preview release/materialsLibrary/package.json
  59. 138 48
      dist/preview release/nodeEditor/babylon.nodeEditor.d.ts
  60. 6 6
      dist/preview release/nodeEditor/babylon.nodeEditor.js
  61. 2267 2788
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js
  62. 1 1
      dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map
  63. 298 105
      dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts
  64. 2 2
      dist/preview release/nodeEditor/package.json
  65. 1 1
      dist/preview release/package.json
  66. 1 1
      dist/preview release/packagesSizeBaseLine.json
  67. 3 3
      dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.js
  68. 3 3
      dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.js
  69. 3 3
      dist/preview release/postProcessesLibrary/babylon.oceanPostProcess.js
  70. 3 3
      dist/preview release/postProcessesLibrary/babylonjs.postProcess.js
  71. 2 2
      dist/preview release/postProcessesLibrary/package.json
  72. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.brickProceduralTexture.js
  73. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.cloudProceduralTexture.js
  74. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.fireProceduralTexture.js
  75. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.grassProceduralTexture.js
  76. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.marbleProceduralTexture.js
  77. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.js
  78. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.perlinNoiseProceduralTexture.js
  79. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.roadProceduralTexture.js
  80. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.js
  81. 3 3
      dist/preview release/proceduralTexturesLibrary/babylon.woodProceduralTexture.js
  82. 3 3
      dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js
  83. 2 2
      dist/preview release/proceduralTexturesLibrary/package.json
  84. 309 80
      dist/preview release/serializers/babylon.glTF2Serializer.js
  85. 1 1
      dist/preview release/serializers/babylon.glTF2Serializer.js.map
  86. 2 2
      dist/preview release/serializers/babylon.glTF2Serializer.min.js
  87. 1 1
      dist/preview release/serializers/babylon.objSerializer.min.js
  88. 80 20
      dist/preview release/serializers/babylonjs.serializers.d.ts
  89. 318 83
      dist/preview release/serializers/babylonjs.serializers.js
  90. 1 1
      dist/preview release/serializers/babylonjs.serializers.js.map
  91. 2 2
      dist/preview release/serializers/babylonjs.serializers.min.js
  92. 173 46
      dist/preview release/serializers/babylonjs.serializers.module.d.ts
  93. 3 3
      dist/preview release/serializers/package.json
  94. 2439 203
      dist/preview release/viewer/babylon.module.d.ts
  95. 183 143
      dist/preview release/viewer/babylon.viewer.js
  96. 3 3
      dist/preview release/viewer/babylon.viewer.max.js
  97. 17 0
      dist/preview release/what's new.md
  98. 34 0
      gui/src/2D/controls/image.ts
  99. 57 13
      gui/src/2D/controls/sliders/imageScrollBar.ts
  100. 0 0
      gui/src/3D/controls/holographicButton.ts

+ 2 - 1
.vscode/settings.json

@@ -53,7 +53,8 @@
         "**/*.fragment.ts": true,
         "**/*.vertex.ts": true,
         "**/ShadersInclude/**/*.ts": true,
-        "assets": true
+        "assets": true,
+        "**/babylonWeb**": true,
     },
     "editor.tabSize": 4,
     "typescript.tsdk": "node_modules\\typescript\\lib",

+ 49 - 38
Playground/js/frame.js

@@ -1,11 +1,34 @@
 
-(function() {
+var engine = null;
+var canvas = null;
+var scene = null;
+
+fastEval = function(code) {
+    var head = document.getElementsByTagName('head')[0];
+    var script = document.createElement('script');
+    script.setAttribute('type', 'text/javascript');
+
+    script.innerHTML = `try {${code};}
+    catch(e) {
+        handleException(e);
+    }`;
+
+    head.appendChild(script);
+}
+
+handleException = function(e) {
+    console.error(e);
+}
+
+run = function() {
     var snippetUrl = "https://snippet.babylonjs.com";
-    var engine;
     var fpsLabel = document.getElementById("fpsLabel");
     var refreshAnchor = document.getElementById("refresh");
     var editAnchor = document.getElementById("edit");
 
+    var createEngineFunction = "createDefaultEngine";
+    var createSceneFunction;
+
     if (location.href.toLowerCase().indexOf("noui") > -1) {
         fpsLabel.style.visibility = "hidden";
         fpsLabel.style.display = "none";
@@ -17,10 +40,6 @@
 
     BABYLON.Engine.ShadersRepository = "/src/Shaders/";
 
-    var showError = function(error) {
-        utils.showError(error, null);
-    };
-
     compileAndRun = function(code) {
         try {
 
@@ -34,22 +53,18 @@
                 engine = null;
             }
 
-            var canvas = document.getElementById("renderCanvas");
-
-            var createEngineFunction = "createDefaultEngine";
-            var createSceneFunction;
+            canvas = document.getElementById("renderCanvas");
 
-            var createDefaultEngine = function() {
-                return new BABYLON.Engine(canvas, true, { stencil: true });
+            createDefaultEngine = function () {
+                return new BABYLON.Engine(canvas, true, { preserveDrawingBuffer: true, stencil: true });
             }
 
-            var scene;
-
             if (code.indexOf("createEngine") !== -1) {
                 createEngineFunction = "createEngine";
             }
 
-            if (code.indexOf("delayCreateScene") !== -1) { // createScene
+            // Check for different typos
+            if (code.indexOf("delayCreateScene") !== -1) { // delayCreateScene
                 createSceneFunction = "delayCreateScene";
                 checkCamera = false;
             } else if (code.indexOf("createScene") !== -1) { // createScene
@@ -61,37 +76,33 @@
             }
 
             if (!createSceneFunction) {
-                // just pasted code.
+                // Just pasted code.
                 engine = createDefaultEngine();
                 scene = new BABYLON.Scene(engine);
-                eval("runScript = function(scene, canvas) {" + code + "}");
+                var runScript = null;
+                fastEval("runScript = function(scene, canvas) {" + code + "}");
                 runScript(scene, canvas);
-
-                zipCode = "var scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
             } else {
-                //execute the code
-                eval(code);
-                //create engine
-                eval("engine = " + createEngineFunction + "()");
+                code += "\n engine = " + createEngineFunction + "();";
+                code += "\n if (!engine) throw 'engine should not be null.';";
+                code += "\n" + "scene = " + createSceneFunction + "();";
+
+                // Execute the code
+                fastEval(code);
+
                 if (!engine) {
-                    showError("createEngine function must return an engine.", null);
+                    console.error("createEngine function must return an engine.");
                     return;
                 }
 
-                //create scene
-                eval("scene = " + createSceneFunction + "()");
-
                 if (!scene) {
-                    showError(createSceneFunction + " function must return a scene.", null);
+                    console.error(createSceneFunction + " function must return a scene.");
                     return;
                 }
-
-                // update the scene code for the zip file
-                zipCode = code + "\r\n\r\nvar scene = " + createSceneFunction + "()";
             }
 
-            BABYLON.Camera.ForceAttachControlToAlwaysPreventDefault = true;
-            engine.runRenderLoop(function() {
+            engine = engine;
+            engine.runRenderLoop(function () {
                 if (engine.scenes.length === 0) {
                     return;
                 }
@@ -106,10 +117,8 @@
                     scene.render();
                 }
 
-                if (fpsLabel) {
-                    fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
-                }
-            });
+                fpsLabel.innerHTML = engine.getFps().toFixed() + " fps";
+            }.bind(this));         
 
         } catch (e) {
             // showError(e.message);
@@ -175,4 +184,6 @@
 
     checkHash();
 
-})();
+}
+
+run();

+ 8 - 7
Playground/js/main.js

@@ -1,5 +1,5 @@
 var engine = null;
-var canas = null;
+var canvas = null;
 var scene = null;
 var globalParent = null;
 
@@ -96,6 +96,9 @@ compileAndRun = function(parent, fpsLabel) {
 
                 parent.zipTool.ZipCode = "var engine = " + defaultEngineZip + ";\r\nvar scene = new BABYLON.Scene(engine);\r\n\r\n" + code;
             } else {
+                code += "\n engine = " + createEngineFunction + "();";
+                code += "\n if (!engine) throw 'engine should not be null.';";
+
                 if (parent.settingsPG.ScriptLanguage == "JS") {
                     code += "\n" + "scene = " + createSceneFunction + "();";
                 }
@@ -105,15 +108,13 @@ compileAndRun = function(parent, fpsLabel) {
                     code += "\n" + "scene = " + createSceneFunction + "();";
                 }
 
-                // Create engine
-                fastEval("engine = " + createEngineFunction + "()");
+                // Execute the code
+                fastEval(code);
+
                 if (!engine) {
                     parent.utils.showError("createEngine function must return an engine.", null);
                     return;
-                }                
-
-                // Execute the code
-                fastEval(code);
+                }
 
                 if (!scene) {
                     parent.utils.showError(createSceneFunction + " function must return a scene.", null);

+ 17 - 4
Playground/js/monacoCreator.js

@@ -54,10 +54,21 @@ class MonacoCreator {
      */
     async loadMonaco(typings) {
         let response = await fetch(typings || "https://preview.babylonjs.com/babylon.d.ts");
-        if (!response.ok)
+        if (!response.ok) {
             return;
+        }
+
+        let libContent = await response.text();
+
+        if (!typings) {
+            response = await fetch(typings || "https://preview.babylonjs.com/gui/babylon.gui.d.ts");
+            if (!response.ok) {
+                return;
+            }
+
+            libContent += await response.text();
+        }
 
-        const libContent = await response.text();
         this.setupDefinitionWorker(libContent);
 
         require.config({ paths: { 'vs': 'node_modules/monaco-editor/dev/vs' } });
@@ -290,11 +301,13 @@ class MonacoCreator {
         };
         editorOptions.minimap.enabled = document.getElementById("minimapToggle1280").classList.contains('checked');
         this.jsEditor = monaco.editor.create(document.getElementById('jsEditor'), editorOptions);
-
         this.jsEditor.setValue(oldCode);
+
+        const analyzeCodeDebounced = this.parent.utils.debounceAsync((async) => this.analyzeCode(), 500);
+
         this.jsEditor.onDidChangeModelContent(function () {
             this.parent.utils.markDirty();
-            this.analyzeCode();
+            analyzeCodeDebounced();
         }.bind(this));
     };
 

+ 65 - 0
Playground/js/utils.js

@@ -119,4 +119,69 @@ class Utils {
             if(document.getElementById("menuButton" + this.multipleSize[i]).offsetHeight > 0) return this.multipleSize[i];
         }
     };
+
+    debounceAsync(fn, wait = 0, options = {}) {
+        let lastCallAt
+        let deferred
+        let timer
+        let pendingArgs = []
+        return function debounced(...args) {
+            const currentWait = getWait(wait)
+            const currentTime = new Date().getTime()
+
+            const isCold = !lastCallAt || (currentTime - lastCallAt) > currentWait
+
+            lastCallAt = currentTime
+
+            if (isCold && options.leading) {
+                return options.accumulate
+                    ? Promise.resolve(fn.call(this, [args])).then(result => result[0])
+                    : Promise.resolve(fn.call(this, ...args))
+            }
+
+            if (deferred) {
+                clearTimeout(timer)
+            } else {
+                deferred = defer()
+            }
+
+            pendingArgs.push(args)
+            timer = setTimeout(flush.bind(this), currentWait)
+
+            if (options.accumulate) {
+                const argsIndex = pendingArgs.length - 1
+                return deferred.promise.then(results => results[argsIndex])
+            }
+
+            return deferred.promise
+        }
+
+        function getWait(wait) {
+            return (typeof wait === 'function') ? wait() : wait
+        }
+    
+        function defer() {
+            const deferred = {}
+            deferred.promise = new Promise((resolve, reject) => {
+                deferred.resolve = resolve
+                deferred.reject = reject
+            })
+            return deferred
+        }
+
+        function flush() {
+            const thisDeferred = deferred
+            clearTimeout(timer)
+
+            Promise.resolve(
+                options.accumulate
+                    ? fn.call(this, pendingArgs)
+                    : fn.apply(this, pendingArgs[pendingArgs.length - 1])
+            )
+                .then(thisDeferred.resolve, thisDeferred.reject)
+
+            pendingArgs = []
+            deferred = null
+        }
+    }    
 }

+ 639 - 0
Playground/scripts/spriteMap.js

@@ -0,0 +1,639 @@
+var createScene = function () {
+    var scene = new BABYLON.Scene(engine);
+    // Create camera and light
+    var light = new BABYLON.PointLight("Point", new BABYLON.Vector3(5, 10, 5), scene);
+    var camera = new BABYLON.FreeCamera("Camera", new BABYLON.Vector3(0, 0, -30), scene);
+    
+    // Attach the Controls to the canvas
+    camera.attachControl(canvas, true);
+    
+    // Load the JSON file, for simplicity in this demonstration it is included in-line.
+    let atlasJSON = getJSONFile();
+    
+    // Load the SpriteSheet Associated with the JSON Atlas.
+    let spriteSheet = new BABYLON.Texture('./textures/spriteMap/none_trimmed/Legends_Level_A.png', scene,
+    false, //NoMipMaps
+    false, //InvertY usually false if exported from TexturePacker
+    BABYLON.Texture.NEAREST_NEAREST, //Sampling Mode
+    null, //Onload, you could spin up the sprite map in a function nested here
+    null, //OnError
+    null, //CustomBuffer
+    false, //DeleteBuffer
+    BABYLON.Engine.TEXTURETYPE_RGBA //ImageFormageType RGBA
+    );
+    
+    spriteSheet.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;
+    spriteSheet.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE; //Or Wrap, its up to you...
+    
+    let backgroundSize = new BABYLON.Vector2(200,60);
+    
+    let background = new BABYLON.SpriteMap('background', atlasJSON, spriteSheet,
+    {
+        stageSize: backgroundSize,
+        maxAnimationFrames:8,
+        baseTile : 42,
+        layerCount: 2,
+        flipU: true, //Sometimes you gotta flip the depending on the sprite format.
+        colorMultiply : new BABYLON.Vector3(0.3,0.3,0.3)
+    },
+    scene);    
+    
+    //Set all the available tiles to the top left corner of the background for Visual debugging, and reference.
+    for(var i = 0; i<background.spriteCount; i++){
+        background.changeTiles(0, new BABYLON.Vector2(i + 1, backgroundSize.y - 1), i)
+    }
+
+    //TILE, FRAME, NEXT TILE, Timing, Speed
+    //See documentation for Animation Map Information. - TODO
+    let eighth = 1 / 8
+    let speed = 0.005
+    background.addAnimationToTile(1, 0, 2, eighth * 1, speed)
+    background.addAnimationToTile(1, 1, 3, eighth * 2, speed)
+    background.addAnimationToTile(1, 2, 4, eighth * 3, speed)
+    background.addAnimationToTile(1, 3, 5, eighth * 4, speed)
+    background.addAnimationToTile(1, 4, 6, eighth * 5, speed)
+    background.addAnimationToTile(1, 5, 7, eighth * 6, speed)
+    background.addAnimationToTile(1, 6, 8, eighth * 7, speed)
+    background.addAnimationToTile(1, 7, 1, 1, 	  	   speed)
+
+    background.addAnimationToTile(25, 0, 26, eighth * 1, speed)
+    background.addAnimationToTile(25, 1, 27, eighth * 2, speed)
+    background.addAnimationToTile(25, 2, 28, eighth * 3, speed)
+    background.addAnimationToTile(25, 3, 29, eighth * 4, speed)
+    background.addAnimationToTile(25, 4, 30, eighth * 5, speed)
+    background.addAnimationToTile(25, 5, 31, eighth * 6, speed)
+    background.addAnimationToTile(25, 6, 29, eighth * 7, speed)
+    background.addAnimationToTile(25, 7, 25, 1, 	 	 speed)
+
+    background.addAnimationToTile(48, 0, 49, 0.25, 	speed)
+    background.addAnimationToTile(48, 1, 50, 0.5, 	speed)
+    background.addAnimationToTile(48, 2, 51, 0.75, 	speed)
+    background.addAnimationToTile(48, 4, 48, 1, 	speed)
+
+    background.addAnimationToTile(49, 0, 50, 0.25, 	speed * 0.5)
+    background.addAnimationToTile(49, 1, 51, 0.5, 	speed * 0.5)
+    background.addAnimationToTile(49, 2, 48, 0.75, 	speed * 0.5)
+    background.addAnimationToTile(49, 4, 49, 1, 	speed * 0.5)
+
+    background.addAnimationToTile(50, 0, 51, 0.25,  speed * 0.3)
+    background.addAnimationToTile(50, 1, 48, 0.5,   speed * 0.3)
+    background.addAnimationToTile(50, 2, 49, 0.75,  speed * 0.3)
+    background.addAnimationToTile(50, 4, 50, 1, 	speed * 0.3)
+
+    background.position.z = 5;
+
+    //Procedurally Editing the Tiles
+    //Adding Water to BG
+    let tilePositions = []
+    for(let x = 15; x < backgroundSize.x - 15; x++){
+        for(let y = backgroundSize.y - 26; y > 0; y--){
+            if(x % 12 == 0){
+                tilePositions.push(new BABYLON.Vector2(x, y))
+            }
+        }
+    }
+    background.changeTiles(1, tilePositions, 1)
+    
+    //Adding Sewer Drains to BG
+    tilePositions = []
+    for(let x = 15; x < backgroundSize.x - 15; x++){
+        if(x % 12 == 0){
+            tilePositions.push(new BABYLON.Vector2(x, backgroundSize.y - 26))
+        }
+    }
+    background.changeTiles(1, tilePositions, 25)
+    
+    //More Water!
+    tilePositions = []
+    for(let x = 15; x < backgroundSize.x - 15; x++){
+        for(let y = backgroundSize.y - 12; y > 0; y--){
+            if((x + 6) % 12 == 0){
+                tilePositions.push(new BABYLON.Vector2(x, y))
+            }
+        }
+    }
+    
+    background.changeTiles(1, tilePositions, 1);
+
+    tilePositions = [];
+    
+    //Random Array for placing variations of the torches animation.
+    let pTiles = [48, 49, 50, 48, 49, 50, 48];
+    
+    //Making the Base of the level
+    let levelSize = new BABYLON.Vector2(80,40);
+    
+    let levelBase = new BABYLON.SpriteMap('base', atlasJSON, spriteSheet,
+    {
+        stageSize: levelSize,
+        maxAnimationFrames:8,
+        baseTile : 42,
+        layerCount: 2,
+        flipU: true,
+        colorMultiply : new BABYLON.Vector3(0.6,0.6,0.6)
+    },
+    scene);
+    
+    //Duplicating over the animation map from the background system.
+    levelBase.animationMap = background.animationMap
+    
+    
+    //Making a hole.
+    tilePositions = []
+    for(let x = 15; x < levelSize.x - 15; x++){
+        for(let y = levelSize.y - 15; y > 15; y--){
+            tilePositions.push(new BABYLON.Vector2(x, y))
+        }
+    }
+    levelBase.changeTiles(0, tilePositions, 0)
+
+    //Adding Columns
+    tilePositions = []
+    for(let x = 15; x < levelSize.x - 15; x++){
+        for(let y = levelSize.y - 16; y > 16; y--){
+            if(x % 6 == 0){
+                tilePositions.push(new BABYLON.Vector2(x, y))
+            }
+        }
+    }
+    levelBase.changeTiles(0, tilePositions, 23)
+
+    //Adding Torches
+    for(let x = 15; x < levelSize.x - 15; x++){
+        if((x + 6) % 12 == 0){
+            levelBase.changeTiles(1, new BABYLON.Vector2(x, 18),
+            pTiles[Math.floor(Math.random()*pTiles.length)])
+        }
+    }
+
+    //Adding Caps
+    tilePositions = []
+    for(let x =1 5; x < levelSize.x - 15; x++){
+        if(x % 6 == 0){
+         tilePositions.push(new BABYLON.Vector2(x, 16))
+        }
+    }
+    levelBase.changeTiles(0, tilePositions, 24)
+
+    //Adding Bases
+    tilePositions = []
+    for(let x = 15; x < levelSize.x - 15; x++){
+        if(x % 6 == 0){
+            tilePositions.push(new BABYLON.Vector2(x, 25))
+        }
+    }
+    levelBase.changeTiles(0, tilePositions, 22)
+
+    //Now this last section was created like all the last two, except it was later exported from the browser and saved.
+    //This shows how to load from the .tilemaps file
+       
+    levelStage = new BABYLON.SpriteMap('levelStage', atlasJSON, spriteSheet,
+    {
+        stageSize: levelSize,
+        maxAnimationFrames:8,
+        baseTile : 42,
+        layerCount: 2,
+        flipU: true
+    },
+    scene);
+
+    levelStage.loadTileMaps('./textures/spriteMap/none_trimmed/levelStage.tilemaps')
+    levelStage.animationMap = background.animationMap
+    levelStage.position.z = -5   
+
+    //To download .tilemaps file for this SpriteMap uncomment the below line.
+    //levelStage.saveTileMaps();
+	
+    return scene;
+}
+
+const getJSONFile = ()=>{
+    return {"frames": [
+{
+	"filename": "blank.png",
+	"frame": {"x":221,"y":221,"w":1,"h":1},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-0.png",
+	"frame": {"x":1,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-1.png",
+	"frame": {"x":1,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-2.png",
+	"frame": {"x":1,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-3.png",
+	"frame": {"x":1,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-4.png",
+	"frame": {"x":1,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-5.png",
+	"frame": {"x":1,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-6.png",
+	"frame": {"x":1,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-7.png",
+	"frame": {"x":1,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-0.png",
+	"frame": {"x":36,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-1.png",
+	"frame": {"x":71,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-2.png",
+	"frame": {"x":106,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-3.png",
+	"frame": {"x":141,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-0.png",
+	"frame": {"x":176,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-1.png",
+	"frame": {"x":211,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-2.png",
+	"frame": {"x":246,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-3.png",
+	"frame": {"x":36,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-0.png",
+	"frame": {"x":36,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-1.png",
+	"frame": {"x":36,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-2.png",
+	"frame": {"x":36,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-3.png",
+	"frame": {"x":36,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-0.png",
+	"frame": {"x":36,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-1.png",
+	"frame": {"x":36,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-2.png",
+	"frame": {"x":71,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-3.png",
+	"frame": {"x":106,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-0.png",
+	"frame": {"x":141,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-1.png",
+	"frame": {"x":176,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-2.png",
+	"frame": {"x":211,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-3.png",
+	"frame": {"x":246,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-4.png",
+	"frame": {"x":71,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-5.png",
+	"frame": {"x":71,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-6.png",
+	"frame": {"x":71,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-7.png",
+	"frame": {"x":71,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-0.png",
+	"frame": {"x":71,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-1.png",
+	"frame": {"x":71,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-2.png",
+	"frame": {"x":106,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-3.png",
+	"frame": {"x":106,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-4.png",
+	"frame": {"x":106,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-5.png",
+	"frame": {"x":106,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-6.png",
+	"frame": {"x":106,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-7.png",
+	"frame": {"x":141,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-8.png",
+	"frame": {"x":176,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-9.png",
+	"frame": {"x":211,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-10.png",
+	"frame": {"x":106,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-11.png",
+	"frame": {"x":141,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-12.png",
+	"frame": {"x":176,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-13.png",
+	"frame": {"x":211,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-14.png",
+	"frame": {"x":246,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-0.png",
+	"frame": {"x":246,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-1.png",
+	"frame": {"x":141,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-2.png",
+	"frame": {"x":141,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-3.png",
+	"frame": {"x":141,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+}],
+"meta": {
+	"app": "https://www.codeandweb.com/texturepacker",
+	"version": "1.0",
+	"image": "Legends_Level_A.png",
+	"format": "RGBA8888",
+	"size": {"w":279,"h":279},
+	"scale": "1",
+	"smartupdate": "$TexturePacker:SmartUpdate:a755ec93daaec56d1c8bcd801e167677:2e759c84cbaf9134b80c1a34b50e5c9c:9f820b9412efc8199e0407f80b8c0011$"
+}
+}
+
+}

+ 420 - 0
Playground/textures/spriteMap/none_trimmed/Legends_Level_A.json

@@ -0,0 +1,420 @@
+{"frames": [
+
+{
+	"filename": "Falling-Water-0.png",
+	"frame": {"x":1,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-1.png",
+	"frame": {"x":1,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-2.png",
+	"frame": {"x":1,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-3.png",
+	"frame": {"x":1,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-4.png",
+	"frame": {"x":1,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-5.png",
+	"frame": {"x":1,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-6.png",
+	"frame": {"x":1,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Falling-Water-7.png",
+	"frame": {"x":1,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-0.png",
+	"frame": {"x":36,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-1.png",
+	"frame": {"x":71,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-2.png",
+	"frame": {"x":106,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large-Column-Light-3.png",
+	"frame": {"x":141,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-0.png",
+	"frame": {"x":176,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-1.png",
+	"frame": {"x":211,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-2.png",
+	"frame": {"x":246,"y":1,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Large_Column-3.png",
+	"frame": {"x":36,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-0.png",
+	"frame": {"x":36,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-1.png",
+	"frame": {"x":36,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-2.png",
+	"frame": {"x":36,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman-Column-3.png",
+	"frame": {"x":36,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-0.png",
+	"frame": {"x":36,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-1.png",
+	"frame": {"x":36,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-2.png",
+	"frame": {"x":71,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Roman_Column_Light-3.png",
+	"frame": {"x":106,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-0.png",
+	"frame": {"x":141,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-1.png",
+	"frame": {"x":176,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-2.png",
+	"frame": {"x":211,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-3.png",
+	"frame": {"x":246,"y":36,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-4.png",
+	"frame": {"x":71,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-5.png",
+	"frame": {"x":71,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-6.png",
+	"frame": {"x":71,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Sewer-Drain-7.png",
+	"frame": {"x":71,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-0.png",
+	"frame": {"x":71,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-1.png",
+	"frame": {"x":71,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-2.png",
+	"frame": {"x":106,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-3.png",
+	"frame": {"x":106,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-4.png",
+	"frame": {"x":106,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-5.png",
+	"frame": {"x":106,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-6.png",
+	"frame": {"x":106,"y":246,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-7.png",
+	"frame": {"x":141,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-8.png",
+	"frame": {"x":176,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-9.png",
+	"frame": {"x":211,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-10.png",
+	"frame": {"x":106,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-11.png",
+	"frame": {"x":141,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-12.png",
+	"frame": {"x":176,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-13.png",
+	"frame": {"x":211,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Stone-Platform-14.png",
+	"frame": {"x":246,"y":71,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-0.png",
+	"frame": {"x":246,"y":106,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-1.png",
+	"frame": {"x":141,"y":141,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-2.png",
+	"frame": {"x":141,"y":176,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+},
+{
+	"filename": "Torch-A-3.png",
+	"frame": {"x":141,"y":211,"w":32,"h":32},
+	"rotated": false,
+	"trimmed": false,
+	"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
+	"sourceSize": {"w":32,"h":32}
+}],
+"meta": {
+	"app": "https://www.codeandweb.com/texturepacker",
+	"version": "1.0",
+	"image": "Legends_Level_A.png",
+	"format": "RGBA8888",
+	"size": {"w":279,"h":279},
+	"scale": "1",
+	"smartupdate": "$TexturePacker:SmartUpdate:a755ec93daaec56d1c8bcd801e167677:2e759c84cbaf9134b80c1a34b50e5c9c:9f820b9412efc8199e0407f80b8c0011$"
+}
+}

BIN
Playground/textures/spriteMap/none_trimmed/Legends_Level_A.png


File diff suppressed because it is too large
+ 2 - 0
Playground/textures/spriteMap/none_trimmed/levelStage.tilemaps


File diff suppressed because it is too large
+ 1225 - 105
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.js


File diff suppressed because it is too large
+ 2660 - 464
dist/preview release/babylon.max.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/babylon.max.js.map


File diff suppressed because it is too large
+ 2439 - 203
dist/preview release/babylon.module.d.ts


File diff suppressed because it is too large
+ 1314 - 126
dist/preview release/documentation.d.ts


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

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

+ 9 - 1
dist/preview release/gui/babylon.gui.d.ts

@@ -1501,6 +1501,8 @@ declare module BABYLON.GUI {
         autoScale: boolean;
         /** Gets or sets the streching mode used by the image */
         stretch: number;
+        /** @hidden */
+        _rotate90(n: number): Image;
         /**
          * Gets or sets the internal DOM image used to render the control
          */
@@ -2750,14 +2752,16 @@ declare module BABYLON.GUI {
      */
     export class ImageScrollBar extends BaseSlider {
         name?: string | undefined;
+        private _backgroundBaseImage;
         private _backgroundImage;
         private _thumbImage;
+        private _thumbBaseImage;
         private _thumbLength;
         private _thumbHeight;
         private _barImageHeight;
         private _tempMeasure;
         /**
-         * Gets or sets the image used to render the background
+         * Gets or sets the image used to render the background for horizontal bar
          */
         backgroundImage: Image;
         /**
@@ -3614,6 +3618,10 @@ declare module BABYLON.GUI {
         private _tooltipOutObserver;
         private _disposeTooltip;
         /**
+         * Rendering ground id of all the mesh in the button
+         */
+        renderingGroupId: number;
+        /**
          * Text to be displayed on the tooltip shown when hovering on the button. When set to null tooltip is disabled. (Default: null)
          */
         tooltipText: BABYLON.Nullable<string>;

+ 102 - 16
dist/preview release/gui/babylon.gui.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
@@ -6565,6 +6565,21 @@ var Image = /** @class */ (function (_super) {
         enumerable: true,
         configurable: true
     });
+    /** @hidden */
+    Image.prototype._rotate90 = function (n) {
+        var canvas = document.createElement('canvas');
+        var context = canvas.getContext('2d');
+        var width = this._domImage.width;
+        var height = this._domImage.height;
+        canvas.width = height;
+        canvas.height = width;
+        context.translate(canvas.width / 2, canvas.height / 2);
+        context.rotate(n * Math.PI / 2);
+        context.drawImage(this._domImage, 0, 0, width, height, -width / 2, -height / 2, width, height);
+        var dataUrl = canvas.toDataURL("image/jpg");
+        var rotatedImage = new Image(this.name + "rotated", dataUrl);
+        return rotatedImage;
+    };
     Object.defineProperty(Image.prototype, "domImage", {
         get: function () {
             return this._domImage;
@@ -6679,6 +6694,17 @@ var Image = /** @class */ (function (_super) {
             // check if object alr exist in document
             var svgExist = document.body.querySelector('object[data="' + svgsrc + '"]');
             if (svgExist) {
+                var svgDoc = svgExist.contentDocument;
+                // get viewbox width and height, get svg document width and height in px
+                if (svgDoc && svgDoc.documentElement) {
+                    var vb = svgDoc.documentElement.getAttribute("viewBox");
+                    var docwidth = Number(svgDoc.documentElement.getAttribute("width"));
+                    var docheight = Number(svgDoc.documentElement.getAttribute("height"));
+                    if (vb && docwidth && docheight) {
+                        this._getSVGAttribs(svgExist, elemid);
+                        return value;
+                    }
+                }
                 // wait for object to load
                 svgExist.addEventListener("load", function () {
                     _this._getSVGAttribs(svgExist, elemid);
@@ -10837,21 +10863,42 @@ var ImageScrollBar = /** @class */ (function (_super) {
     }
     Object.defineProperty(ImageScrollBar.prototype, "backgroundImage", {
         /**
-         * Gets or sets the image used to render the background
+         * Gets or sets the image used to render the background for horizontal bar
          */
         get: function () {
-            return this._backgroundImage;
+            return this._backgroundBaseImage;
         },
         set: function (value) {
             var _this = this;
-            if (this._backgroundImage === value) {
+            if (this._backgroundBaseImage === value) {
                 return;
             }
-            this._backgroundImage = value;
-            if (value && !value.isLoaded) {
-                value.onImageLoadedObservable.addOnce(function () { return _this._markAsDirty(); });
+            this._backgroundBaseImage = value;
+            if (this.isVertical) {
+                if (value && !value.isLoaded) {
+                    value.onImageLoadedObservable.addOnce(function () {
+                        var rotatedValue = value._rotate90(1);
+                        _this._backgroundImage = rotatedValue;
+                        if (!rotatedValue.isLoaded) {
+                            rotatedValue.onImageLoadedObservable.addOnce(function () {
+                                _this._markAsDirty();
+                            });
+                        }
+                        _this._markAsDirty();
+                    });
+                }
+                this._backgroundImage = value._rotate90(1);
+                this._markAsDirty();
+            }
+            else {
+                this._backgroundImage = value;
+                if (value && !value.isLoaded) {
+                    value.onImageLoadedObservable.addOnce(function () {
+                        _this._markAsDirty();
+                    });
+                }
+                this._markAsDirty();
             }
-            this._markAsDirty();
         },
         enumerable: true,
         configurable: true
@@ -10861,18 +10908,39 @@ var ImageScrollBar = /** @class */ (function (_super) {
          * Gets or sets the image used to render the thumb
          */
         get: function () {
-            return this._thumbImage;
+            return this._thumbBaseImage;
         },
         set: function (value) {
             var _this = this;
-            if (this._thumbImage === value) {
+            if (this._thumbBaseImage === value) {
                 return;
             }
-            this._thumbImage = value;
-            if (value && !value.isLoaded) {
-                value.onImageLoadedObservable.addOnce(function () { return _this._markAsDirty(); });
+            this._thumbBaseImage = value;
+            if (this.isVertical) {
+                if (value && !value.isLoaded) {
+                    value.onImageLoadedObservable.addOnce(function () {
+                        var rotatedValue = value._rotate90(-1);
+                        _this._thumbImage = rotatedValue;
+                        if (!rotatedValue.isLoaded) {
+                            rotatedValue.onImageLoadedObservable.addOnce(function () {
+                                _this._markAsDirty();
+                            });
+                        }
+                        _this._markAsDirty();
+                    });
+                }
+                this._thumbImage = value._rotate90(-1);
+                this._markAsDirty();
+            }
+            else {
+                this._thumbImage = value;
+                if (value && !value.isLoaded) {
+                    value.onImageLoadedObservable.addOnce(function () {
+                        _this._markAsDirty();
+                    });
+                }
+                this._markAsDirty();
             }
-            this._markAsDirty();
         },
         enumerable: true,
         configurable: true
@@ -14613,6 +14681,24 @@ var HolographicButton = /** @class */ (function (_super) {
         this.onPointerEnterObservable.remove(this._tooltipHoverObserver);
         this.onPointerOutObservable.remove(this._tooltipOutObserver);
     };
+    Object.defineProperty(HolographicButton.prototype, "renderingGroupId", {
+        get: function () {
+            return this._backPlate.renderingGroupId;
+        },
+        /**
+         * Rendering ground id of all the mesh in the button
+         */
+        set: function (id) {
+            this._backPlate.renderingGroupId = id;
+            this._textPlate.renderingGroupId = id;
+            this._frontPlate.renderingGroupId = id;
+            if (this._tooltipMesh) {
+                this._tooltipMesh.renderingGroupId = id;
+            }
+        },
+        enumerable: true,
+        configurable: true
+    });
     Object.defineProperty(HolographicButton.prototype, "tooltipText", {
         get: function () {
             if (this._tooltipTextBlock) {

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/gui/babylon.gui.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


+ 18 - 2
dist/preview release/gui/babylon.gui.module.d.ts

@@ -1545,6 +1545,8 @@ declare module "babylonjs-gui/2D/controls/image" {
         autoScale: boolean;
         /** Gets or sets the streching mode used by the image */
         stretch: number;
+        /** @hidden */
+        _rotate90(n: number): Image;
         /**
          * Gets or sets the internal DOM image used to render the control
          */
@@ -2868,14 +2870,16 @@ declare module "babylonjs-gui/2D/controls/sliders/imageScrollBar" {
      */
     export class ImageScrollBar extends BaseSlider {
         name?: string | undefined;
+        private _backgroundBaseImage;
         private _backgroundImage;
         private _thumbImage;
+        private _thumbBaseImage;
         private _thumbLength;
         private _thumbHeight;
         private _barImageHeight;
         private _tempMeasure;
         /**
-         * Gets or sets the image used to render the background
+         * Gets or sets the image used to render the background for horizontal bar
          */
         backgroundImage: Image;
         /**
@@ -3852,6 +3856,10 @@ declare module "babylonjs-gui/3D/controls/holographicButton" {
         private _tooltipOutObserver;
         private _disposeTooltip;
         /**
+         * Rendering ground id of all the mesh in the button
+         */
+        renderingGroupId: number;
+        /**
          * Text to be displayed on the tooltip shown when hovering on the button. When set to null tooltip is disabled. (Default: null)
          */
         tooltipText: Nullable<string>;
@@ -5528,6 +5536,8 @@ declare module BABYLON.GUI {
         autoScale: boolean;
         /** Gets or sets the streching mode used by the image */
         stretch: number;
+        /** @hidden */
+        _rotate90(n: number): Image;
         /**
          * Gets or sets the internal DOM image used to render the control
          */
@@ -6777,14 +6787,16 @@ declare module BABYLON.GUI {
      */
     export class ImageScrollBar extends BaseSlider {
         name?: string | undefined;
+        private _backgroundBaseImage;
         private _backgroundImage;
         private _thumbImage;
+        private _thumbBaseImage;
         private _thumbLength;
         private _thumbHeight;
         private _barImageHeight;
         private _tempMeasure;
         /**
-         * Gets or sets the image used to render the background
+         * Gets or sets the image used to render the background for horizontal bar
          */
         backgroundImage: Image;
         /**
@@ -7641,6 +7653,10 @@ declare module BABYLON.GUI {
         private _tooltipOutObserver;
         private _disposeTooltip;
         /**
+         * Rendering ground id of all the mesh in the button
+         */
+        renderingGroupId: number;
+        /**
          * Text to be displayed on the tooltip shown when hovering on the button. When set to null tooltip is disabled. (Default: null)
          */
         tooltipText: BABYLON.Nullable<string>;

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

@@ -4,7 +4,7 @@
     },
     "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.",
-    "version": "4.1.0-beta.4",
+    "version": "4.1.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.4"
+        "babylonjs": "4.1.0-beta.11"
     },
     "engines": {
         "node": "*"

File diff suppressed because it is too large
+ 8 - 8
dist/preview release/inspector/babylon.inspector.bundle.js


File diff suppressed because it is too large
+ 616 - 1696
dist/preview release/inspector/babylon.inspector.bundle.max.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/inspector/babylon.inspector.bundle.max.js.map


+ 22 - 1
dist/preview release/inspector/babylon.inspector.d.ts

@@ -33,6 +33,9 @@ declare module INSPECTOR {
         onInspectorClosedObservable: BABYLON.Observable<BABYLON.Scene>;
         onTabChangedObservable: BABYLON.Observable<number>;
         onPluginActivatedObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>>;
+        sceneImportDefaults: {
+            [key: string]: any;
+        };
         validationResults: BABYLON.GLTF2.IGLTFValidationResults;
         onValidationResultsUpdatedObservable: BABYLON.Observable<BABYLON.GLTF2.IGLTFValidationResults>;
         onExtensionLoadedObservable: BABYLON.Observable<BABYLON.IGLTFLoaderExtension>;
@@ -1299,6 +1302,7 @@ declare module INSPECTOR {
         constructor(props: INodeMaterialPropertyGridComponentProps);
         edit(): void;
         renderTextures(): JSX.Element | null;
+        renderInputBlock(block: BABYLON.InputBlock): JSX.Element | null;
         renderInputValues(): JSX.Element | null;
         render(): JSX.Element;
     }
@@ -1377,6 +1381,20 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    interface IFileMultipleButtonLineComponentProps {
+        label: string;
+        onClick: (event: any) => void;
+        accept: string;
+    }
+    export class FileMultipleButtonLineComponent extends React.Component<IFileMultipleButtonLineComponentProps> {
+        private static _IDGenerator;
+        private _id;
+        constructor(props: IFileMultipleButtonLineComponentProps);
+        onChange(evt: any): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     export class ToolsTabComponent extends PaneComponent {
         private _videoRecorder;
         private _screenShotSize;
@@ -1388,6 +1406,7 @@ declare module INSPECTOR {
         captureScreenshot(): void;
         captureRender(): void;
         recordVideo(): void;
+        importAnimations(event: any): void;
         shouldExport(node: BABYLON.Node): boolean;
         exportGLTF(): void;
         exportBabylon(): void;
@@ -1414,6 +1433,7 @@ declare module INSPECTOR {
         onPopup?: () => void;
         onClose?: () => void;
         globalState?: GlobalState;
+        initialTab?: BABYLON.DebugLayerTab;
     }
     export class ActionTabsComponent extends React.Component<IActionTabsComponentProps, {
         selectedEntity: any;
@@ -1486,7 +1506,7 @@ declare module INSPECTOR {
     export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, {
         isActive: boolean;
     }> {
-        private _onActiveCameraObserver;
+        private _onBeforeRenderObserver;
         constructor(props: ICameraTreeItemComponentProps);
         setActive(): void;
         componentDidMount(): void;
@@ -1795,6 +1815,7 @@ declare module INSPECTOR {
         onClose: () => void;
         onPopup: () => void;
         extensibilityGroups?: BABYLON.IExplorerExtensibilityGroup[];
+        initialTab?: BABYLON.DebugLayerTab;
     }
     export class EmbedHostComponent extends React.Component<IEmbedHostComponentProps> {
         private _once;

+ 48 - 3
dist/preview release/inspector/babylon.inspector.module.d.ts

@@ -44,6 +44,9 @@ declare module "babylonjs-inspector/components/globalState" {
         onInspectorClosedObservable: Observable<Scene>;
         onTabChangedObservable: Observable<number>;
         onPluginActivatedObserver: Nullable<Observer<ISceneLoaderPlugin | ISceneLoaderPluginAsync>>;
+        sceneImportDefaults: {
+            [key: string]: any;
+        };
         validationResults: IGLTFValidationResults;
         onValidationResultsUpdatedObservable: Observable<IGLTFValidationResults>;
         onExtensionLoadedObservable: Observable<IGLTFLoaderExtension>;
@@ -1675,6 +1678,7 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/mat
     import { PropertyChangedEvent } from "babylonjs-inspector/components/propertyChangedEvent";
     import { LockObject } from "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/lockObject";
     import { GlobalState } from "babylonjs-inspector/components/globalState";
+    import { InputBlock } from 'babylonjs/Materials/Node/Blocks/Input/inputBlock';
     interface INodeMaterialPropertyGridComponentProps {
         globalState: GlobalState;
         material: NodeMaterial;
@@ -1687,6 +1691,7 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/propertyGrids/mat
         constructor(props: INodeMaterialPropertyGridComponentProps);
         edit(): void;
         renderTextures(): JSX.Element | null;
+        renderInputBlock(block: InputBlock): JSX.Element | null;
         renderInputValues(): JSX.Element | null;
         render(): JSX.Element;
     }
@@ -1778,6 +1783,21 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/tools/gltfCompone
         render(): JSX.Element;
     }
 }
+declare module "babylonjs-inspector/components/actionTabs/lines/fileMultipleButtonLineComponent" {
+    import * as React from "react";
+    interface IFileMultipleButtonLineComponentProps {
+        label: string;
+        onClick: (event: any) => void;
+        accept: string;
+    }
+    export class FileMultipleButtonLineComponent extends React.Component<IFileMultipleButtonLineComponentProps> {
+        private static _IDGenerator;
+        private _id;
+        constructor(props: IFileMultipleButtonLineComponentProps);
+        onChange(evt: any): void;
+        render(): JSX.Element;
+    }
+}
 declare module "babylonjs-inspector/components/actionTabs/tabs/toolsTabComponent" {
     import { PaneComponent, IPaneComponentProps } from "babylonjs-inspector/components/actionTabs/paneComponent";
     import { Node } from "babylonjs/node";
@@ -1792,6 +1812,7 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/toolsTabComponent
         captureScreenshot(): void;
         captureRender(): void;
         recordVideo(): void;
+        importAnimations(event: any): void;
         shouldExport(node: Node): boolean;
         exportGLTF(): void;
         exportBabylon(): void;
@@ -1811,6 +1832,7 @@ declare module "babylonjs-inspector/components/actionTabs/tabs/settingsTabCompon
 declare module "babylonjs-inspector/components/actionTabs/actionTabsComponent" {
     import * as React from "react";
     import { Scene } from "babylonjs/scene";
+    import { DebugLayerTab } from "babylonjs/Debug/debugLayer";
     import { GlobalState } from "babylonjs-inspector/components/globalState";
     interface IActionTabsComponentProps {
         scene?: Scene;
@@ -1822,6 +1844,7 @@ declare module "babylonjs-inspector/components/actionTabs/actionTabsComponent" {
         onPopup?: () => void;
         onClose?: () => void;
         globalState?: GlobalState;
+        initialTab?: DebugLayerTab;
     }
     export class ActionTabsComponent extends React.Component<IActionTabsComponentProps, {
         selectedEntity: any;
@@ -1904,7 +1927,7 @@ declare module "babylonjs-inspector/components/sceneExplorer/entities/cameraTree
     export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, {
         isActive: boolean;
     }> {
-        private _onActiveCameraObserver;
+        private _onBeforeRenderObserver;
         constructor(props: ICameraTreeItemComponentProps);
         setActive(): void;
         componentDidMount(): void;
@@ -2263,7 +2286,7 @@ declare module "babylonjs-inspector/components/embedHost/embedHostComponent" {
     import * as React from "react";
     import { Scene } from "babylonjs/scene";
     import { GlobalState } from "babylonjs-inspector/components/globalState";
-    import { IExplorerExtensibilityGroup } from 'babylonjs/Debug/debugLayer';
+    import { IExplorerExtensibilityGroup, DebugLayerTab } from 'babylonjs/Debug/debugLayer';
     interface IEmbedHostComponentProps {
         scene: Scene;
         globalState: GlobalState;
@@ -2273,6 +2296,7 @@ declare module "babylonjs-inspector/components/embedHost/embedHostComponent" {
         onClose: () => void;
         onPopup: () => void;
         extensibilityGroups?: IExplorerExtensibilityGroup[];
+        initialTab?: DebugLayerTab;
     }
     export class EmbedHostComponent extends React.Component<IEmbedHostComponentProps> {
         private _once;
@@ -2362,6 +2386,9 @@ declare module INSPECTOR {
         onInspectorClosedObservable: BABYLON.Observable<BABYLON.Scene>;
         onTabChangedObservable: BABYLON.Observable<number>;
         onPluginActivatedObserver: BABYLON.Nullable<BABYLON.Observer<BABYLON.ISceneLoaderPlugin | BABYLON.ISceneLoaderPluginAsync>>;
+        sceneImportDefaults: {
+            [key: string]: any;
+        };
         validationResults: BABYLON.GLTF2.IGLTFValidationResults;
         onValidationResultsUpdatedObservable: BABYLON.Observable<BABYLON.GLTF2.IGLTFValidationResults>;
         onExtensionLoadedObservable: BABYLON.Observable<BABYLON.IGLTFLoaderExtension>;
@@ -3628,6 +3655,7 @@ declare module INSPECTOR {
         constructor(props: INodeMaterialPropertyGridComponentProps);
         edit(): void;
         renderTextures(): JSX.Element | null;
+        renderInputBlock(block: BABYLON.InputBlock): JSX.Element | null;
         renderInputValues(): JSX.Element | null;
         render(): JSX.Element;
     }
@@ -3706,6 +3734,20 @@ declare module INSPECTOR {
     }
 }
 declare module INSPECTOR {
+    interface IFileMultipleButtonLineComponentProps {
+        label: string;
+        onClick: (event: any) => void;
+        accept: string;
+    }
+    export class FileMultipleButtonLineComponent extends React.Component<IFileMultipleButtonLineComponentProps> {
+        private static _IDGenerator;
+        private _id;
+        constructor(props: IFileMultipleButtonLineComponentProps);
+        onChange(evt: any): void;
+        render(): JSX.Element;
+    }
+}
+declare module INSPECTOR {
     export class ToolsTabComponent extends PaneComponent {
         private _videoRecorder;
         private _screenShotSize;
@@ -3717,6 +3759,7 @@ declare module INSPECTOR {
         captureScreenshot(): void;
         captureRender(): void;
         recordVideo(): void;
+        importAnimations(event: any): void;
         shouldExport(node: BABYLON.Node): boolean;
         exportGLTF(): void;
         exportBabylon(): void;
@@ -3743,6 +3786,7 @@ declare module INSPECTOR {
         onPopup?: () => void;
         onClose?: () => void;
         globalState?: GlobalState;
+        initialTab?: BABYLON.DebugLayerTab;
     }
     export class ActionTabsComponent extends React.Component<IActionTabsComponentProps, {
         selectedEntity: any;
@@ -3815,7 +3859,7 @@ declare module INSPECTOR {
     export class CameraTreeItemComponent extends React.Component<ICameraTreeItemComponentProps, {
         isActive: boolean;
     }> {
-        private _onActiveCameraObserver;
+        private _onBeforeRenderObserver;
         constructor(props: ICameraTreeItemComponentProps);
         setActive(): void;
         componentDidMount(): void;
@@ -4124,6 +4168,7 @@ declare module INSPECTOR {
         onClose: () => void;
         onPopup: () => void;
         extensibilityGroups?: BABYLON.IExplorerExtensibilityGroup[];
+        initialTab?: BABYLON.DebugLayerTab;
     }
     export class EmbedHostComponent extends React.Component<IEmbedHostComponentProps> {
         private _once;

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

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

+ 3 - 3
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 2 - 2
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -2153,8 +2153,8 @@ var GLTFLoader = /** @class */ (function () {
     GLTFLoader.prototype._checkExtensions = function () {
         if (this._gltf.extensionsRequired) {
             var _loop_1 = function (name_3) {
-                var extension = this_1._extensions.find(function (extension) { return extension.name === name_3; });
-                if (!extension || !extension.enabled) {
+                var available = this_1._extensions.some(function (extension) { return extension.name === name_3 && extension.enabled; });
+                if (!available) {
                     throw new Error("Require extension " + name_3 + " is not available");
                 }
             };

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 5 - 5
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
@@ -4713,8 +4713,8 @@ var GLTFLoader = /** @class */ (function () {
     GLTFLoader.prototype._checkExtensions = function () {
         if (this._gltf.extensionsRequired) {
             var _loop_1 = function (name_3) {
-                var extension = this_1._extensions.find(function (extension) { return extension.name === name_3; });
-                if (!extension || !extension.enabled) {
+                var available = this_1._extensions.some(function (extension) { return extension.name === name_3 && extension.enabled; });
+                if (!available) {
                     throw new Error("Require extension " + name_3 + " is not available");
                 }
             };

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 5 - 5
dist/preview release/loaders/babylonjs.loaders.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
@@ -6046,8 +6046,8 @@ var GLTFLoader = /** @class */ (function () {
     GLTFLoader.prototype._checkExtensions = function () {
         if (this._gltf.extensionsRequired) {
             var _loop_1 = function (name_3) {
-                var extension = this_1._extensions.find(function (extension) { return extension.name === name_3; });
-                if (!extension || !extension.enabled) {
+                var available = this_1._extensions.some(function (extension) { return extension.name === name_3 && extension.enabled; });
+                if (!available) {
                     throw new Error("Require extension " + name_3 + " is not available");
                 }
             };

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.js.map


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/loaders/babylonjs.loaders.min.js


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

@@ -4,7 +4,7 @@
     },
     "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.",
-    "version": "4.1.0-beta.4",
+    "version": "4.1.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,8 +28,8 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs-gltf2interface": "4.1.0-beta.4",
-        "babylonjs": "4.1.0-beta.4"
+        "babylonjs-gltf2interface": "4.1.0-beta.11",
+        "babylonjs": "4.1.0-beta.11"
     },
     "engines": {
         "node": "*"

+ 3 - 3
dist/preview release/materialsLibrary/babylon.cellMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.customMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/materialsLibrary/babylon.customMaterial.min.js


+ 3 - 3
dist/preview release/materialsLibrary/babylon.fireMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.furMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.gradientMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.gridMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.lavaMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.mixMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.normalMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.shadowOnlyMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.simpleMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.skyMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.terrainMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.triPlanarMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylon.waterMaterial.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/materialsLibrary/babylonjs.materials.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

File diff suppressed because it is too large
+ 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",
     "description": "The Babylon.js materials library is a collection of advanced materials to be used in a Babylon.js scene.",
-    "version": "4.1.0-beta.4",
+    "version": "4.1.0-beta.11",
     "repository": {
         "type": "git",
         "url": "https://github.com/BabylonJS/Babylon.js.git"
@@ -28,7 +28,7 @@
     ],
     "license": "Apache-2.0",
     "dependencies": {
-        "babylonjs": "4.1.0-beta.4"
+        "babylonjs": "4.1.0-beta.11"
     },
     "engines": {
         "node": "*"

+ 138 - 48
dist/preview release/nodeEditor/babylon.nodeEditor.d.ts

@@ -46,6 +46,15 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    export interface IDisplayManager {
+        getHeaderClass(block: BABYLON.NodeMaterialBlock): string;
+        shouldDisplayPortLabels(block: BABYLON.NodeMaterialBlock): boolean;
+        updatePreviewContent(block: BABYLON.NodeMaterialBlock, contentArea: HTMLDivElement): void;
+        getBackgroundColor(block: BABYLON.NodeMaterialBlock): string;
+        getHeaderText(block: BABYLON.NodeMaterialBlock): string;
+    }
+}
+declare module NODEEDITOR {
     export class NodePort {
         connectionPoint: BABYLON.NodeMaterialConnectionPoint;
         node: GraphNode;
@@ -53,10 +62,88 @@ declare module NODEEDITOR {
         private _img;
         private _globalState;
         private _onCandidateLinkMovedObserver;
+        delegatedPort: BABYLON.Nullable<NodePort>;
         readonly element: HTMLDivElement;
         refresh(): void;
         constructor(portContainer: HTMLElement, connectionPoint: BABYLON.NodeMaterialConnectionPoint, node: GraphNode, globalState: GlobalState);
         dispose(): void;
+        static CreatePortElement(connectionPoint: BABYLON.NodeMaterialConnectionPoint, node: GraphNode, root: HTMLElement, displayManager: BABYLON.Nullable<IDisplayManager>, globalState: GlobalState): NodePort;
+    }
+}
+declare module NODEEDITOR {
+    export interface INodeLocationInfo {
+        blockId: number;
+        x: number;
+        y: number;
+    }
+    export interface IFrameData {
+        x: number;
+        y: number;
+        width: number;
+        height: number;
+        color: number[];
+        name: string;
+        isCollapsed: boolean;
+    }
+    export interface IEditorData {
+        locations: INodeLocationInfo[];
+        x: number;
+        y: number;
+        zoom: number;
+        frames?: IFrameData[];
+    }
+}
+declare module NODEEDITOR {
+    export class GraphFrame {
+        private _name;
+        private _color;
+        private _x;
+        private _y;
+        private _gridAlignedX;
+        private _gridAlignedY;
+        private _width;
+        private _height;
+        element: HTMLDivElement;
+        private _headerElement;
+        private _headerTextElement;
+        private _headerCollapseElement;
+        private _headerCloseElement;
+        private _portContainer;
+        private _outputPortContainer;
+        private _inputPortContainer;
+        private _nodes;
+        private _ownerCanvas;
+        private _mouseStartPointX;
+        private _mouseStartPointY;
+        private _onSelectionChangedObserver;
+        private _isCollapsed;
+        private _ports;
+        private _controlledPorts;
+        private readonly CloseSVG;
+        private readonly ExpandSVG;
+        private readonly CollapseSVG;
+        isCollapsed: boolean;
+        private _createInputPort;
+        readonly nodes: GraphNode[];
+        name: string;
+        color: BABYLON.Color3;
+        x: number;
+        y: number;
+        width: number;
+        height: number;
+        constructor(candidate: BABYLON.Nullable<HTMLDivElement>, canvas: GraphCanvasComponent, doNotCaptureNodes?: boolean);
+        refresh(): void;
+        addNode(node: GraphNode): void;
+        removeNode(node: GraphNode): void;
+        syncNode(node: GraphNode): void;
+        cleanAccumulation(): void;
+        private _onDown;
+        private _onUp;
+        private _moveFrame;
+        private _onMove;
+        dispose(): void;
+        serialize(): IFrameData;
+        static Parse(serializationData: IFrameData, canvas: GraphCanvasComponent): GraphFrame;
     }
 }
 declare module NODEEDITOR {
@@ -69,8 +156,13 @@ declare module NODEEDITOR {
         private _path;
         private _selectionPath;
         private _onSelectionChangedObserver;
+        private _isVisible;
+        onDisposedObservable: BABYLON.Observable<NodeLink>;
+        isVisible: boolean;
         readonly portA: NodePort;
         readonly portB: NodePort | undefined;
+        readonly nodeA: GraphNode;
+        readonly nodeB: GraphNode | undefined;
         update(endX?: number, endY?: number, straight?: boolean): void;
         constructor(graphCanvas: GraphCanvasComponent, portA: NodePort, nodeA: GraphNode, portB?: NodePort, nodeB?: GraphNode);
         onClick(): void;
@@ -87,6 +179,7 @@ declare module NODEEDITOR {
         private _hostCanvas;
         private _graphCanvas;
         private _selectionContainer;
+        private _frameContainer;
         private _svgCanvas;
         private _rootContainer;
         private _nodes;
@@ -106,22 +199,31 @@ declare module NODEEDITOR {
         private _candidatePort;
         private _gridSize;
         private _selectionBox;
+        private _selectedFrame;
+        private _frameCandidate;
+        private _frames;
         private _altKeyIsPressed;
         private _ctrlKeyIsPressed;
         private _oldY;
+        _frameIsMoving: boolean;
         gridSize: number;
         readonly globalState: GlobalState;
         readonly nodes: GraphNode[];
         readonly links: NodeLink[];
+        readonly frames: GraphFrame[];
         zoom: number;
         x: number;
         y: number;
         readonly selectedNodes: GraphNode[];
         readonly selectedLink: BABYLON.Nullable<NodeLink>;
+        readonly selectedFrame: BABYLON.Nullable<GraphFrame>;
         readonly canvasContainer: HTMLDivElement;
         readonly svgCanvas: HTMLElement;
+        readonly selectionContainer: HTMLDivElement;
+        readonly frameContainer: HTMLDivElement;
         constructor(props: IGraphCanvasComponentProps);
-        getGridPosition(position: number): number;
+        getGridPosition(position: number, useCeil?: boolean): number;
+        getGridPositionCeil(position: number): number;
         updateTransform(): void;
         onKeyUp(): void;
         findNodeFromBlock(block: BABYLON.NodeMaterialBlock): GraphNode;
@@ -137,6 +239,7 @@ declare module NODEEDITOR {
         onWheel(evt: React.WheelEvent): void;
         zoomToFit(): void;
         processCandidatePort(): void;
+        processEditorData(editorData: IEditorData): void;
         render(): JSX.Element;
     }
 }
@@ -477,6 +580,12 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    export interface IPropertyComponentProps {
+        globalState: GlobalState;
+        block: BABYLON.NodeMaterialBlock;
+    }
+}
+declare module NODEEDITOR {
     interface ITextInputLineComponentProps {
         label: string;
         globalState: GlobalState;
@@ -515,25 +624,9 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
-    export class StringTools {
-        private static _SaveAs;
-        private static _Click;
-        /**
-         * Gets the base math type of node material block connection point.
-         * @param type Type to parse.
-         */
-        static GetBaseType(type: BABYLON.NodeMaterialBlockConnectionPointTypes): string;
-        /**
-         * Download a string into a file that will be saved locally by the browser
-         * @param content defines the string to download locally as a file
-         */
-        static DownloadAsFile(document: HTMLDocument, content: string, filename: string): void;
-    }
-}
-declare module NODEEDITOR {
-    export interface IPropertyComponentProps {
-        globalState: GlobalState;
-        block: BABYLON.NodeMaterialBlock;
+    export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
+        constructor(props: IPropertyComponentProps);
+        render(): JSX.Element;
     }
 }
 declare module NODEEDITOR {
@@ -696,18 +789,19 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
-    export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
-        constructor(props: IPropertyComponentProps);
-        render(): JSX.Element;
-    }
-}
-declare module NODEEDITOR {
-    export interface IDisplayManager {
-        getHeaderClass(block: BABYLON.NodeMaterialBlock): string;
-        shouldDisplayPortLabels(block: BABYLON.NodeMaterialBlock): boolean;
-        updatePreviewContent(block: BABYLON.NodeMaterialBlock, contentArea: HTMLDivElement): void;
-        getBackgroundColor(block: BABYLON.NodeMaterialBlock): string;
-        getHeaderText(block: BABYLON.NodeMaterialBlock): string;
+    export class StringTools {
+        private static _SaveAs;
+        private static _Click;
+        /**
+         * Gets the base math type of node material block connection point.
+         * @param type Type to parse.
+         */
+        static GetBaseType(type: BABYLON.NodeMaterialBlockConnectionPointTypes): string;
+        /**
+         * Download a string into a file that will be saved locally by the browser
+         * @param content defines the string to download locally as a file
+         */
+        static DownloadAsFile(document: HTMLDocument, content: string, filename: string): void;
     }
 }
 declare module NODEEDITOR {
@@ -823,6 +917,7 @@ declare module NODEEDITOR {
         private _inputsContainer;
         private _outputsContainer;
         private _content;
+        private _comments;
         private _inputPorts;
         private _outputPorts;
         private _links;
@@ -835,10 +930,15 @@ declare module NODEEDITOR {
         private _globalState;
         private _onSelectionChangedObserver;
         private _onSelectionBoxMovedObserver;
+        private _onFrameCreatedObserver;
         private _onUpdateRequiredObserver;
         private _ownerCanvas;
         private _isSelected;
         private _displayManager;
+        private _isVisible;
+        isVisible: boolean;
+        readonly outputPorts: NodePort[];
+        readonly inputPorts: NodePort[];
         readonly links: NodeLink[];
         readonly gridAlignedX: number;
         readonly gridAlignedY: number;
@@ -850,13 +950,14 @@ declare module NODEEDITOR {
         readonly name: string;
         isSelected: boolean;
         constructor(block: BABYLON.NodeMaterialBlock, globalState: GlobalState);
+        isOverlappingFrame(frame: GraphFrame): boolean;
         getPortForConnectionPoint(point: BABYLON.NodeMaterialConnectionPoint): BABYLON.Nullable<NodePort>;
         getLinksForConnectionPoint(point: BABYLON.NodeMaterialConnectionPoint): NodeLink[];
+        private _refreshFrames;
         private _refreshLinks;
         refresh(): void;
-        private _appendConnection;
         private _onDown;
-        cleanAccumulation(): void;
+        cleanAccumulation(useCeil?: boolean): void;
         private _onUp;
         private _onMove;
         renderProperties(): BABYLON.Nullable<JSX.Element>;
@@ -869,7 +970,7 @@ declare module NODEEDITOR {
         nodeMaterial: BABYLON.NodeMaterial;
         hostElement: HTMLElement;
         hostDocument: HTMLDocument;
-        onSelectionChangedObservable: BABYLON.Observable<BABYLON.Nullable<GraphNode | NodeLink>>;
+        onSelectionChangedObservable: BABYLON.Observable<BABYLON.Nullable<GraphNode | GraphFrame | NodeLink>>;
         onRebuildRequiredObservable: BABYLON.Observable<void>;
         onResetRequiredObservable: BABYLON.Observable<void>;
         onUpdateRequiredObservable: BABYLON.Observable<void>;
@@ -886,6 +987,7 @@ declare module NODEEDITOR {
         onAnimationCommandActivated: BABYLON.Observable<void>;
         onCandidateLinkMoved: BABYLON.Observable<BABYLON.Nullable<BABYLON.Vector2>>;
         onSelectionBoxMoved: BABYLON.Observable<ClientRect | DOMRect>;
+        onFrameCreated: BABYLON.Observable<GraphFrame>;
         onCandidatePortSelected: BABYLON.Observable<BABYLON.Nullable<NodePort>>;
         onGetNodeFromBlock: (block: BABYLON.NodeMaterialBlock) => GraphNode;
         onGridSizeChanged: BABYLON.Observable<void>;
@@ -944,6 +1046,7 @@ declare module NODEEDITOR {
     }
     export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, {
         currentNode: BABYLON.Nullable<GraphNode>;
+        currentFrame: BABYLON.Nullable<GraphFrame>;
     }> {
         constructor(props: IPropertyTabComponentProps);
         componentDidMount(): void;
@@ -1003,19 +1106,6 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
-    export interface INodeLocationInfo {
-        blockId: number;
-        x: number;
-        y: number;
-    }
-    export interface IEditorData {
-        locations: INodeLocationInfo[];
-        x: number;
-        y: number;
-        zoom: number;
-    }
-}
-declare module NODEEDITOR {
     interface IPreviewMeshControlComponent {
         globalState: GlobalState;
     }

File diff suppressed because it is too large
+ 6 - 6
dist/preview release/nodeEditor/babylon.nodeEditor.js


File diff suppressed because it is too large
+ 2267 - 2788
dist/preview release/nodeEditor/babylon.nodeEditor.max.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/nodeEditor/babylon.nodeEditor.max.js.map


+ 298 - 105
dist/preview release/nodeEditor/babylon.nodeEditor.module.d.ts

@@ -109,10 +109,22 @@ declare module "babylonjs-node-editor/components/preview/previewMeshType" {
         Custom = 6
     }
 }
+declare module "babylonjs-node-editor/diagram/display/displayManager" {
+    import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
+    export interface IDisplayManager {
+        getHeaderClass(block: NodeMaterialBlock): string;
+        shouldDisplayPortLabels(block: NodeMaterialBlock): boolean;
+        updatePreviewContent(block: NodeMaterialBlock, contentArea: HTMLDivElement): void;
+        getBackgroundColor(block: NodeMaterialBlock): string;
+        getHeaderText(block: NodeMaterialBlock): string;
+    }
+}
 declare module "babylonjs-node-editor/diagram/nodePort" {
-    import { GraphNode } from "babylonjs-node-editor/diagram/graphNode";
     import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
     import { GlobalState } from "babylonjs-node-editor/globalState";
+    import { Nullable } from 'babylonjs/types';
+    import { IDisplayManager } from "babylonjs-node-editor/diagram/display/displayManager";
+    import { GraphNode } from "babylonjs-node-editor/diagram/graphNode";
     export class NodePort {
         connectionPoint: NodeMaterialConnectionPoint;
         node: GraphNode;
@@ -120,16 +132,100 @@ declare module "babylonjs-node-editor/diagram/nodePort" {
         private _img;
         private _globalState;
         private _onCandidateLinkMovedObserver;
+        delegatedPort: Nullable<NodePort>;
         readonly element: HTMLDivElement;
         refresh(): void;
         constructor(portContainer: HTMLElement, connectionPoint: NodeMaterialConnectionPoint, node: GraphNode, globalState: GlobalState);
         dispose(): void;
+        static CreatePortElement(connectionPoint: NodeMaterialConnectionPoint, node: GraphNode, root: HTMLElement, displayManager: Nullable<IDisplayManager>, globalState: GlobalState): NodePort;
+    }
+}
+declare module "babylonjs-node-editor/nodeLocationInfo" {
+    export interface INodeLocationInfo {
+        blockId: number;
+        x: number;
+        y: number;
+    }
+    export interface IFrameData {
+        x: number;
+        y: number;
+        width: number;
+        height: number;
+        color: number[];
+        name: string;
+        isCollapsed: boolean;
+    }
+    export interface IEditorData {
+        locations: INodeLocationInfo[];
+        x: number;
+        y: number;
+        zoom: number;
+        frames?: IFrameData[];
+    }
+}
+declare module "babylonjs-node-editor/diagram/graphFrame" {
+    import { GraphNode } from "babylonjs-node-editor/diagram/graphNode";
+    import { GraphCanvasComponent } from "babylonjs-node-editor/diagram/graphCanvas";
+    import { Nullable } from 'babylonjs/types';
+    import { IFrameData } from "babylonjs-node-editor/nodeLocationInfo";
+    import { Color3 } from 'babylonjs/Maths/math.color';
+    export class GraphFrame {
+        private _name;
+        private _color;
+        private _x;
+        private _y;
+        private _gridAlignedX;
+        private _gridAlignedY;
+        private _width;
+        private _height;
+        element: HTMLDivElement;
+        private _headerElement;
+        private _headerTextElement;
+        private _headerCollapseElement;
+        private _headerCloseElement;
+        private _portContainer;
+        private _outputPortContainer;
+        private _inputPortContainer;
+        private _nodes;
+        private _ownerCanvas;
+        private _mouseStartPointX;
+        private _mouseStartPointY;
+        private _onSelectionChangedObserver;
+        private _isCollapsed;
+        private _ports;
+        private _controlledPorts;
+        private readonly CloseSVG;
+        private readonly ExpandSVG;
+        private readonly CollapseSVG;
+        isCollapsed: boolean;
+        private _createInputPort;
+        readonly nodes: GraphNode[];
+        name: string;
+        color: Color3;
+        x: number;
+        y: number;
+        width: number;
+        height: number;
+        constructor(candidate: Nullable<HTMLDivElement>, canvas: GraphCanvasComponent, doNotCaptureNodes?: boolean);
+        refresh(): void;
+        addNode(node: GraphNode): void;
+        removeNode(node: GraphNode): void;
+        syncNode(node: GraphNode): void;
+        cleanAccumulation(): void;
+        private _onDown;
+        private _onUp;
+        private _moveFrame;
+        private _onMove;
+        dispose(): void;
+        serialize(): IFrameData;
+        static Parse(serializationData: IFrameData, canvas: GraphCanvasComponent): GraphFrame;
     }
 }
 declare module "babylonjs-node-editor/diagram/nodeLink" {
     import { GraphCanvasComponent } from "babylonjs-node-editor/diagram/graphCanvas";
     import { GraphNode } from "babylonjs-node-editor/diagram/graphNode";
     import { NodePort } from "babylonjs-node-editor/diagram/nodePort";
+    import { Observable } from 'babylonjs/Misc/observable';
     export class NodeLink {
         private _graphCanvas;
         private _portA;
@@ -139,8 +235,13 @@ declare module "babylonjs-node-editor/diagram/nodeLink" {
         private _path;
         private _selectionPath;
         private _onSelectionChangedObserver;
+        private _isVisible;
+        onDisposedObservable: Observable<NodeLink>;
+        isVisible: boolean;
         readonly portA: NodePort;
         readonly portB: NodePort | undefined;
+        readonly nodeA: GraphNode;
+        readonly nodeB: GraphNode | undefined;
         update(endX?: number, endY?: number, straight?: boolean): void;
         constructor(graphCanvas: GraphCanvasComponent, portA: NodePort, nodeA: GraphNode, portB?: NodePort, nodeB?: GraphNode);
         onClick(): void;
@@ -155,6 +256,8 @@ declare module "babylonjs-node-editor/diagram/graphCanvas" {
     import { Nullable } from 'babylonjs/types';
     import { NodeLink } from "babylonjs-node-editor/diagram/nodeLink";
     import { NodeMaterialConnectionPoint } from 'babylonjs/Materials/Node/nodeMaterialBlockConnectionPoint';
+    import { GraphFrame } from "babylonjs-node-editor/diagram/graphFrame";
+    import { IEditorData } from "babylonjs-node-editor/nodeLocationInfo";
     export interface IGraphCanvasComponentProps {
         globalState: GlobalState;
     }
@@ -164,6 +267,7 @@ declare module "babylonjs-node-editor/diagram/graphCanvas" {
         private _hostCanvas;
         private _graphCanvas;
         private _selectionContainer;
+        private _frameContainer;
         private _svgCanvas;
         private _rootContainer;
         private _nodes;
@@ -183,22 +287,31 @@ declare module "babylonjs-node-editor/diagram/graphCanvas" {
         private _candidatePort;
         private _gridSize;
         private _selectionBox;
+        private _selectedFrame;
+        private _frameCandidate;
+        private _frames;
         private _altKeyIsPressed;
         private _ctrlKeyIsPressed;
         private _oldY;
+        _frameIsMoving: boolean;
         gridSize: number;
         readonly globalState: GlobalState;
         readonly nodes: GraphNode[];
         readonly links: NodeLink[];
+        readonly frames: GraphFrame[];
         zoom: number;
         x: number;
         y: number;
         readonly selectedNodes: GraphNode[];
         readonly selectedLink: Nullable<NodeLink>;
+        readonly selectedFrame: Nullable<GraphFrame>;
         readonly canvasContainer: HTMLDivElement;
         readonly svgCanvas: HTMLElement;
+        readonly selectionContainer: HTMLDivElement;
+        readonly frameContainer: HTMLDivElement;
         constructor(props: IGraphCanvasComponentProps);
-        getGridPosition(position: number): number;
+        getGridPosition(position: number, useCeil?: boolean): number;
+        getGridPositionCeil(position: number): number;
         updateTransform(): void;
         onKeyUp(): void;
         findNodeFromBlock(block: NodeMaterialBlock): GraphNode;
@@ -214,6 +327,7 @@ declare module "babylonjs-node-editor/diagram/graphCanvas" {
         onWheel(evt: React.WheelEvent): void;
         zoomToFit(): void;
         processCandidatePort(): void;
+        processEditorData(editorData: IEditorData): void;
         render(): JSX.Element;
     }
 }
@@ -602,6 +716,14 @@ declare module "babylonjs-node-editor/sharedComponents/lineContainerComponent" {
         render(): JSX.Element;
     }
 }
+declare module "babylonjs-node-editor/diagram/properties/propertyComponentProps" {
+    import { GlobalState } from "babylonjs-node-editor/globalState";
+    import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
+    export interface IPropertyComponentProps {
+        globalState: GlobalState;
+        block: NodeMaterialBlock;
+    }
+}
 declare module "babylonjs-node-editor/sharedComponents/textInputLineComponent" {
     import * as React from "react";
     import { Observable } from "babylonjs/Misc/observable";
@@ -645,29 +767,12 @@ declare module "babylonjs-node-editor/sharedComponents/textLineComponent" {
         render(): JSX.Element;
     }
 }
-declare module "babylonjs-node-editor/stringTools" {
-    import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes';
-    export class StringTools {
-        private static _SaveAs;
-        private static _Click;
-        /**
-         * Gets the base math type of node material block connection point.
-         * @param type Type to parse.
-         */
-        static GetBaseType(type: NodeMaterialBlockConnectionPointTypes): string;
-        /**
-         * Download a string into a file that will be saved locally by the browser
-         * @param content defines the string to download locally as a file
-         */
-        static DownloadAsFile(document: HTMLDocument, content: string, filename: string): void;
-    }
-}
-declare module "babylonjs-node-editor/diagram/properties/propertyComponentProps" {
-    import { GlobalState } from "babylonjs-node-editor/globalState";
-    import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
-    export interface IPropertyComponentProps {
-        globalState: GlobalState;
-        block: NodeMaterialBlock;
+declare module "babylonjs-node-editor/diagram/properties/genericNodePropertyComponent" {
+    import * as React from "react";
+    import { IPropertyComponentProps } from "babylonjs-node-editor/diagram/properties/propertyComponentProps";
+    export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
+        constructor(props: IPropertyComponentProps);
+        render(): JSX.Element;
     }
 }
 declare module "babylonjs-node-editor/diagram/properties/inputNodePropertyComponent" {
@@ -865,22 +970,21 @@ declare module "babylonjs-node-editor/diagram/propertyLedger" {
         };
     }
 }
-declare module "babylonjs-node-editor/diagram/properties/genericNodePropertyComponent" {
-    import * as React from "react";
-    import { IPropertyComponentProps } from "babylonjs-node-editor/diagram/properties/propertyComponentProps";
-    export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
-        constructor(props: IPropertyComponentProps);
-        render(): JSX.Element;
-    }
-}
-declare module "babylonjs-node-editor/diagram/display/displayManager" {
-    import { NodeMaterialBlock } from 'babylonjs/Materials/Node/nodeMaterialBlock';
-    export interface IDisplayManager {
-        getHeaderClass(block: NodeMaterialBlock): string;
-        shouldDisplayPortLabels(block: NodeMaterialBlock): boolean;
-        updatePreviewContent(block: NodeMaterialBlock, contentArea: HTMLDivElement): void;
-        getBackgroundColor(block: NodeMaterialBlock): string;
-        getHeaderText(block: NodeMaterialBlock): string;
+declare module "babylonjs-node-editor/stringTools" {
+    import { NodeMaterialBlockConnectionPointTypes } from 'babylonjs/Materials/Node/Enums/nodeMaterialBlockConnectionPointTypes';
+    export class StringTools {
+        private static _SaveAs;
+        private static _Click;
+        /**
+         * Gets the base math type of node material block connection point.
+         * @param type Type to parse.
+         */
+        static GetBaseType(type: NodeMaterialBlockConnectionPointTypes): string;
+        /**
+         * Download a string into a file that will be saved locally by the browser
+         * @param content defines the string to download locally as a file
+         */
+        static DownloadAsFile(document: HTMLDocument, content: string, filename: string): void;
     }
 }
 declare module "babylonjs-node-editor/diagram/display/inputDisplayManager" {
@@ -1011,6 +1115,7 @@ declare module "babylonjs-node-editor/diagram/graphNode" {
     import { GraphCanvasComponent } from "babylonjs-node-editor/diagram/graphCanvas";
     import { NodeLink } from "babylonjs-node-editor/diagram/nodeLink";
     import { NodePort } from "babylonjs-node-editor/diagram/nodePort";
+    import { GraphFrame } from "babylonjs-node-editor/diagram/graphFrame";
     export class GraphNode {
         block: NodeMaterialBlock;
         private _visual;
@@ -1019,6 +1124,7 @@ declare module "babylonjs-node-editor/diagram/graphNode" {
         private _inputsContainer;
         private _outputsContainer;
         private _content;
+        private _comments;
         private _inputPorts;
         private _outputPorts;
         private _links;
@@ -1031,10 +1137,15 @@ declare module "babylonjs-node-editor/diagram/graphNode" {
         private _globalState;
         private _onSelectionChangedObserver;
         private _onSelectionBoxMovedObserver;
+        private _onFrameCreatedObserver;
         private _onUpdateRequiredObserver;
         private _ownerCanvas;
         private _isSelected;
         private _displayManager;
+        private _isVisible;
+        isVisible: boolean;
+        readonly outputPorts: NodePort[];
+        readonly inputPorts: NodePort[];
         readonly links: NodeLink[];
         readonly gridAlignedX: number;
         readonly gridAlignedY: number;
@@ -1046,13 +1157,14 @@ declare module "babylonjs-node-editor/diagram/graphNode" {
         readonly name: string;
         isSelected: boolean;
         constructor(block: NodeMaterialBlock, globalState: GlobalState);
+        isOverlappingFrame(frame: GraphFrame): boolean;
         getPortForConnectionPoint(point: NodeMaterialConnectionPoint): Nullable<NodePort>;
         getLinksForConnectionPoint(point: NodeMaterialConnectionPoint): NodeLink[];
+        private _refreshFrames;
         private _refreshLinks;
         refresh(): void;
-        private _appendConnection;
         private _onDown;
-        cleanAccumulation(): void;
+        cleanAccumulation(useCeil?: boolean): void;
         private _onUp;
         private _onMove;
         renderProperties(): Nullable<JSX.Element>;
@@ -1072,11 +1184,12 @@ declare module "babylonjs-node-editor/globalState" {
     import { Vector2 } from 'babylonjs/Maths/math.vector';
     import { NodePort } from "babylonjs-node-editor/diagram/nodePort";
     import { NodeLink } from "babylonjs-node-editor/diagram/nodeLink";
+    import { GraphFrame } from "babylonjs-node-editor/diagram/graphFrame";
     export class GlobalState {
         nodeMaterial: NodeMaterial;
         hostElement: HTMLElement;
         hostDocument: HTMLDocument;
-        onSelectionChangedObservable: Observable<Nullable<GraphNode | NodeLink>>;
+        onSelectionChangedObservable: Observable<Nullable<GraphNode | GraphFrame | NodeLink>>;
         onRebuildRequiredObservable: Observable<void>;
         onResetRequiredObservable: Observable<void>;
         onUpdateRequiredObservable: Observable<void>;
@@ -1093,6 +1206,7 @@ declare module "babylonjs-node-editor/globalState" {
         onAnimationCommandActivated: Observable<void>;
         onCandidateLinkMoved: Observable<Nullable<Vector2>>;
         onSelectionBoxMoved: Observable<ClientRect | DOMRect>;
+        onFrameCreated: Observable<GraphFrame>;
         onCandidatePortSelected: Observable<Nullable<NodePort>>;
         onGetNodeFromBlock: (block: NodeMaterialBlock) => GraphNode;
         onGridSizeChanged: Observable<void>;
@@ -1155,11 +1269,13 @@ declare module "babylonjs-node-editor/components/propertyTab/propertyTabComponen
     import { GlobalState } from "babylonjs-node-editor/globalState";
     import { Nullable } from 'babylonjs/types';
     import { GraphNode } from "babylonjs-node-editor/diagram/graphNode";
+    import { GraphFrame } from "babylonjs-node-editor/diagram/graphFrame";
     interface IPropertyTabComponentProps {
         globalState: GlobalState;
     }
     export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, {
         currentNode: Nullable<GraphNode>;
+        currentFrame: Nullable<GraphFrame>;
     }> {
         constructor(props: IPropertyTabComponentProps);
         componentDidMount(): void;
@@ -1223,19 +1339,6 @@ declare module "babylonjs-node-editor/components/preview/previewManager" {
         dispose(): void;
     }
 }
-declare module "babylonjs-node-editor/nodeLocationInfo" {
-    export interface INodeLocationInfo {
-        blockId: number;
-        x: number;
-        y: number;
-    }
-    export interface IEditorData {
-        locations: INodeLocationInfo[];
-        x: number;
-        y: number;
-        zoom: number;
-    }
-}
 declare module "babylonjs-node-editor/components/preview/previewMeshControlComponent" {
     import * as React from "react";
     import { GlobalState } from "babylonjs-node-editor/globalState";
@@ -1401,6 +1504,15 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    export interface IDisplayManager {
+        getHeaderClass(block: BABYLON.NodeMaterialBlock): string;
+        shouldDisplayPortLabels(block: BABYLON.NodeMaterialBlock): boolean;
+        updatePreviewContent(block: BABYLON.NodeMaterialBlock, contentArea: HTMLDivElement): void;
+        getBackgroundColor(block: BABYLON.NodeMaterialBlock): string;
+        getHeaderText(block: BABYLON.NodeMaterialBlock): string;
+    }
+}
+declare module NODEEDITOR {
     export class NodePort {
         connectionPoint: BABYLON.NodeMaterialConnectionPoint;
         node: GraphNode;
@@ -1408,10 +1520,88 @@ declare module NODEEDITOR {
         private _img;
         private _globalState;
         private _onCandidateLinkMovedObserver;
+        delegatedPort: BABYLON.Nullable<NodePort>;
         readonly element: HTMLDivElement;
         refresh(): void;
         constructor(portContainer: HTMLElement, connectionPoint: BABYLON.NodeMaterialConnectionPoint, node: GraphNode, globalState: GlobalState);
         dispose(): void;
+        static CreatePortElement(connectionPoint: BABYLON.NodeMaterialConnectionPoint, node: GraphNode, root: HTMLElement, displayManager: BABYLON.Nullable<IDisplayManager>, globalState: GlobalState): NodePort;
+    }
+}
+declare module NODEEDITOR {
+    export interface INodeLocationInfo {
+        blockId: number;
+        x: number;
+        y: number;
+    }
+    export interface IFrameData {
+        x: number;
+        y: number;
+        width: number;
+        height: number;
+        color: number[];
+        name: string;
+        isCollapsed: boolean;
+    }
+    export interface IEditorData {
+        locations: INodeLocationInfo[];
+        x: number;
+        y: number;
+        zoom: number;
+        frames?: IFrameData[];
+    }
+}
+declare module NODEEDITOR {
+    export class GraphFrame {
+        private _name;
+        private _color;
+        private _x;
+        private _y;
+        private _gridAlignedX;
+        private _gridAlignedY;
+        private _width;
+        private _height;
+        element: HTMLDivElement;
+        private _headerElement;
+        private _headerTextElement;
+        private _headerCollapseElement;
+        private _headerCloseElement;
+        private _portContainer;
+        private _outputPortContainer;
+        private _inputPortContainer;
+        private _nodes;
+        private _ownerCanvas;
+        private _mouseStartPointX;
+        private _mouseStartPointY;
+        private _onSelectionChangedObserver;
+        private _isCollapsed;
+        private _ports;
+        private _controlledPorts;
+        private readonly CloseSVG;
+        private readonly ExpandSVG;
+        private readonly CollapseSVG;
+        isCollapsed: boolean;
+        private _createInputPort;
+        readonly nodes: GraphNode[];
+        name: string;
+        color: BABYLON.Color3;
+        x: number;
+        y: number;
+        width: number;
+        height: number;
+        constructor(candidate: BABYLON.Nullable<HTMLDivElement>, canvas: GraphCanvasComponent, doNotCaptureNodes?: boolean);
+        refresh(): void;
+        addNode(node: GraphNode): void;
+        removeNode(node: GraphNode): void;
+        syncNode(node: GraphNode): void;
+        cleanAccumulation(): void;
+        private _onDown;
+        private _onUp;
+        private _moveFrame;
+        private _onMove;
+        dispose(): void;
+        serialize(): IFrameData;
+        static Parse(serializationData: IFrameData, canvas: GraphCanvasComponent): GraphFrame;
     }
 }
 declare module NODEEDITOR {
@@ -1424,8 +1614,13 @@ declare module NODEEDITOR {
         private _path;
         private _selectionPath;
         private _onSelectionChangedObserver;
+        private _isVisible;
+        onDisposedObservable: BABYLON.Observable<NodeLink>;
+        isVisible: boolean;
         readonly portA: NodePort;
         readonly portB: NodePort | undefined;
+        readonly nodeA: GraphNode;
+        readonly nodeB: GraphNode | undefined;
         update(endX?: number, endY?: number, straight?: boolean): void;
         constructor(graphCanvas: GraphCanvasComponent, portA: NodePort, nodeA: GraphNode, portB?: NodePort, nodeB?: GraphNode);
         onClick(): void;
@@ -1442,6 +1637,7 @@ declare module NODEEDITOR {
         private _hostCanvas;
         private _graphCanvas;
         private _selectionContainer;
+        private _frameContainer;
         private _svgCanvas;
         private _rootContainer;
         private _nodes;
@@ -1461,22 +1657,31 @@ declare module NODEEDITOR {
         private _candidatePort;
         private _gridSize;
         private _selectionBox;
+        private _selectedFrame;
+        private _frameCandidate;
+        private _frames;
         private _altKeyIsPressed;
         private _ctrlKeyIsPressed;
         private _oldY;
+        _frameIsMoving: boolean;
         gridSize: number;
         readonly globalState: GlobalState;
         readonly nodes: GraphNode[];
         readonly links: NodeLink[];
+        readonly frames: GraphFrame[];
         zoom: number;
         x: number;
         y: number;
         readonly selectedNodes: GraphNode[];
         readonly selectedLink: BABYLON.Nullable<NodeLink>;
+        readonly selectedFrame: BABYLON.Nullable<GraphFrame>;
         readonly canvasContainer: HTMLDivElement;
         readonly svgCanvas: HTMLElement;
+        readonly selectionContainer: HTMLDivElement;
+        readonly frameContainer: HTMLDivElement;
         constructor(props: IGraphCanvasComponentProps);
-        getGridPosition(position: number): number;
+        getGridPosition(position: number, useCeil?: boolean): number;
+        getGridPositionCeil(position: number): number;
         updateTransform(): void;
         onKeyUp(): void;
         findNodeFromBlock(block: BABYLON.NodeMaterialBlock): GraphNode;
@@ -1492,6 +1697,7 @@ declare module NODEEDITOR {
         onWheel(evt: React.WheelEvent): void;
         zoomToFit(): void;
         processCandidatePort(): void;
+        processEditorData(editorData: IEditorData): void;
         render(): JSX.Element;
     }
 }
@@ -1832,6 +2038,12 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
+    export interface IPropertyComponentProps {
+        globalState: GlobalState;
+        block: BABYLON.NodeMaterialBlock;
+    }
+}
+declare module NODEEDITOR {
     interface ITextInputLineComponentProps {
         label: string;
         globalState: GlobalState;
@@ -1870,25 +2082,9 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
-    export class StringTools {
-        private static _SaveAs;
-        private static _Click;
-        /**
-         * Gets the base math type of node material block connection point.
-         * @param type Type to parse.
-         */
-        static GetBaseType(type: BABYLON.NodeMaterialBlockConnectionPointTypes): string;
-        /**
-         * Download a string into a file that will be saved locally by the browser
-         * @param content defines the string to download locally as a file
-         */
-        static DownloadAsFile(document: HTMLDocument, content: string, filename: string): void;
-    }
-}
-declare module NODEEDITOR {
-    export interface IPropertyComponentProps {
-        globalState: GlobalState;
-        block: BABYLON.NodeMaterialBlock;
+    export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
+        constructor(props: IPropertyComponentProps);
+        render(): JSX.Element;
     }
 }
 declare module NODEEDITOR {
@@ -2051,18 +2247,19 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
-    export class GenericPropertyTabComponent extends React.Component<IPropertyComponentProps> {
-        constructor(props: IPropertyComponentProps);
-        render(): JSX.Element;
-    }
-}
-declare module NODEEDITOR {
-    export interface IDisplayManager {
-        getHeaderClass(block: BABYLON.NodeMaterialBlock): string;
-        shouldDisplayPortLabels(block: BABYLON.NodeMaterialBlock): boolean;
-        updatePreviewContent(block: BABYLON.NodeMaterialBlock, contentArea: HTMLDivElement): void;
-        getBackgroundColor(block: BABYLON.NodeMaterialBlock): string;
-        getHeaderText(block: BABYLON.NodeMaterialBlock): string;
+    export class StringTools {
+        private static _SaveAs;
+        private static _Click;
+        /**
+         * Gets the base math type of node material block connection point.
+         * @param type Type to parse.
+         */
+        static GetBaseType(type: BABYLON.NodeMaterialBlockConnectionPointTypes): string;
+        /**
+         * Download a string into a file that will be saved locally by the browser
+         * @param content defines the string to download locally as a file
+         */
+        static DownloadAsFile(document: HTMLDocument, content: string, filename: string): void;
     }
 }
 declare module NODEEDITOR {
@@ -2178,6 +2375,7 @@ declare module NODEEDITOR {
         private _inputsContainer;
         private _outputsContainer;
         private _content;
+        private _comments;
         private _inputPorts;
         private _outputPorts;
         private _links;
@@ -2190,10 +2388,15 @@ declare module NODEEDITOR {
         private _globalState;
         private _onSelectionChangedObserver;
         private _onSelectionBoxMovedObserver;
+        private _onFrameCreatedObserver;
         private _onUpdateRequiredObserver;
         private _ownerCanvas;
         private _isSelected;
         private _displayManager;
+        private _isVisible;
+        isVisible: boolean;
+        readonly outputPorts: NodePort[];
+        readonly inputPorts: NodePort[];
         readonly links: NodeLink[];
         readonly gridAlignedX: number;
         readonly gridAlignedY: number;
@@ -2205,13 +2408,14 @@ declare module NODEEDITOR {
         readonly name: string;
         isSelected: boolean;
         constructor(block: BABYLON.NodeMaterialBlock, globalState: GlobalState);
+        isOverlappingFrame(frame: GraphFrame): boolean;
         getPortForConnectionPoint(point: BABYLON.NodeMaterialConnectionPoint): BABYLON.Nullable<NodePort>;
         getLinksForConnectionPoint(point: BABYLON.NodeMaterialConnectionPoint): NodeLink[];
+        private _refreshFrames;
         private _refreshLinks;
         refresh(): void;
-        private _appendConnection;
         private _onDown;
-        cleanAccumulation(): void;
+        cleanAccumulation(useCeil?: boolean): void;
         private _onUp;
         private _onMove;
         renderProperties(): BABYLON.Nullable<JSX.Element>;
@@ -2224,7 +2428,7 @@ declare module NODEEDITOR {
         nodeMaterial: BABYLON.NodeMaterial;
         hostElement: HTMLElement;
         hostDocument: HTMLDocument;
-        onSelectionChangedObservable: BABYLON.Observable<BABYLON.Nullable<GraphNode | NodeLink>>;
+        onSelectionChangedObservable: BABYLON.Observable<BABYLON.Nullable<GraphNode | GraphFrame | NodeLink>>;
         onRebuildRequiredObservable: BABYLON.Observable<void>;
         onResetRequiredObservable: BABYLON.Observable<void>;
         onUpdateRequiredObservable: BABYLON.Observable<void>;
@@ -2241,6 +2445,7 @@ declare module NODEEDITOR {
         onAnimationCommandActivated: BABYLON.Observable<void>;
         onCandidateLinkMoved: BABYLON.Observable<BABYLON.Nullable<BABYLON.Vector2>>;
         onSelectionBoxMoved: BABYLON.Observable<ClientRect | DOMRect>;
+        onFrameCreated: BABYLON.Observable<GraphFrame>;
         onCandidatePortSelected: BABYLON.Observable<BABYLON.Nullable<NodePort>>;
         onGetNodeFromBlock: (block: BABYLON.NodeMaterialBlock) => GraphNode;
         onGridSizeChanged: BABYLON.Observable<void>;
@@ -2299,6 +2504,7 @@ declare module NODEEDITOR {
     }
     export class PropertyTabComponent extends React.Component<IPropertyTabComponentProps, {
         currentNode: BABYLON.Nullable<GraphNode>;
+        currentFrame: BABYLON.Nullable<GraphFrame>;
     }> {
         constructor(props: IPropertyTabComponentProps);
         componentDidMount(): void;
@@ -2358,19 +2564,6 @@ declare module NODEEDITOR {
     }
 }
 declare module NODEEDITOR {
-    export interface INodeLocationInfo {
-        blockId: number;
-        x: number;
-        y: number;
-    }
-    export interface IEditorData {
-        locations: INodeLocationInfo[];
-        x: number;
-        y: number;
-        zoom: number;
-    }
-}
-declare module NODEEDITOR {
     interface IPreviewMeshControlComponent {
         globalState: GlobalState;
     }

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

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

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

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

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

@@ -1 +1 @@
-{"thinEngineOnly":116435,"engineOnly":153253,"sceneOnly":497822,"minGridMaterial":628387,"minStandardMaterial":752319}
+{"thinEngineOnly":119146,"engineOnly":155955,"sceneOnly":501692,"minGridMaterial":631692,"minStandardMaterial":755590}

+ 3 - 3
dist/preview release/postProcessesLibrary/babylon.asciiArtPostProcess.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/postProcessesLibrary/babylon.digitalRainPostProcess.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/postProcessesLibrary/babylon.oceanPostProcess.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/postProcessesLibrary/babylonjs.postProcess.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

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

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

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.brickProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.cloudProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.fireProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.grassProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.marbleProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.normalMapProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.perlinNoiseProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.roadProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.starfieldProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylon.woodProceduralTexture.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

+ 3 - 3
dist/preview release/proceduralTexturesLibrary/babylonjs.proceduralTextures.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 

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

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

+ 309 - 80
dist/preview release/serializers/babylon.glTF2Serializer.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
@@ -399,31 +399,19 @@ var KHR_lights_punctual = /** @class */ (function () {
     }
     /** @hidden */
     KHR_lights_punctual.prototype.dispose = function () {
-        delete this._exporter;
         delete this._lights;
     };
+    Object.defineProperty(KHR_lights_punctual.prototype, "wasUsed", {
+        /** @hidden */
+        get: function () {
+            return !!this._lights;
+        },
+        enumerable: true,
+        configurable: true
+    });
     /** @hidden */
     KHR_lights_punctual.prototype.onExporting = function () {
-        if (this._lights) {
-            if (this._exporter._glTF.extensionsUsed == null) {
-                this._exporter._glTF.extensionsUsed = [];
-            }
-            if (this._exporter._glTF.extensionsUsed.indexOf(NAME) === -1) {
-                this._exporter._glTF.extensionsUsed.push(NAME);
-            }
-            if (this.required) {
-                if (this._exporter._glTF.extensionsRequired == null) {
-                    this._exporter._glTF.extensionsRequired = [];
-                }
-                if (this._exporter._glTF.extensionsRequired.indexOf(NAME) === -1) {
-                    this._exporter._glTF.extensionsRequired.push(NAME);
-                }
-            }
-            if (this._exporter._glTF.extensions == null) {
-                this._exporter._glTF.extensions = {};
-            }
-            this._exporter._glTF.extensions[NAME] = this._lights;
-        }
+        this._exporter._glTF.extensions[NAME] = this._lights;
     };
     /**
      * Define this method to modify the default behavior when exporting a node
@@ -519,6 +507,107 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_1__["_Exporter"].RegisterExtension(NAME,
 
 /***/ }),
 
+/***/ "./glTF/2.0/Extensions/KHR_materials_sheen.ts":
+/*!****************************************************!*\
+  !*** ./glTF/2.0/Extensions/KHR_materials_sheen.ts ***!
+  \****************************************************/
+/*! exports provided: KHR_materials_sheen */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return KHR_materials_sheen; });
+/* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
+/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Maths/math");
+/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__);
+
+
+var NAME = "KHR_materials_sheen";
+/**
+ * @hidden
+ */
+var KHR_materials_sheen = /** @class */ (function () {
+    function KHR_materials_sheen(exporter) {
+        /** Name of this extension */
+        this.name = NAME;
+        /** Defines whether this extension is enabled */
+        this.enabled = true;
+        /** Defines whether this extension is required */
+        this.required = false;
+        /** Reference to the glTF exporter */
+        this._textureInfos = [];
+        this._exportedTextures = [];
+        this._wasUsed = false;
+    }
+    KHR_materials_sheen.prototype.dispose = function () {
+        this._textureInfos = [];
+        this._exportedTextures = [];
+    };
+    Object.defineProperty(KHR_materials_sheen.prototype, "wasUsed", {
+        /** @hidden */
+        get: function () {
+            return this._wasUsed;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    KHR_materials_sheen.prototype._getTextureIndex = function (babylonTexture) {
+        var textureIndex = this._exportedTextures.indexOf(babylonTexture);
+        if (textureIndex === -1 && babylonTexture.reservedDataStore) {
+            textureIndex = this._exportedTextures.indexOf(babylonTexture.reservedDataStore.source);
+        }
+        return textureIndex;
+    };
+    KHR_materials_sheen.prototype.postExportTexture = function (context, textureInfo, babylonTexture) {
+        var textureIndex = this._getTextureIndex(babylonTexture);
+        if (textureIndex > -1) {
+            this._textureInfos[textureIndex] = textureInfo;
+        }
+    };
+    KHR_materials_sheen.prototype.postExportMaterialAdditionalTextures = function (context, node, babylonMaterial) {
+        if (babylonMaterial instanceof babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__["PBRMaterial"]) {
+            if (babylonMaterial.sheen.isEnabled && babylonMaterial.sheen.texture) {
+                this._exportedTextures.push(babylonMaterial.sheen.texture);
+                return [babylonMaterial.sheen.texture];
+            }
+        }
+        return [];
+    };
+    KHR_materials_sheen.prototype.postExportMaterialAsync = function (context, node, babylonMaterial) {
+        var _this = this;
+        return new Promise(function (resolve, reject) {
+            if (babylonMaterial instanceof babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__["PBRMaterial"]) {
+                if (!babylonMaterial.sheen.isEnabled) {
+                    resolve(node);
+                    return;
+                }
+                _this._wasUsed = true;
+                if (node.extensions == null) {
+                    node.extensions = {};
+                }
+                var sheenInfo = {
+                    colorFactor: babylonMaterial.sheen.color.asArray(),
+                    intensityFactor: babylonMaterial.sheen.intensity
+                };
+                if (babylonMaterial.sheen.texture) {
+                    var textureIndex = _this._getTextureIndex(babylonMaterial.sheen.texture);
+                    if (textureIndex > -1) {
+                        sheenInfo.colorIntensityTexture = _this._textureInfos[textureIndex];
+                    }
+                }
+                node.extensions[NAME] = sheenInfo;
+            }
+            resolve(node);
+        });
+    };
+    return KHR_materials_sheen;
+}());
+
+_glTFExporter__WEBPACK_IMPORTED_MODULE_0__["_Exporter"].RegisterExtension(NAME, function (exporter) { return new KHR_materials_sheen(exporter); });
+
+
+/***/ }),
+
 /***/ "./glTF/2.0/Extensions/KHR_texture_transform.ts":
 /*!******************************************************!*\
   !*** ./glTF/2.0/Extensions/KHR_texture_transform.ts ***!
@@ -543,16 +632,59 @@ var NAME = "KHR_texture_transform";
  */
 var KHR_texture_transform = /** @class */ (function () {
     function KHR_texture_transform(exporter) {
+        this._recordedTextures = [];
         /** Name of this extension */
         this.name = NAME;
         /** Defines whether this extension is enabled */
         this.enabled = true;
         /** Defines whether this extension is required */
         this.required = false;
-        this._exporter = exporter;
+        /** Reference to the glTF exporter */
+        this._wasUsed = false;
     }
     KHR_texture_transform.prototype.dispose = function () {
-        delete this._exporter;
+        for (var _i = 0, _a = this._recordedTextures; _i < _a.length; _i++) {
+            var texture = _a[_i];
+            texture.dispose();
+        }
+    };
+    Object.defineProperty(KHR_texture_transform.prototype, "wasUsed", {
+        /** @hidden */
+        get: function () {
+            return this._wasUsed;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    KHR_texture_transform.prototype.postExportTexture = function (context, textureInfo, babylonTexture) {
+        if (babylonTexture && babylonTexture.uRotationCenter === 0 && babylonTexture.vRotationCenter === 0) {
+            var textureTransform = {};
+            var transformIsRequired = false;
+            if (babylonTexture.uOffset !== 0 || babylonTexture.vOffset !== 0) {
+                textureTransform.offset = [babylonTexture.uOffset, babylonTexture.vOffset];
+                transformIsRequired = true;
+            }
+            if (babylonTexture.uScale !== 1 || babylonTexture.vScale !== 1) {
+                textureTransform.scale = [babylonTexture.uScale, babylonTexture.vScale];
+                transformIsRequired = true;
+            }
+            if (babylonTexture.wAng !== 0) {
+                textureTransform.rotation = babylonTexture.wAng;
+                transformIsRequired = true;
+            }
+            if (babylonTexture.coordinatesIndex !== 0) {
+                textureTransform.texCoord = babylonTexture.coordinatesIndex;
+                transformIsRequired = true;
+            }
+            if (!transformIsRequired) {
+                return;
+            }
+            this._wasUsed = true;
+            if (!textureInfo.extensions) {
+                textureInfo.extensions = {};
+            }
+            textureInfo.extensions[NAME] = textureTransform;
+        }
     };
     KHR_texture_transform.prototype.preExportTextureAsync = function (context, babylonTexture, mimeType) {
         var _this = this;
@@ -562,18 +694,22 @@ var KHR_texture_transform = /** @class */ (function () {
                 reject(context + ": \"scene\" is not defined for Babylon texture " + babylonTexture.name + "!");
                 return;
             }
-            // TODO: this doesn't take into account rotation center values
-            var texture_transform_extension = {};
+            var transformIsRequired = false;
             if (babylonTexture.uOffset !== 0 || babylonTexture.vOffset !== 0) {
-                texture_transform_extension.offset = [babylonTexture.uOffset, babylonTexture.vOffset];
+                transformIsRequired = true;
             }
             if (babylonTexture.uScale !== 1 || babylonTexture.vScale !== 1) {
-                texture_transform_extension.scale = [babylonTexture.uScale, babylonTexture.vScale];
+                transformIsRequired = true;
             }
             if (babylonTexture.wAng !== 0) {
-                texture_transform_extension.rotation = babylonTexture.wAng;
+                transformIsRequired = true;
             }
-            if (!Object.keys(texture_transform_extension).length) {
+            if (!transformIsRequired) {
+                resolve(babylonTexture);
+                return;
+            }
+            // Do we need to flatten the transform?
+            if (babylonTexture.uRotationCenter === 0 && babylonTexture.vRotationCenter === 0) {
                 resolve(babylonTexture);
                 return;
             }
@@ -595,12 +731,19 @@ var KHR_texture_transform = /** @class */ (function () {
      * @param scene
      */
     KHR_texture_transform.prototype._textureTransformTextureAsync = function (babylonTexture, scene) {
+        var _this = this;
         return new Promise(function (resolve) {
             var proceduralTexture = new babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["ProceduralTexture"]("" + babylonTexture.name, babylonTexture.getSize(), "textureTransform", scene);
             if (!proceduralTexture) {
                 babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["Tools"].Log("Cannot create procedural texture for " + babylonTexture.name + "!");
                 resolve(babylonTexture);
             }
+            proceduralTexture.reservedDataStore = {
+                hidden: true,
+                source: babylonTexture
+            };
+            _this._recordedTextures.push(proceduralTexture);
+            proceduralTexture.coordinatesIndex = babylonTexture.coordinatesIndex;
             proceduralTexture.setTexture("textureSampler", babylonTexture);
             proceduralTexture.setMatrix("textureTransformMat", babylonTexture.getTextureMatrix());
             // isReady trigger creation of effect if it doesnt exist yet
@@ -628,7 +771,7 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_1__["_Exporter"].RegisterExtension(NAME,
 /*!**************************************!*\
   !*** ./glTF/2.0/Extensions/index.ts ***!
   \**************************************/
-/*! exports provided: KHR_texture_transform, KHR_lights_punctual */
+/*! exports provided: KHR_texture_transform, KHR_lights_punctual, KHR_materials_sheen */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -639,6 +782,10 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _KHR_lights_punctual__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./KHR_lights_punctual */ "./glTF/2.0/Extensions/KHR_lights_punctual.ts");
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return _KHR_lights_punctual__WEBPACK_IMPORTED_MODULE_1__["KHR_lights_punctual"]; });
 
+/* harmony import */ var _KHR_materials_sheen__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./KHR_materials_sheen */ "./glTF/2.0/Extensions/KHR_materials_sheen.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return _KHR_materials_sheen__WEBPACK_IMPORTED_MODULE_2__["KHR_materials_sheen"]; });
+
+
 
 
 
@@ -1417,7 +1564,6 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
-
 /**
  * Converts Babylon Scene into glTF 2.0.
  * @hidden
@@ -1452,60 +1598,107 @@ var _Exporter = /** @class */ (function () {
         this._glTFMaterialExporter = new _glTFMaterialExporter__WEBPACK_IMPORTED_MODULE_2__["_GLTFMaterialExporter"](this);
         this._loadExtensions();
     }
-    _Exporter.prototype._applyExtensions = function (property, actionAsync) {
+    _Exporter.prototype._applyExtension = function (node, extensions, index, actionAsync) {
+        var _this = this;
+        if (index >= extensions.length) {
+            return Promise.resolve(node);
+        }
+        var currentPromise = actionAsync(extensions[index], node);
+        if (!currentPromise) {
+            return this._applyExtension(node, extensions, index + 1, actionAsync);
+        }
+        return currentPromise.then(function (newNode) { return _this._applyExtension(newNode || node, extensions, index + 1, actionAsync); });
+    };
+    _Exporter.prototype._applyExtensions = function (node, actionAsync) {
+        var extensions = [];
         for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
             var name_1 = _a[_i];
-            var extension = this._extensions[name_1];
-            if (extension.enabled) {
-                var exporterProperty = property;
-                exporterProperty._activeLoaderExtensions = exporterProperty._activeLoaderExtensions || {};
-                var activeLoaderExtensions = exporterProperty._activeLoaderExtensions;
-                if (!activeLoaderExtensions[name_1]) {
-                    activeLoaderExtensions[name_1] = true;
-                    try {
-                        var result = actionAsync(extension);
-                        if (result) {
-                            return result;
-                        }
-                    }
-                    finally {
-                        delete activeLoaderExtensions[name_1];
-                        delete exporterProperty._activeLoaderExtensions;
-                    }
-                }
-            }
+            extensions.push(this._extensions[name_1]);
         }
-        return null;
+        return this._applyExtension(node, extensions, 0, actionAsync);
     };
     _Exporter.prototype._extensionsPreExportTextureAsync = function (context, babylonTexture, mimeType) {
-        return this._applyExtensions(babylonTexture, function (extension) { return extension.preExportTextureAsync && extension.preExportTextureAsync(context, babylonTexture, mimeType); });
+        return this._applyExtensions(babylonTexture, function (extension, node) { return extension.preExportTextureAsync && extension.preExportTextureAsync(context, node, mimeType); });
     };
     _Exporter.prototype._extensionsPostExportMeshPrimitiveAsync = function (context, meshPrimitive, babylonSubMesh, binaryWriter) {
-        return this._applyExtensions(meshPrimitive, function (extension) { return extension.postExportMeshPrimitiveAsync && extension.postExportMeshPrimitiveAsync(context, meshPrimitive, babylonSubMesh, binaryWriter); });
+        return this._applyExtensions(meshPrimitive, function (extension, node) { return extension.postExportMeshPrimitiveAsync && extension.postExportMeshPrimitiveAsync(context, node, babylonSubMesh, binaryWriter); });
     };
     _Exporter.prototype._extensionsPostExportNodeAsync = function (context, node, babylonNode) {
-        return this._applyExtensions(node, function (extension) { return extension.postExportNodeAsync && extension.postExportNodeAsync(context, node, babylonNode); });
+        return this._applyExtensions(node, function (extension, node) { return extension.postExportNodeAsync && extension.postExportNodeAsync(context, node, babylonNode); });
     };
-    _Exporter.prototype._forEachExtensions = function (action) {
+    _Exporter.prototype._extensionsPostExportMaterialAsync = function (context, material, babylonMaterial) {
+        return this._applyExtensions(material, function (extension, node) { return extension.postExportMaterialAsync && extension.postExportMaterialAsync(context, node, babylonMaterial); });
+    };
+    _Exporter.prototype._extensionsPostExportMaterialAdditionalTextures = function (context, material, babylonMaterial) {
+        var output = [];
         for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
             var name_2 = _a[_i];
             var extension = this._extensions[name_2];
+            if (extension.postExportMaterialAdditionalTextures) {
+                output.push.apply(output, extension.postExportMaterialAdditionalTextures(context, material, babylonMaterial));
+            }
+        }
+        return output;
+    };
+    _Exporter.prototype._extensionsPostExportTextures = function (context, textureInfo, babylonTexture) {
+        for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
+            var name_3 = _a[_i];
+            var extension = this._extensions[name_3];
+            if (extension.postExportTexture) {
+                extension.postExportTexture(context, textureInfo, babylonTexture);
+            }
+        }
+    };
+    _Exporter.prototype._forEachExtensions = function (action) {
+        for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
+            var name_4 = _a[_i];
+            var extension = this._extensions[name_4];
             if (extension.enabled) {
                 action(extension);
             }
         }
     };
     _Exporter.prototype._extensionsOnExporting = function () {
-        this._forEachExtensions(function (extension) { return extension.onExporting && extension.onExporting(); });
+        var _this = this;
+        this._forEachExtensions(function (extension) {
+            if (extension.wasUsed) {
+                if (_this._glTF.extensionsUsed == null) {
+                    _this._glTF.extensionsUsed = [];
+                }
+                if (_this._glTF.extensionsUsed.indexOf(extension.name) === -1) {
+                    _this._glTF.extensionsUsed.push(extension.name);
+                }
+                if (extension.required) {
+                    if (_this._glTF.extensionsRequired == null) {
+                        _this._glTF.extensionsRequired = [];
+                    }
+                    if (_this._glTF.extensionsRequired.indexOf(extension.name) === -1) {
+                        _this._glTF.extensionsRequired.push(extension.name);
+                    }
+                }
+                if (_this._glTF.extensions == null) {
+                    _this._glTF.extensions = {};
+                }
+                if (extension.onExporting) {
+                    extension.onExporting();
+                }
+            }
+        });
     };
     /**
      * Load glTF serializer extensions
      */
     _Exporter.prototype._loadExtensions = function () {
         for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
-            var name_3 = _a[_i];
-            var extension = _Exporter._ExtensionFactories[name_3](this);
-            this._extensions[name_3] = extension;
+            var name_5 = _a[_i];
+            var extension = _Exporter._ExtensionFactories[name_5](this);
+            this._extensions[name_5] = extension;
+        }
+    };
+    _Exporter.prototype.dispose = function () {
+        for (var extensionKey in this._extensions) {
+            var extension = this._extensions[extensionKey];
+            extension.dispose();
         }
     };
     /**
@@ -2004,10 +2197,12 @@ var _Exporter = /** @class */ (function () {
     /**
      * Generates data for .gltf and .bin files based on the glTF prefix string
      * @param glTFPrefix Text to use when prefixing a glTF file
+     * @param dispose Dispose the exporter
      * @returns GLTFData with glTF file data
      */
-    _Exporter.prototype._generateGLTFAsync = function (glTFPrefix) {
+    _Exporter.prototype._generateGLTFAsync = function (glTFPrefix, dispose) {
         var _this = this;
+        if (dispose === void 0) { dispose = true; }
         return this._generateBinaryAsync().then(function (binaryBuffer) {
             _this._extensionsOnExporting();
             var jsonText = _this.generateJSON(false, glTFPrefix, true);
@@ -2022,6 +2217,9 @@ var _Exporter = /** @class */ (function () {
                     container.glTFFiles[image] = new Blob([_this._imageData[image].data], { type: _this._imageData[image].mimeType });
                 }
             }
+            if (dispose) {
+                _this.dispose();
+            }
             return container;
         });
     };
@@ -2050,13 +2248,11 @@ var _Exporter = /** @class */ (function () {
         return padding;
     };
     /**
-     * Generates a glb file from the json and binary data
-     * Returns an object with the glb file name as the key and data as the value
-     * @param glTFPrefix
-     * @returns object with glb filename as key and data as value
+     * @hidden
      */
-    _Exporter.prototype._generateGLBAsync = function (glTFPrefix) {
+    _Exporter.prototype._generateGLBAsync = function (glTFPrefix, dispose) {
         var _this = this;
+        if (dispose === void 0) { dispose = true; }
         return this._generateBinaryAsync().then(function (binaryBuffer) {
             _this._extensionsOnExporting();
             var jsonText = _this.generateJSON(true);
@@ -2122,6 +2318,9 @@ var _Exporter = /** @class */ (function () {
             if (_this._localEngine != null) {
                 _this._localEngine.dispose();
             }
+            if (dispose) {
+                _this.dispose();
+            }
             return container;
         });
     };
@@ -2531,12 +2730,12 @@ var _Exporter = /** @class */ (function () {
                         }
                         else {
                             return promise.then(function (node) {
-                                var directDescendents = babylonNode.getDescendants(true, function (node) { return (node instanceof babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__["Node"]); });
-                                if (directDescendents.length || node.mesh != null || (node.extensions)) {
-                                    _this._nodes.push(node);
-                                    nodeIndex = _this._nodes.length - 1;
-                                    nodeMap[babylonNode.uniqueId] = nodeIndex;
+                                if (!node) {
+                                    return;
                                 }
+                                _this._nodes.push(node);
+                                nodeIndex = _this._nodes.length - 1;
+                                nodeMap[babylonNode.uniqueId] = nodeIndex;
                                 if (!babylonScene.animationGroups.length && babylonNode.animations.length) {
                                     _glTFAnimation__WEBPACK_IMPORTED_MODULE_5__["_GLTFAnimation"]._CreateNodeAnimationFromNodeAnimations(babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, nodeMap, _this._nodes, binaryWriter, _this._bufferViews, _this._accessors, _this._convertToRightHandedSystem, _this._animationSampleRate);
                                 }
@@ -3073,7 +3272,31 @@ var _GLTFMaterialExporter = /** @class */ (function () {
         _GLTFMaterialExporter._SetAlphaMode(glTFMaterial, babylonStandardMaterial);
         materials.push(glTFMaterial);
         materialMap[babylonStandardMaterial.uniqueId] = materials.length - 1;
-        return Promise.all(promises).then(function () { });
+        return this._finishMaterial(promises, glTFMaterial, babylonStandardMaterial, mimeType);
+    };
+    _GLTFMaterialExporter.prototype._finishMaterial = function (promises, glTFMaterial, babylonMaterial, mimeType) {
+        var _this = this;
+        return Promise.all(promises).then(function () {
+            var textures = _this._exporter._extensionsPostExportMaterialAdditionalTextures("exportMaterial", glTFMaterial, babylonMaterial);
+            var tasks = null;
+            for (var _i = 0, textures_1 = textures; _i < textures_1.length; _i++) {
+                var texture = textures_1[_i];
+                if (!tasks) {
+                    tasks = [];
+                }
+                tasks.push(_this._exportTextureAsync(texture, mimeType));
+            }
+            if (!tasks) {
+                tasks = [Promise.resolve(null)];
+            }
+            return Promise.all(tasks).then(function () {
+                var extensionWork = _this._exporter._extensionsPostExportMaterialAsync("exportMaterial", glTFMaterial, babylonMaterial);
+                if (!extensionWork) {
+                    return glTFMaterial;
+                }
+                return extensionWork.then(function () { return glTFMaterial; });
+            });
+        });
     };
     /**
      * Converts a Babylon PBR Metallic Roughness Material to a glTF Material
@@ -3153,7 +3376,7 @@ var _GLTFMaterialExporter = /** @class */ (function () {
         glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
         materials.push(glTFMaterial);
         materialMap[babylonPBRMetalRoughMaterial.uniqueId] = materials.length - 1;
-        return Promise.all(promises).then(function () { });
+        return this._finishMaterial(promises, glTFMaterial, babylonPBRMetalRoughMaterial, mimeType);
     };
     /**
      * Converts an image typed array buffer to a base64 image
@@ -3714,7 +3937,8 @@ var _GLTFMaterialExporter = /** @class */ (function () {
                     var promise = this._exportTextureAsync(babylonPBRMaterial.ambientTexture, mimeType).then(function (glTFTexture) {
                         if (glTFTexture) {
                             var occlusionTexture = {
-                                index: glTFTexture.index
+                                index: glTFTexture.index,
+                                texCoord: glTFTexture.texCoord
                             };
                             glTFMaterial.occlusionTexture = occlusionTexture;
                             if (babylonPBRMaterial.ambientTextureStrength) {
@@ -3740,7 +3964,7 @@ var _GLTFMaterialExporter = /** @class */ (function () {
             materials.push(glTFMaterial);
             materialMap[babylonPBRMaterial.uniqueId] = materials.length - 1;
         }
-        return Promise.all(promises).then(function (result) { });
+        return this._finishMaterial(promises, glTFMaterial, babylonPBRMaterial, mimeType);
     };
     _GLTFMaterialExporter.prototype.getPixelsFromTexture = function (babylonTexture) {
         var pixels = babylonTexture.textureType === babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Constants"].TEXTURETYPE_UNSIGNED_INT ? babylonTexture.readPixels() : babylonTexture.readPixels();
@@ -3799,6 +4023,7 @@ var _GLTFMaterialExporter = /** @class */ (function () {
                     var textureInfo = _this._getTextureInfoFromBase64(base64Data, babylonTexture.name.replace(/\.\/|\/|\.\\|\\/g, "_"), mimeType, babylonTexture.coordinatesIndex, samplerIndex_1);
                     if (textureInfo) {
                         _this._textureMap[textureUid] = textureInfo;
+                        _this._exporter._extensionsPostExportTextures("linkTextureInfo", textureInfo, babylonTexture);
                     }
                     return textureInfo;
                 });
@@ -4166,7 +4391,7 @@ var _GLTFUtilities = /** @class */ (function () {
 /*!***************************!*\
   !*** ./glTF/2.0/index.ts ***!
   \***************************/
-/*! exports provided: GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual */
+/*! exports provided: GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual, KHR_materials_sheen */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -4199,6 +4424,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_7__["KHR_lights_punctual"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_7__["KHR_materials_sheen"]; });
+
 
 
 
@@ -4253,7 +4480,7 @@ var __IGLTFExporterExtension = 0; // I am here to allow dts to be created
 /*!******************************************!*\
   !*** ./legacy/legacy-glTF2Serializer.ts ***!
   \******************************************/
-/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual */
+/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual, KHR_materials_sheen */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -4285,6 +4512,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return _glTF_2_0__WEBPACK_IMPORTED_MODULE_4__["KHR_lights_punctual"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return _glTF_2_0__WEBPACK_IMPORTED_MODULE_4__["KHR_materials_sheen"]; });
+
 
 
 

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylon.glTF2Serializer.js.map


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/serializers/babylon.glTF2Serializer.min.js


File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylon.objSerializer.min.js


+ 80 - 20
dist/preview release/serializers/babylonjs.serializers.d.ts

@@ -53,11 +53,18 @@ declare module BABYLON.GLTF2.Exporter {
         /**
          * Define this method to modify the default behavior before exporting a texture
          * @param context The context when loading the asset
-         * @param babylonTexture The glTF texture info property
+         * @param babylonTexture The Babylon.js texture
          * @param mimeType The mime-type of the generated image
-         * @returns A promise that resolves with the exported glTF texture info when the export is complete, or null if not handled
+         * @returns A promise that resolves with the exported texture
          */
-        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Texture>;
+        /**
+         * Define this method to get notified when a texture info is created
+         * @param context The context when loading the asset
+         * @param textureInfo The glTF texture info
+         * @param babylonTexture The Babylon.js texture
+         */
+        postExportTexture?(context: string, textureInfo: ITextureInfo, babylonTexture: BaseTexture): void;
         /**
          * Define this method to modify the default behavior when exporting texture info
          * @param context The context when loading the asset
@@ -66,7 +73,7 @@ declare module BABYLON.GLTF2.Exporter {
          * @param binaryWriter glTF serializer binary writer instance
          * @returns nullable IMeshPrimitive promise
          */
-        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Promise<IMeshPrimitive>;
         /**
          * Define this method to modify the default behavior when exporting a node
          * @param context The context when exporting the node
@@ -74,7 +81,25 @@ declare module BABYLON.GLTF2.Exporter {
          * @param babylonNode BabylonJS node
          * @returns nullable INode promise
          */
-        postExportNodeAsync?(context: string, node: INode, babylonNode: Node): Nullable<Promise<INode>>;
+        postExportNodeAsync?(context: string, node: INode, babylonNode: Node): Promise<INode>;
+        /**
+         * Define this method to modify the default behavior when exporting a material
+         * @param material glTF material
+         * @param babylonMaterial BabylonJS material
+         * @returns nullable IMaterial promise
+         */
+        postExportMaterialAsync?(context: string, node: IMaterial, babylonMaterial: Material): Promise<IMaterial>;
+        /**
+         * Define this method to return additional textures to export from a material
+         * @param material glTF material
+         * @param babylonMaterial BabylonJS material
+         * @returns List of textures
+         */
+        postExportMaterialAdditionalTextures?(context: string, node: IMaterial, babylonMaterial: Material): BaseTexture[];
+        /** Gets a boolean indicating that this extension was used */
+        wasUsed: boolean;
+        /** Gets a boolean indicating that this extension is required for the file to work */
+        required: boolean;
         /**
          * Called after the exporter state changes to EXPORTING
          */
@@ -168,7 +193,8 @@ declare module BABYLON.GLTF2.Exporter {
          * @param imageData map of image file name to data
          * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
          */
-        _convertStandardMaterialAsync(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void>;
+        _convertStandardMaterialAsync(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<IMaterial>;
+        private _finishMaterial;
         /**
          * Converts a Babylon PBR Metallic Roughness Material to a glTF Material
          * @param babylonPBRMetalRoughMaterial BJS PBR Metallic Roughness Material
@@ -179,7 +205,7 @@ declare module BABYLON.GLTF2.Exporter {
          * @param imageData map of image file name to data
          * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
          */
-        _convertPBRMetallicRoughnessMaterialAsync(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void>;
+        _convertPBRMetallicRoughnessMaterialAsync(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<IMaterial>;
         /**
          * Converts an image typed array buffer to a base64 image
          * @param buffer typed array buffer
@@ -278,7 +304,7 @@ declare module BABYLON.GLTF2.Exporter {
          * @param imageData map of image file name to data
          * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
          */
-        _convertPBRMaterialAsync(babylonPBRMaterial: PBRMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void>;
+        _convertPBRMaterialAsync(babylonPBRMaterial: PBRMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<IMaterial>;
         private setMetallicRoughnessPbrMaterial;
         private getPixelsFromTexture;
         /**
@@ -560,10 +586,14 @@ declare module BABYLON.GLTF2.Exporter {
         private _extensions;
         private static _ExtensionNames;
         private static _ExtensionFactories;
+        private _applyExtension;
         private _applyExtensions;
-        _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<BaseTexture>>;
-        _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
-        _extensionsPostExportNodeAsync(context: string, node: INode, babylonNode: Node): Nullable<Promise<INode>>;
+        _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Nullable<BaseTexture>>;
+        _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Promise<Nullable<IMeshPrimitive>>;
+        _extensionsPostExportNodeAsync(context: string, node: INode, babylonNode: Node): Promise<Nullable<INode>>;
+        _extensionsPostExportMaterialAsync(context: string, material: IMaterial, babylonMaterial: Material): Promise<Nullable<IMaterial>>;
+        _extensionsPostExportMaterialAdditionalTextures(context: string, material: IMaterial, babylonMaterial: Material): BaseTexture[];
+        _extensionsPostExportTextures(context: string, textureInfo: ITextureInfo, babylonTexture: BaseTexture): void;
         private _forEachExtensions;
         private _extensionsOnExporting;
         /**
@@ -576,6 +606,7 @@ declare module BABYLON.GLTF2.Exporter {
          * @param options Options to modify the behavior of the exporter
          */
         constructor(babylonScene: Scene, options?: IExportOptions);
+        dispose(): void;
         /**
          * Registers a glTF exporter extension
          * @param name Name of the extension to export
@@ -670,9 +701,10 @@ declare module BABYLON.GLTF2.Exporter {
         /**
          * Generates data for .gltf and .bin files based on the glTF prefix string
          * @param glTFPrefix Text to use when prefixing a glTF file
+         * @param dispose Dispose the exporter
          * @returns GLTFData with glTF file data
          */
-        _generateGLTFAsync(glTFPrefix: string): Promise<GLTFData>;
+        _generateGLTFAsync(glTFPrefix: string, dispose?: boolean): Promise<GLTFData>;
         /**
          * Creates a binary buffer for glTF
          * @returns array buffer for binary data
@@ -685,12 +717,9 @@ declare module BABYLON.GLTF2.Exporter {
          */
         private _getPadding;
         /**
-         * Generates a glb file from the json and binary data
-         * Returns an object with the glb file name as the key and data as the value
-         * @param glTFPrefix
-         * @returns object with glb filename as key and data as value
+         * @hidden
          */
-        _generateGLBAsync(glTFPrefix: string): Promise<GLTFData>;
+        _generateGLBAsync(glTFPrefix: string, dispose?: boolean): Promise<GLTFData>;
         /**
          * Sets the TRS for each node
          * @param node glTF Node for storing the transformation data
@@ -1006,6 +1035,7 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
      * @hidden
      */
     export class KHR_texture_transform implements IGLTFExporterExtensionV2 {
+        private _recordedTextures;
         /** Name of this extension */
         readonly name: string;
         /** Defines whether this extension is enabled */
@@ -1013,10 +1043,13 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
         /** Defines whether this extension is required */
         required: boolean;
         /** Reference to the glTF exporter */
-        private _exporter;
+        private _wasUsed;
         constructor(exporter: _Exporter);
         dispose(): void;
-        preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        /** @hidden */
+        readonly wasUsed: boolean;
+        postExportTexture?(context: string, textureInfo: ITextureInfo, babylonTexture: Texture): void;
+        preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Texture>;
         /**
          * Transform the babylon texture by the offset, rotation and scale parameters using a procedural texture
          * @param babylonTexture
@@ -1047,6 +1080,8 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
+        readonly wasUsed: boolean;
+        /** @hidden */
         onExporting(): void;
         /**
          * Define this method to modify the default behavior when exporting a node
@@ -1055,7 +1090,32 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
          * @param babylonNode BabylonJS node
          * @returns nullable INode promise
          */
-        postExportNodeAsync(context: string, node: INode, babylonNode: Node): Nullable<Promise<INode>>;
+        postExportNodeAsync(context: string, node: INode, babylonNode: Node): Promise<INode>;
+    }
+}
+declare module BABYLON.GLTF2.Exporter.Extensions {
+    /**
+     * @hidden
+     */
+    export class KHR_materials_sheen implements IGLTFExporterExtensionV2 {
+        /** Name of this extension */
+        readonly name: string;
+        /** Defines whether this extension is enabled */
+        enabled: boolean;
+        /** Defines whether this extension is required */
+        required: boolean;
+        /** Reference to the glTF exporter */
+        private _textureInfos;
+        private _exportedTextures;
+        private _wasUsed;
+        constructor(exporter: _Exporter);
+        dispose(): void;
+        /** @hidden */
+        readonly wasUsed: boolean;
+        private _getTextureIndex;
+        postExportTexture?(context: string, textureInfo: ITextureInfo, babylonTexture: Texture): void;
+        postExportMaterialAdditionalTextures?(context: string, node: IMaterial, babylonMaterial: Material): BaseTexture[];
+        postExportMaterialAsync?(context: string, node: IMaterial, babylonMaterial: Material): Promise<IMaterial>;
     }
 }
 declare module BABYLON {

+ 318 - 83
dist/preview release/serializers/babylonjs.serializers.js

@@ -97,9 +97,9 @@ return /******/ (function(modules) { // webpackBootstrap
 /******/ ({
 
 /***/ "../../node_modules/tslib/tslib.es6.js":
-/*!***********************************************************!*\
-  !*** C:/Repos/Babylon.js/node_modules/tslib/tslib.es6.js ***!
-  \***********************************************************/
+/*!*****************************************************************!*\
+  !*** C:/Dev/Babylon/Babylon.js/node_modules/tslib/tslib.es6.js ***!
+  \*****************************************************************/
 /*! exports provided: __extends, __assign, __rest, __decorate, __param, __metadata, __awaiter, __generator, __exportStar, __values, __read, __spread, __spreadArrays, __await, __asyncGenerator, __asyncDelegator, __asyncValues, __makeTemplateObject, __importStar, __importDefault */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
@@ -577,31 +577,19 @@ var KHR_lights_punctual = /** @class */ (function () {
     }
     /** @hidden */
     KHR_lights_punctual.prototype.dispose = function () {
-        delete this._exporter;
         delete this._lights;
     };
+    Object.defineProperty(KHR_lights_punctual.prototype, "wasUsed", {
+        /** @hidden */
+        get: function () {
+            return !!this._lights;
+        },
+        enumerable: true,
+        configurable: true
+    });
     /** @hidden */
     KHR_lights_punctual.prototype.onExporting = function () {
-        if (this._lights) {
-            if (this._exporter._glTF.extensionsUsed == null) {
-                this._exporter._glTF.extensionsUsed = [];
-            }
-            if (this._exporter._glTF.extensionsUsed.indexOf(NAME) === -1) {
-                this._exporter._glTF.extensionsUsed.push(NAME);
-            }
-            if (this.required) {
-                if (this._exporter._glTF.extensionsRequired == null) {
-                    this._exporter._glTF.extensionsRequired = [];
-                }
-                if (this._exporter._glTF.extensionsRequired.indexOf(NAME) === -1) {
-                    this._exporter._glTF.extensionsRequired.push(NAME);
-                }
-            }
-            if (this._exporter._glTF.extensions == null) {
-                this._exporter._glTF.extensions = {};
-            }
-            this._exporter._glTF.extensions[NAME] = this._lights;
-        }
+        this._exporter._glTF.extensions[NAME] = this._lights;
     };
     /**
      * Define this method to modify the default behavior when exporting a node
@@ -697,6 +685,107 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_1__["_Exporter"].RegisterExtension(NAME,
 
 /***/ }),
 
+/***/ "./glTF/2.0/Extensions/KHR_materials_sheen.ts":
+/*!****************************************************!*\
+  !*** ./glTF/2.0/Extensions/KHR_materials_sheen.ts ***!
+  \****************************************************/
+/*! exports provided: KHR_materials_sheen */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return KHR_materials_sheen; });
+/* harmony import */ var _glTFExporter__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../glTFExporter */ "./glTF/2.0/glTFExporter.ts");
+/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! babylonjs/Materials/PBR/pbrMaterial */ "babylonjs/Maths/math");
+/* harmony import */ var babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__);
+
+
+var NAME = "KHR_materials_sheen";
+/**
+ * @hidden
+ */
+var KHR_materials_sheen = /** @class */ (function () {
+    function KHR_materials_sheen(exporter) {
+        /** Name of this extension */
+        this.name = NAME;
+        /** Defines whether this extension is enabled */
+        this.enabled = true;
+        /** Defines whether this extension is required */
+        this.required = false;
+        /** Reference to the glTF exporter */
+        this._textureInfos = [];
+        this._exportedTextures = [];
+        this._wasUsed = false;
+    }
+    KHR_materials_sheen.prototype.dispose = function () {
+        this._textureInfos = [];
+        this._exportedTextures = [];
+    };
+    Object.defineProperty(KHR_materials_sheen.prototype, "wasUsed", {
+        /** @hidden */
+        get: function () {
+            return this._wasUsed;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    KHR_materials_sheen.prototype._getTextureIndex = function (babylonTexture) {
+        var textureIndex = this._exportedTextures.indexOf(babylonTexture);
+        if (textureIndex === -1 && babylonTexture.reservedDataStore) {
+            textureIndex = this._exportedTextures.indexOf(babylonTexture.reservedDataStore.source);
+        }
+        return textureIndex;
+    };
+    KHR_materials_sheen.prototype.postExportTexture = function (context, textureInfo, babylonTexture) {
+        var textureIndex = this._getTextureIndex(babylonTexture);
+        if (textureIndex > -1) {
+            this._textureInfos[textureIndex] = textureInfo;
+        }
+    };
+    KHR_materials_sheen.prototype.postExportMaterialAdditionalTextures = function (context, node, babylonMaterial) {
+        if (babylonMaterial instanceof babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__["PBRMaterial"]) {
+            if (babylonMaterial.sheen.isEnabled && babylonMaterial.sheen.texture) {
+                this._exportedTextures.push(babylonMaterial.sheen.texture);
+                return [babylonMaterial.sheen.texture];
+            }
+        }
+        return [];
+    };
+    KHR_materials_sheen.prototype.postExportMaterialAsync = function (context, node, babylonMaterial) {
+        var _this = this;
+        return new Promise(function (resolve, reject) {
+            if (babylonMaterial instanceof babylonjs_Materials_PBR_pbrMaterial__WEBPACK_IMPORTED_MODULE_1__["PBRMaterial"]) {
+                if (!babylonMaterial.sheen.isEnabled) {
+                    resolve(node);
+                    return;
+                }
+                _this._wasUsed = true;
+                if (node.extensions == null) {
+                    node.extensions = {};
+                }
+                var sheenInfo = {
+                    colorFactor: babylonMaterial.sheen.color.asArray(),
+                    intensityFactor: babylonMaterial.sheen.intensity
+                };
+                if (babylonMaterial.sheen.texture) {
+                    var textureIndex = _this._getTextureIndex(babylonMaterial.sheen.texture);
+                    if (textureIndex > -1) {
+                        sheenInfo.colorIntensityTexture = _this._textureInfos[textureIndex];
+                    }
+                }
+                node.extensions[NAME] = sheenInfo;
+            }
+            resolve(node);
+        });
+    };
+    return KHR_materials_sheen;
+}());
+
+_glTFExporter__WEBPACK_IMPORTED_MODULE_0__["_Exporter"].RegisterExtension(NAME, function (exporter) { return new KHR_materials_sheen(exporter); });
+
+
+/***/ }),
+
 /***/ "./glTF/2.0/Extensions/KHR_texture_transform.ts":
 /*!******************************************************!*\
   !*** ./glTF/2.0/Extensions/KHR_texture_transform.ts ***!
@@ -721,16 +810,59 @@ var NAME = "KHR_texture_transform";
  */
 var KHR_texture_transform = /** @class */ (function () {
     function KHR_texture_transform(exporter) {
+        this._recordedTextures = [];
         /** Name of this extension */
         this.name = NAME;
         /** Defines whether this extension is enabled */
         this.enabled = true;
         /** Defines whether this extension is required */
         this.required = false;
-        this._exporter = exporter;
+        /** Reference to the glTF exporter */
+        this._wasUsed = false;
     }
     KHR_texture_transform.prototype.dispose = function () {
-        delete this._exporter;
+        for (var _i = 0, _a = this._recordedTextures; _i < _a.length; _i++) {
+            var texture = _a[_i];
+            texture.dispose();
+        }
+    };
+    Object.defineProperty(KHR_texture_transform.prototype, "wasUsed", {
+        /** @hidden */
+        get: function () {
+            return this._wasUsed;
+        },
+        enumerable: true,
+        configurable: true
+    });
+    KHR_texture_transform.prototype.postExportTexture = function (context, textureInfo, babylonTexture) {
+        if (babylonTexture && babylonTexture.uRotationCenter === 0 && babylonTexture.vRotationCenter === 0) {
+            var textureTransform = {};
+            var transformIsRequired = false;
+            if (babylonTexture.uOffset !== 0 || babylonTexture.vOffset !== 0) {
+                textureTransform.offset = [babylonTexture.uOffset, babylonTexture.vOffset];
+                transformIsRequired = true;
+            }
+            if (babylonTexture.uScale !== 1 || babylonTexture.vScale !== 1) {
+                textureTransform.scale = [babylonTexture.uScale, babylonTexture.vScale];
+                transformIsRequired = true;
+            }
+            if (babylonTexture.wAng !== 0) {
+                textureTransform.rotation = babylonTexture.wAng;
+                transformIsRequired = true;
+            }
+            if (babylonTexture.coordinatesIndex !== 0) {
+                textureTransform.texCoord = babylonTexture.coordinatesIndex;
+                transformIsRequired = true;
+            }
+            if (!transformIsRequired) {
+                return;
+            }
+            this._wasUsed = true;
+            if (!textureInfo.extensions) {
+                textureInfo.extensions = {};
+            }
+            textureInfo.extensions[NAME] = textureTransform;
+        }
     };
     KHR_texture_transform.prototype.preExportTextureAsync = function (context, babylonTexture, mimeType) {
         var _this = this;
@@ -740,18 +872,22 @@ var KHR_texture_transform = /** @class */ (function () {
                 reject(context + ": \"scene\" is not defined for Babylon texture " + babylonTexture.name + "!");
                 return;
             }
-            // TODO: this doesn't take into account rotation center values
-            var texture_transform_extension = {};
+            var transformIsRequired = false;
             if (babylonTexture.uOffset !== 0 || babylonTexture.vOffset !== 0) {
-                texture_transform_extension.offset = [babylonTexture.uOffset, babylonTexture.vOffset];
+                transformIsRequired = true;
             }
             if (babylonTexture.uScale !== 1 || babylonTexture.vScale !== 1) {
-                texture_transform_extension.scale = [babylonTexture.uScale, babylonTexture.vScale];
+                transformIsRequired = true;
             }
             if (babylonTexture.wAng !== 0) {
-                texture_transform_extension.rotation = babylonTexture.wAng;
+                transformIsRequired = true;
+            }
+            if (!transformIsRequired) {
+                resolve(babylonTexture);
+                return;
             }
-            if (!Object.keys(texture_transform_extension).length) {
+            // Do we need to flatten the transform?
+            if (babylonTexture.uRotationCenter === 0 && babylonTexture.vRotationCenter === 0) {
                 resolve(babylonTexture);
                 return;
             }
@@ -773,12 +909,19 @@ var KHR_texture_transform = /** @class */ (function () {
      * @param scene
      */
     KHR_texture_transform.prototype._textureTransformTextureAsync = function (babylonTexture, scene) {
+        var _this = this;
         return new Promise(function (resolve) {
             var proceduralTexture = new babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["ProceduralTexture"]("" + babylonTexture.name, babylonTexture.getSize(), "textureTransform", scene);
             if (!proceduralTexture) {
                 babylonjs_Misc_tools__WEBPACK_IMPORTED_MODULE_0__["Tools"].Log("Cannot create procedural texture for " + babylonTexture.name + "!");
                 resolve(babylonTexture);
             }
+            proceduralTexture.reservedDataStore = {
+                hidden: true,
+                source: babylonTexture
+            };
+            _this._recordedTextures.push(proceduralTexture);
+            proceduralTexture.coordinatesIndex = babylonTexture.coordinatesIndex;
             proceduralTexture.setTexture("textureSampler", babylonTexture);
             proceduralTexture.setMatrix("textureTransformMat", babylonTexture.getTextureMatrix());
             // isReady trigger creation of effect if it doesnt exist yet
@@ -806,7 +949,7 @@ _glTFExporter__WEBPACK_IMPORTED_MODULE_1__["_Exporter"].RegisterExtension(NAME,
 /*!**************************************!*\
   !*** ./glTF/2.0/Extensions/index.ts ***!
   \**************************************/
-/*! exports provided: KHR_texture_transform, KHR_lights_punctual */
+/*! exports provided: KHR_texture_transform, KHR_lights_punctual, KHR_materials_sheen */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -817,6 +960,10 @@ __webpack_require__.r(__webpack_exports__);
 /* harmony import */ var _KHR_lights_punctual__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./KHR_lights_punctual */ "./glTF/2.0/Extensions/KHR_lights_punctual.ts");
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return _KHR_lights_punctual__WEBPACK_IMPORTED_MODULE_1__["KHR_lights_punctual"]; });
 
+/* harmony import */ var _KHR_materials_sheen__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./KHR_materials_sheen */ "./glTF/2.0/Extensions/KHR_materials_sheen.ts");
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return _KHR_materials_sheen__WEBPACK_IMPORTED_MODULE_2__["KHR_materials_sheen"]; });
+
+
 
 
 
@@ -1595,7 +1742,6 @@ __webpack_require__.r(__webpack_exports__);
 
 
 
-
 /**
  * Converts Babylon Scene into glTF 2.0.
  * @hidden
@@ -1630,60 +1776,107 @@ var _Exporter = /** @class */ (function () {
         this._glTFMaterialExporter = new _glTFMaterialExporter__WEBPACK_IMPORTED_MODULE_2__["_GLTFMaterialExporter"](this);
         this._loadExtensions();
     }
-    _Exporter.prototype._applyExtensions = function (property, actionAsync) {
+    _Exporter.prototype._applyExtension = function (node, extensions, index, actionAsync) {
+        var _this = this;
+        if (index >= extensions.length) {
+            return Promise.resolve(node);
+        }
+        var currentPromise = actionAsync(extensions[index], node);
+        if (!currentPromise) {
+            return this._applyExtension(node, extensions, index + 1, actionAsync);
+        }
+        return currentPromise.then(function (newNode) { return _this._applyExtension(newNode || node, extensions, index + 1, actionAsync); });
+    };
+    _Exporter.prototype._applyExtensions = function (node, actionAsync) {
+        var extensions = [];
         for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
             var name_1 = _a[_i];
-            var extension = this._extensions[name_1];
-            if (extension.enabled) {
-                var exporterProperty = property;
-                exporterProperty._activeLoaderExtensions = exporterProperty._activeLoaderExtensions || {};
-                var activeLoaderExtensions = exporterProperty._activeLoaderExtensions;
-                if (!activeLoaderExtensions[name_1]) {
-                    activeLoaderExtensions[name_1] = true;
-                    try {
-                        var result = actionAsync(extension);
-                        if (result) {
-                            return result;
-                        }
-                    }
-                    finally {
-                        delete activeLoaderExtensions[name_1];
-                        delete exporterProperty._activeLoaderExtensions;
-                    }
-                }
-            }
+            extensions.push(this._extensions[name_1]);
         }
-        return null;
+        return this._applyExtension(node, extensions, 0, actionAsync);
     };
     _Exporter.prototype._extensionsPreExportTextureAsync = function (context, babylonTexture, mimeType) {
-        return this._applyExtensions(babylonTexture, function (extension) { return extension.preExportTextureAsync && extension.preExportTextureAsync(context, babylonTexture, mimeType); });
+        return this._applyExtensions(babylonTexture, function (extension, node) { return extension.preExportTextureAsync && extension.preExportTextureAsync(context, node, mimeType); });
     };
     _Exporter.prototype._extensionsPostExportMeshPrimitiveAsync = function (context, meshPrimitive, babylonSubMesh, binaryWriter) {
-        return this._applyExtensions(meshPrimitive, function (extension) { return extension.postExportMeshPrimitiveAsync && extension.postExportMeshPrimitiveAsync(context, meshPrimitive, babylonSubMesh, binaryWriter); });
+        return this._applyExtensions(meshPrimitive, function (extension, node) { return extension.postExportMeshPrimitiveAsync && extension.postExportMeshPrimitiveAsync(context, node, babylonSubMesh, binaryWriter); });
     };
     _Exporter.prototype._extensionsPostExportNodeAsync = function (context, node, babylonNode) {
-        return this._applyExtensions(node, function (extension) { return extension.postExportNodeAsync && extension.postExportNodeAsync(context, node, babylonNode); });
+        return this._applyExtensions(node, function (extension, node) { return extension.postExportNodeAsync && extension.postExportNodeAsync(context, node, babylonNode); });
     };
-    _Exporter.prototype._forEachExtensions = function (action) {
+    _Exporter.prototype._extensionsPostExportMaterialAsync = function (context, material, babylonMaterial) {
+        return this._applyExtensions(material, function (extension, node) { return extension.postExportMaterialAsync && extension.postExportMaterialAsync(context, node, babylonMaterial); });
+    };
+    _Exporter.prototype._extensionsPostExportMaterialAdditionalTextures = function (context, material, babylonMaterial) {
+        var output = [];
         for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
             var name_2 = _a[_i];
             var extension = this._extensions[name_2];
+            if (extension.postExportMaterialAdditionalTextures) {
+                output.push.apply(output, extension.postExportMaterialAdditionalTextures(context, material, babylonMaterial));
+            }
+        }
+        return output;
+    };
+    _Exporter.prototype._extensionsPostExportTextures = function (context, textureInfo, babylonTexture) {
+        for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
+            var name_3 = _a[_i];
+            var extension = this._extensions[name_3];
+            if (extension.postExportTexture) {
+                extension.postExportTexture(context, textureInfo, babylonTexture);
+            }
+        }
+    };
+    _Exporter.prototype._forEachExtensions = function (action) {
+        for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
+            var name_4 = _a[_i];
+            var extension = this._extensions[name_4];
             if (extension.enabled) {
                 action(extension);
             }
         }
     };
     _Exporter.prototype._extensionsOnExporting = function () {
-        this._forEachExtensions(function (extension) { return extension.onExporting && extension.onExporting(); });
+        var _this = this;
+        this._forEachExtensions(function (extension) {
+            if (extension.wasUsed) {
+                if (_this._glTF.extensionsUsed == null) {
+                    _this._glTF.extensionsUsed = [];
+                }
+                if (_this._glTF.extensionsUsed.indexOf(extension.name) === -1) {
+                    _this._glTF.extensionsUsed.push(extension.name);
+                }
+                if (extension.required) {
+                    if (_this._glTF.extensionsRequired == null) {
+                        _this._glTF.extensionsRequired = [];
+                    }
+                    if (_this._glTF.extensionsRequired.indexOf(extension.name) === -1) {
+                        _this._glTF.extensionsRequired.push(extension.name);
+                    }
+                }
+                if (_this._glTF.extensions == null) {
+                    _this._glTF.extensions = {};
+                }
+                if (extension.onExporting) {
+                    extension.onExporting();
+                }
+            }
+        });
     };
     /**
      * Load glTF serializer extensions
      */
     _Exporter.prototype._loadExtensions = function () {
         for (var _i = 0, _a = _Exporter._ExtensionNames; _i < _a.length; _i++) {
-            var name_3 = _a[_i];
-            var extension = _Exporter._ExtensionFactories[name_3](this);
-            this._extensions[name_3] = extension;
+            var name_5 = _a[_i];
+            var extension = _Exporter._ExtensionFactories[name_5](this);
+            this._extensions[name_5] = extension;
+        }
+    };
+    _Exporter.prototype.dispose = function () {
+        for (var extensionKey in this._extensions) {
+            var extension = this._extensions[extensionKey];
+            extension.dispose();
         }
     };
     /**
@@ -2182,10 +2375,12 @@ var _Exporter = /** @class */ (function () {
     /**
      * Generates data for .gltf and .bin files based on the glTF prefix string
      * @param glTFPrefix Text to use when prefixing a glTF file
+     * @param dispose Dispose the exporter
      * @returns GLTFData with glTF file data
      */
-    _Exporter.prototype._generateGLTFAsync = function (glTFPrefix) {
+    _Exporter.prototype._generateGLTFAsync = function (glTFPrefix, dispose) {
         var _this = this;
+        if (dispose === void 0) { dispose = true; }
         return this._generateBinaryAsync().then(function (binaryBuffer) {
             _this._extensionsOnExporting();
             var jsonText = _this.generateJSON(false, glTFPrefix, true);
@@ -2200,6 +2395,9 @@ var _Exporter = /** @class */ (function () {
                     container.glTFFiles[image] = new Blob([_this._imageData[image].data], { type: _this._imageData[image].mimeType });
                 }
             }
+            if (dispose) {
+                _this.dispose();
+            }
             return container;
         });
     };
@@ -2228,13 +2426,11 @@ var _Exporter = /** @class */ (function () {
         return padding;
     };
     /**
-     * Generates a glb file from the json and binary data
-     * Returns an object with the glb file name as the key and data as the value
-     * @param glTFPrefix
-     * @returns object with glb filename as key and data as value
+     * @hidden
      */
-    _Exporter.prototype._generateGLBAsync = function (glTFPrefix) {
+    _Exporter.prototype._generateGLBAsync = function (glTFPrefix, dispose) {
         var _this = this;
+        if (dispose === void 0) { dispose = true; }
         return this._generateBinaryAsync().then(function (binaryBuffer) {
             _this._extensionsOnExporting();
             var jsonText = _this.generateJSON(true);
@@ -2300,6 +2496,9 @@ var _Exporter = /** @class */ (function () {
             if (_this._localEngine != null) {
                 _this._localEngine.dispose();
             }
+            if (dispose) {
+                _this.dispose();
+            }
             return container;
         });
     };
@@ -2709,12 +2908,12 @@ var _Exporter = /** @class */ (function () {
                         }
                         else {
                             return promise.then(function (node) {
-                                var directDescendents = babylonNode.getDescendants(true, function (node) { return (node instanceof babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_1__["Node"]); });
-                                if (directDescendents.length || node.mesh != null || (node.extensions)) {
-                                    _this._nodes.push(node);
-                                    nodeIndex = _this._nodes.length - 1;
-                                    nodeMap[babylonNode.uniqueId] = nodeIndex;
+                                if (!node) {
+                                    return;
                                 }
+                                _this._nodes.push(node);
+                                nodeIndex = _this._nodes.length - 1;
+                                nodeMap[babylonNode.uniqueId] = nodeIndex;
                                 if (!babylonScene.animationGroups.length && babylonNode.animations.length) {
                                     _glTFAnimation__WEBPACK_IMPORTED_MODULE_5__["_GLTFAnimation"]._CreateNodeAnimationFromNodeAnimations(babylonNode, runtimeGLTFAnimation, idleGLTFAnimations, nodeMap, _this._nodes, binaryWriter, _this._bufferViews, _this._accessors, _this._convertToRightHandedSystem, _this._animationSampleRate);
                                 }
@@ -3251,7 +3450,31 @@ var _GLTFMaterialExporter = /** @class */ (function () {
         _GLTFMaterialExporter._SetAlphaMode(glTFMaterial, babylonStandardMaterial);
         materials.push(glTFMaterial);
         materialMap[babylonStandardMaterial.uniqueId] = materials.length - 1;
-        return Promise.all(promises).then(function () { });
+        return this._finishMaterial(promises, glTFMaterial, babylonStandardMaterial, mimeType);
+    };
+    _GLTFMaterialExporter.prototype._finishMaterial = function (promises, glTFMaterial, babylonMaterial, mimeType) {
+        var _this = this;
+        return Promise.all(promises).then(function () {
+            var textures = _this._exporter._extensionsPostExportMaterialAdditionalTextures("exportMaterial", glTFMaterial, babylonMaterial);
+            var tasks = null;
+            for (var _i = 0, textures_1 = textures; _i < textures_1.length; _i++) {
+                var texture = textures_1[_i];
+                if (!tasks) {
+                    tasks = [];
+                }
+                tasks.push(_this._exportTextureAsync(texture, mimeType));
+            }
+            if (!tasks) {
+                tasks = [Promise.resolve(null)];
+            }
+            return Promise.all(tasks).then(function () {
+                var extensionWork = _this._exporter._extensionsPostExportMaterialAsync("exportMaterial", glTFMaterial, babylonMaterial);
+                if (!extensionWork) {
+                    return glTFMaterial;
+                }
+                return extensionWork.then(function () { return glTFMaterial; });
+            });
+        });
     };
     /**
      * Converts a Babylon PBR Metallic Roughness Material to a glTF Material
@@ -3331,7 +3554,7 @@ var _GLTFMaterialExporter = /** @class */ (function () {
         glTFMaterial.pbrMetallicRoughness = glTFPbrMetallicRoughness;
         materials.push(glTFMaterial);
         materialMap[babylonPBRMetalRoughMaterial.uniqueId] = materials.length - 1;
-        return Promise.all(promises).then(function () { });
+        return this._finishMaterial(promises, glTFMaterial, babylonPBRMetalRoughMaterial, mimeType);
     };
     /**
      * Converts an image typed array buffer to a base64 image
@@ -3892,7 +4115,8 @@ var _GLTFMaterialExporter = /** @class */ (function () {
                     var promise = this._exportTextureAsync(babylonPBRMaterial.ambientTexture, mimeType).then(function (glTFTexture) {
                         if (glTFTexture) {
                             var occlusionTexture = {
-                                index: glTFTexture.index
+                                index: glTFTexture.index,
+                                texCoord: glTFTexture.texCoord
                             };
                             glTFMaterial.occlusionTexture = occlusionTexture;
                             if (babylonPBRMaterial.ambientTextureStrength) {
@@ -3918,7 +4142,7 @@ var _GLTFMaterialExporter = /** @class */ (function () {
             materials.push(glTFMaterial);
             materialMap[babylonPBRMaterial.uniqueId] = materials.length - 1;
         }
-        return Promise.all(promises).then(function (result) { });
+        return this._finishMaterial(promises, glTFMaterial, babylonPBRMaterial, mimeType);
     };
     _GLTFMaterialExporter.prototype.getPixelsFromTexture = function (babylonTexture) {
         var pixels = babylonTexture.textureType === babylonjs_Maths_math__WEBPACK_IMPORTED_MODULE_0__["Constants"].TEXTURETYPE_UNSIGNED_INT ? babylonTexture.readPixels() : babylonTexture.readPixels();
@@ -3977,6 +4201,7 @@ var _GLTFMaterialExporter = /** @class */ (function () {
                     var textureInfo = _this._getTextureInfoFromBase64(base64Data, babylonTexture.name.replace(/\.\/|\/|\.\\|\\/g, "_"), mimeType, babylonTexture.coordinatesIndex, samplerIndex_1);
                     if (textureInfo) {
                         _this._textureMap[textureUid] = textureInfo;
+                        _this._exporter._extensionsPostExportTextures("linkTextureInfo", textureInfo, babylonTexture);
                     }
                     return textureInfo;
                 });
@@ -4344,7 +4569,7 @@ var _GLTFUtilities = /** @class */ (function () {
 /*!***************************!*\
   !*** ./glTF/2.0/index.ts ***!
   \***************************/
-/*! exports provided: GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual */
+/*! exports provided: GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual, KHR_materials_sheen */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -4377,6 +4602,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_7__["KHR_lights_punctual"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return _Extensions__WEBPACK_IMPORTED_MODULE_7__["KHR_materials_sheen"]; });
+
 
 
 
@@ -4431,7 +4658,7 @@ var __IGLTFExporterExtension = 0; // I am here to allow dts to be created
 /*!***********************!*\
   !*** ./glTF/index.ts ***!
   \***********************/
-/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual */
+/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual, KHR_materials_sheen */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -4460,6 +4687,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return _2_0__WEBPACK_IMPORTED_MODULE_1__["KHR_lights_punctual"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return _2_0__WEBPACK_IMPORTED_MODULE_1__["KHR_materials_sheen"]; });
+
 
 
 
@@ -4470,7 +4699,7 @@ __webpack_require__.r(__webpack_exports__);
 /*!******************!*\
   !*** ./index.ts ***!
   \******************/
-/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, OBJExport, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, STLExport, KHR_texture_transform, KHR_lights_punctual */
+/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, OBJExport, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, STLExport, KHR_texture_transform, KHR_lights_punctual, KHR_materials_sheen */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -4501,6 +4730,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return _glTF__WEBPACK_IMPORTED_MODULE_1__["KHR_lights_punctual"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return _glTF__WEBPACK_IMPORTED_MODULE_1__["KHR_materials_sheen"]; });
+
 /* harmony import */ var _stl__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./stl */ "./stl/index.ts");
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "STLExport", function() { return _stl__WEBPACK_IMPORTED_MODULE_2__["STLExport"]; });
 
@@ -4515,7 +4746,7 @@ __webpack_require__.r(__webpack_exports__);
 /*!******************************************!*\
   !*** ./legacy/legacy-glTF2Serializer.ts ***!
   \******************************************/
-/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual */
+/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, KHR_texture_transform, KHR_lights_punctual, KHR_materials_sheen */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -4547,6 +4778,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return _glTF_2_0__WEBPACK_IMPORTED_MODULE_4__["KHR_lights_punctual"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return _glTF_2_0__WEBPACK_IMPORTED_MODULE_4__["KHR_materials_sheen"]; });
+
 
 
 
@@ -4657,7 +4890,7 @@ if (typeof globalObject !== "undefined") {
 /*!**************************!*\
   !*** ./legacy/legacy.ts ***!
   \**************************/
-/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, OBJExport, STLExport, KHR_texture_transform, KHR_lights_punctual */
+/*! exports provided: __IGLTFExporterExtension, GLTFData, GLTF2Export, _GLTFAnimation, _Exporter, _BinaryWriter, __IGLTFExporterExtensionV2, _GLTFMaterialExporter, _GLTFUtilities, OBJExport, STLExport, KHR_texture_transform, KHR_lights_punctual, KHR_materials_sheen */
 /***/ (function(module, __webpack_exports__, __webpack_require__) {
 
 "use strict";
@@ -4686,6 +4919,8 @@ __webpack_require__.r(__webpack_exports__);
 
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_lights_punctual", function() { return _legacy_glTF2Serializer__WEBPACK_IMPORTED_MODULE_1__["KHR_lights_punctual"]; });
 
+/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "KHR_materials_sheen", function() { return _legacy_glTF2Serializer__WEBPACK_IMPORTED_MODULE_1__["KHR_materials_sheen"]; });
+
 /* harmony import */ var _legacy_objSerializer__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./legacy-objSerializer */ "./legacy/legacy-objSerializer.ts");
 /* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "OBJExport", function() { return _legacy_objSerializer__WEBPACK_IMPORTED_MODULE_2__["OBJExport"]; });
 

File diff suppressed because it is too large
+ 1 - 1
dist/preview release/serializers/babylonjs.serializers.js.map


File diff suppressed because it is too large
+ 2 - 2
dist/preview release/serializers/babylonjs.serializers.min.js


+ 173 - 46
dist/preview release/serializers/babylonjs.serializers.module.d.ts

@@ -47,14 +47,15 @@ declare module "babylonjs-serializers/glTF/glTFFileExporter" {
     }
 }
 declare module "babylonjs-serializers/glTF/2.0/glTFExporterExtension" {
-    import { ImageMimeType, IMeshPrimitive, INode } from "babylonjs-gltf2interface";
+    import { ImageMimeType, IMeshPrimitive, INode, IMaterial, ITextureInfo } from "babylonjs-gltf2interface";
     import { Node } from "babylonjs/node";
-    import { Nullable } from "babylonjs/types";
     import { Texture } from "babylonjs/Materials/Textures/texture";
     import { SubMesh } from "babylonjs/Meshes/subMesh";
     import { IDisposable } from "babylonjs/scene";
     import { _BinaryWriter } from "babylonjs-serializers/glTF/2.0/glTFExporter";
     import { IGLTFExporterExtension } from "babylonjs-serializers/glTF/glTFFileExporter";
+    import { Material } from 'babylonjs/Materials/material';
+    import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture';
     /** @hidden */
     export var __IGLTFExporterExtensionV2: number;
     /**
@@ -65,11 +66,18 @@ declare module "babylonjs-serializers/glTF/2.0/glTFExporterExtension" {
         /**
          * Define this method to modify the default behavior before exporting a texture
          * @param context The context when loading the asset
-         * @param babylonTexture The glTF texture info property
+         * @param babylonTexture The Babylon.js texture
          * @param mimeType The mime-type of the generated image
-         * @returns A promise that resolves with the exported glTF texture info when the export is complete, or null if not handled
+         * @returns A promise that resolves with the exported texture
+         */
+        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Texture>;
+        /**
+         * Define this method to get notified when a texture info is created
+         * @param context The context when loading the asset
+         * @param textureInfo The glTF texture info
+         * @param babylonTexture The Babylon.js texture
          */
-        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        postExportTexture?(context: string, textureInfo: ITextureInfo, babylonTexture: BaseTexture): void;
         /**
          * Define this method to modify the default behavior when exporting texture info
          * @param context The context when loading the asset
@@ -78,7 +86,7 @@ declare module "babylonjs-serializers/glTF/2.0/glTFExporterExtension" {
          * @param binaryWriter glTF serializer binary writer instance
          * @returns nullable IMeshPrimitive promise
          */
-        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Promise<IMeshPrimitive>;
         /**
          * Define this method to modify the default behavior when exporting a node
          * @param context The context when exporting the node
@@ -86,7 +94,25 @@ declare module "babylonjs-serializers/glTF/2.0/glTFExporterExtension" {
          * @param babylonNode BabylonJS node
          * @returns nullable INode promise
          */
-        postExportNodeAsync?(context: string, node: INode, babylonNode: Node): Nullable<Promise<INode>>;
+        postExportNodeAsync?(context: string, node: INode, babylonNode: Node): Promise<INode>;
+        /**
+         * Define this method to modify the default behavior when exporting a material
+         * @param material glTF material
+         * @param babylonMaterial BabylonJS material
+         * @returns nullable IMaterial promise
+         */
+        postExportMaterialAsync?(context: string, node: IMaterial, babylonMaterial: Material): Promise<IMaterial>;
+        /**
+         * Define this method to return additional textures to export from a material
+         * @param material glTF material
+         * @param babylonMaterial BabylonJS material
+         * @returns List of textures
+         */
+        postExportMaterialAdditionalTextures?(context: string, node: IMaterial, babylonMaterial: Material): BaseTexture[];
+        /** Gets a boolean indicating that this extension was used */
+        wasUsed: boolean;
+        /** Gets a boolean indicating that this extension is required for the file to work */
+        required: boolean;
         /**
          * Called after the exporter state changes to EXPORTING
          */
@@ -188,7 +214,8 @@ declare module "babylonjs-serializers/glTF/2.0/glTFMaterialExporter" {
          * @param imageData map of image file name to data
          * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
          */
-        _convertStandardMaterialAsync(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void>;
+        _convertStandardMaterialAsync(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<IMaterial>;
+        private _finishMaterial;
         /**
          * Converts a Babylon PBR Metallic Roughness Material to a glTF Material
          * @param babylonPBRMetalRoughMaterial BJS PBR Metallic Roughness Material
@@ -199,7 +226,7 @@ declare module "babylonjs-serializers/glTF/2.0/glTFMaterialExporter" {
          * @param imageData map of image file name to data
          * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
          */
-        _convertPBRMetallicRoughnessMaterialAsync(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void>;
+        _convertPBRMetallicRoughnessMaterialAsync(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<IMaterial>;
         /**
          * Converts an image typed array buffer to a base64 image
          * @param buffer typed array buffer
@@ -298,7 +325,7 @@ declare module "babylonjs-serializers/glTF/2.0/glTFMaterialExporter" {
          * @param imageData map of image file name to data
          * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
          */
-        _convertPBRMaterialAsync(babylonPBRMaterial: PBRMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void>;
+        _convertPBRMaterialAsync(babylonPBRMaterial: PBRMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<IMaterial>;
         private setMetallicRoughnessPbrMaterial;
         private getPixelsFromTexture;
         /**
@@ -495,13 +522,14 @@ declare module "babylonjs-serializers/glTF/2.0/glTFUtilities" {
     }
 }
 declare module "babylonjs-serializers/glTF/2.0/glTFExporter" {
-    import { IBufferView, IAccessor, INode, IMaterial, ITexture, IImage, ISampler, ImageMimeType, IMeshPrimitive, IGLTF } from "babylonjs-gltf2interface";
+    import { IBufferView, IAccessor, INode, IMaterial, ITexture, IImage, ISampler, ImageMimeType, IMeshPrimitive, IGLTF, ITextureInfo } from "babylonjs-gltf2interface";
     import { FloatArray, Nullable } from "babylonjs/types";
     import { Vector3, Vector4 } from "babylonjs/Maths/math";
     import { Node } from "babylonjs/node";
     import { SubMesh } from "babylonjs/Meshes/subMesh";
     import { BaseTexture } from "babylonjs/Materials/Textures/baseTexture";
     import { Texture } from "babylonjs/Materials/Textures/texture";
+    import { Material } from "babylonjs/Materials/material";
     import { Engine } from "babylonjs/Engines/engine";
     import { Scene } from "babylonjs/scene";
     import { IGLTFExporterExtensionV2 } from "babylonjs-serializers/glTF/2.0/glTFExporterExtension";
@@ -599,10 +627,14 @@ declare module "babylonjs-serializers/glTF/2.0/glTFExporter" {
         private _extensions;
         private static _ExtensionNames;
         private static _ExtensionFactories;
+        private _applyExtension;
         private _applyExtensions;
-        _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<BaseTexture>>;
-        _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
-        _extensionsPostExportNodeAsync(context: string, node: INode, babylonNode: Node): Nullable<Promise<INode>>;
+        _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Nullable<BaseTexture>>;
+        _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Promise<Nullable<IMeshPrimitive>>;
+        _extensionsPostExportNodeAsync(context: string, node: INode, babylonNode: Node): Promise<Nullable<INode>>;
+        _extensionsPostExportMaterialAsync(context: string, material: IMaterial, babylonMaterial: Material): Promise<Nullable<IMaterial>>;
+        _extensionsPostExportMaterialAdditionalTextures(context: string, material: IMaterial, babylonMaterial: Material): BaseTexture[];
+        _extensionsPostExportTextures(context: string, textureInfo: ITextureInfo, babylonTexture: BaseTexture): void;
         private _forEachExtensions;
         private _extensionsOnExporting;
         /**
@@ -615,6 +647,7 @@ declare module "babylonjs-serializers/glTF/2.0/glTFExporter" {
          * @param options Options to modify the behavior of the exporter
          */
         constructor(babylonScene: Scene, options?: IExportOptions);
+        dispose(): void;
         /**
          * Registers a glTF exporter extension
          * @param name Name of the extension to export
@@ -709,9 +742,10 @@ declare module "babylonjs-serializers/glTF/2.0/glTFExporter" {
         /**
          * Generates data for .gltf and .bin files based on the glTF prefix string
          * @param glTFPrefix Text to use when prefixing a glTF file
+         * @param dispose Dispose the exporter
          * @returns GLTFData with glTF file data
          */
-        _generateGLTFAsync(glTFPrefix: string): Promise<GLTFData>;
+        _generateGLTFAsync(glTFPrefix: string, dispose?: boolean): Promise<GLTFData>;
         /**
          * Creates a binary buffer for glTF
          * @returns array buffer for binary data
@@ -724,12 +758,9 @@ declare module "babylonjs-serializers/glTF/2.0/glTFExporter" {
          */
         private _getPadding;
         /**
-         * Generates a glb file from the json and binary data
-         * Returns an object with the glb file name as the key and data as the value
-         * @param glTFPrefix
-         * @returns object with glb filename as key and data as value
+         * @hidden
          */
-        _generateGLBAsync(glTFPrefix: string): Promise<GLTFData>;
+        _generateGLBAsync(glTFPrefix: string, dispose?: boolean): Promise<GLTFData>;
         /**
          * Sets the TRS for each node
          * @param node glTF Node for storing the transformation data
@@ -1048,8 +1079,7 @@ declare module "babylonjs-serializers/glTF/2.0/shaders/textureTransform.fragment
     };
 }
 declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_texture_transform" {
-    import { ImageMimeType } from "babylonjs-gltf2interface";
-    import { Nullable } from "babylonjs/types";
+    import { ImageMimeType, ITextureInfo } from "babylonjs-gltf2interface";
     import { Texture } from "babylonjs/Materials/Textures/texture";
     import { IGLTFExporterExtensionV2 } from "babylonjs-serializers/glTF/2.0/glTFExporterExtension";
     import { _Exporter } from "babylonjs-serializers/glTF/2.0/glTFExporter";
@@ -1058,6 +1088,7 @@ declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_texture_transform"
      * @hidden
      */
     export class KHR_texture_transform implements IGLTFExporterExtensionV2 {
+        private _recordedTextures;
         /** Name of this extension */
         readonly name: string;
         /** Defines whether this extension is enabled */
@@ -1065,10 +1096,13 @@ declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_texture_transform"
         /** Defines whether this extension is required */
         required: boolean;
         /** Reference to the glTF exporter */
-        private _exporter;
+        private _wasUsed;
         constructor(exporter: _Exporter);
         dispose(): void;
-        preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        /** @hidden */
+        readonly wasUsed: boolean;
+        postExportTexture?(context: string, textureInfo: ITextureInfo, babylonTexture: Texture): void;
+        preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Texture>;
         /**
          * Transform the babylon texture by the offset, rotation and scale parameters using a procedural texture
          * @param babylonTexture
@@ -1081,7 +1115,6 @@ declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_texture_transform"
     }
 }
 declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_lights_punctual" {
-    import { Nullable } from "babylonjs/types";
     import { Node } from "babylonjs/node";
     import { INode } from "babylonjs-gltf2interface";
     import { IGLTFExporterExtensionV2 } from "babylonjs-serializers/glTF/2.0/glTFExporterExtension";
@@ -1104,6 +1137,8 @@ declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_lights_punctual" {
         /** @hidden */
         dispose(): void;
         /** @hidden */
+        readonly wasUsed: boolean;
+        /** @hidden */
         onExporting(): void;
         /**
          * Define this method to modify the default behavior when exporting a node
@@ -1112,12 +1147,44 @@ declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_lights_punctual" {
          * @param babylonNode BabylonJS node
          * @returns nullable INode promise
          */
-        postExportNodeAsync(context: string, node: INode, babylonNode: Node): Nullable<Promise<INode>>;
+        postExportNodeAsync(context: string, node: INode, babylonNode: Node): Promise<INode>;
+    }
+}
+declare module "babylonjs-serializers/glTF/2.0/Extensions/KHR_materials_sheen" {
+    import { ITextureInfo, IMaterial } from "babylonjs-gltf2interface";
+    import { IGLTFExporterExtensionV2 } from "babylonjs-serializers/glTF/2.0/glTFExporterExtension";
+    import { _Exporter } from "babylonjs-serializers/glTF/2.0/glTFExporter";
+    import { Material } from 'babylonjs/Materials/material';
+    import { Texture } from 'babylonjs/Materials/Textures/texture';
+    import { BaseTexture } from 'babylonjs/Materials/Textures/baseTexture';
+    /**
+     * @hidden
+     */
+    export class KHR_materials_sheen implements IGLTFExporterExtensionV2 {
+        /** Name of this extension */
+        readonly name: string;
+        /** Defines whether this extension is enabled */
+        enabled: boolean;
+        /** Defines whether this extension is required */
+        required: boolean;
+        /** Reference to the glTF exporter */
+        private _textureInfos;
+        private _exportedTextures;
+        private _wasUsed;
+        constructor(exporter: _Exporter);
+        dispose(): void;
+        /** @hidden */
+        readonly wasUsed: boolean;
+        private _getTextureIndex;
+        postExportTexture?(context: string, textureInfo: ITextureInfo, babylonTexture: Texture): void;
+        postExportMaterialAdditionalTextures?(context: string, node: IMaterial, babylonMaterial: Material): BaseTexture[];
+        postExportMaterialAsync?(context: string, node: IMaterial, babylonMaterial: Material): Promise<IMaterial>;
     }
 }
 declare module "babylonjs-serializers/glTF/2.0/Extensions/index" {
     export * from "babylonjs-serializers/glTF/2.0/Extensions/KHR_texture_transform";
     export * from "babylonjs-serializers/glTF/2.0/Extensions/KHR_lights_punctual";
+    export * from "babylonjs-serializers/glTF/2.0/Extensions/KHR_materials_sheen";
 }
 declare module "babylonjs-serializers/glTF/2.0/index" {
     export * from "babylonjs-serializers/glTF/2.0/glTFAnimation";
@@ -1233,11 +1300,18 @@ declare module BABYLON.GLTF2.Exporter {
         /**
          * Define this method to modify the default behavior before exporting a texture
          * @param context The context when loading the asset
-         * @param babylonTexture The glTF texture info property
+         * @param babylonTexture The Babylon.js texture
          * @param mimeType The mime-type of the generated image
-         * @returns A promise that resolves with the exported glTF texture info when the export is complete, or null if not handled
+         * @returns A promise that resolves with the exported texture
+         */
+        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Texture>;
+        /**
+         * Define this method to get notified when a texture info is created
+         * @param context The context when loading the asset
+         * @param textureInfo The glTF texture info
+         * @param babylonTexture The Babylon.js texture
          */
-        preExportTextureAsync?(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        postExportTexture?(context: string, textureInfo: ITextureInfo, babylonTexture: BaseTexture): void;
         /**
          * Define this method to modify the default behavior when exporting texture info
          * @param context The context when loading the asset
@@ -1246,7 +1320,7 @@ declare module BABYLON.GLTF2.Exporter {
          * @param binaryWriter glTF serializer binary writer instance
          * @returns nullable IMeshPrimitive promise
          */
-        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
+        postExportMeshPrimitiveAsync?(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Promise<IMeshPrimitive>;
         /**
          * Define this method to modify the default behavior when exporting a node
          * @param context The context when exporting the node
@@ -1254,7 +1328,25 @@ declare module BABYLON.GLTF2.Exporter {
          * @param babylonNode BabylonJS node
          * @returns nullable INode promise
          */
-        postExportNodeAsync?(context: string, node: INode, babylonNode: Node): Nullable<Promise<INode>>;
+        postExportNodeAsync?(context: string, node: INode, babylonNode: Node): Promise<INode>;
+        /**
+         * Define this method to modify the default behavior when exporting a material
+         * @param material glTF material
+         * @param babylonMaterial BabylonJS material
+         * @returns nullable IMaterial promise
+         */
+        postExportMaterialAsync?(context: string, node: IMaterial, babylonMaterial: Material): Promise<IMaterial>;
+        /**
+         * Define this method to return additional textures to export from a material
+         * @param material glTF material
+         * @param babylonMaterial BabylonJS material
+         * @returns List of textures
+         */
+        postExportMaterialAdditionalTextures?(context: string, node: IMaterial, babylonMaterial: Material): BaseTexture[];
+        /** Gets a boolean indicating that this extension was used */
+        wasUsed: boolean;
+        /** Gets a boolean indicating that this extension is required for the file to work */
+        required: boolean;
         /**
          * Called after the exporter state changes to EXPORTING
          */
@@ -1348,7 +1440,8 @@ declare module BABYLON.GLTF2.Exporter {
          * @param imageData map of image file name to data
          * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
          */
-        _convertStandardMaterialAsync(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void>;
+        _convertStandardMaterialAsync(babylonStandardMaterial: StandardMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<IMaterial>;
+        private _finishMaterial;
         /**
          * Converts a Babylon PBR Metallic Roughness Material to a glTF Material
          * @param babylonPBRMetalRoughMaterial BJS PBR Metallic Roughness Material
@@ -1359,7 +1452,7 @@ declare module BABYLON.GLTF2.Exporter {
          * @param imageData map of image file name to data
          * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
          */
-        _convertPBRMetallicRoughnessMaterialAsync(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void>;
+        _convertPBRMetallicRoughnessMaterialAsync(babylonPBRMetalRoughMaterial: PBRMetallicRoughnessMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<IMaterial>;
         /**
          * Converts an image typed array buffer to a base64 image
          * @param buffer typed array buffer
@@ -1458,7 +1551,7 @@ declare module BABYLON.GLTF2.Exporter {
          * @param imageData map of image file name to data
          * @param hasTextureCoords specifies if texture coordinates are present on the submesh to determine if textures should be applied
          */
-        _convertPBRMaterialAsync(babylonPBRMaterial: PBRMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<void>;
+        _convertPBRMaterialAsync(babylonPBRMaterial: PBRMaterial, mimeType: ImageMimeType, hasTextureCoords: boolean): Promise<IMaterial>;
         private setMetallicRoughnessPbrMaterial;
         private getPixelsFromTexture;
         /**
@@ -1740,10 +1833,14 @@ declare module BABYLON.GLTF2.Exporter {
         private _extensions;
         private static _ExtensionNames;
         private static _ExtensionFactories;
+        private _applyExtension;
         private _applyExtensions;
-        _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<BaseTexture>>;
-        _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Nullable<Promise<IMeshPrimitive>>;
-        _extensionsPostExportNodeAsync(context: string, node: INode, babylonNode: Node): Nullable<Promise<INode>>;
+        _extensionsPreExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Nullable<BaseTexture>>;
+        _extensionsPostExportMeshPrimitiveAsync(context: string, meshPrimitive: IMeshPrimitive, babylonSubMesh: SubMesh, binaryWriter: _BinaryWriter): Promise<Nullable<IMeshPrimitive>>;
+        _extensionsPostExportNodeAsync(context: string, node: INode, babylonNode: Node): Promise<Nullable<INode>>;
+        _extensionsPostExportMaterialAsync(context: string, material: IMaterial, babylonMaterial: Material): Promise<Nullable<IMaterial>>;
+        _extensionsPostExportMaterialAdditionalTextures(context: string, material: IMaterial, babylonMaterial: Material): BaseTexture[];
+        _extensionsPostExportTextures(context: string, textureInfo: ITextureInfo, babylonTexture: BaseTexture): void;
         private _forEachExtensions;
         private _extensionsOnExporting;
         /**
@@ -1756,6 +1853,7 @@ declare module BABYLON.GLTF2.Exporter {
          * @param options Options to modify the behavior of the exporter
          */
         constructor(babylonScene: Scene, options?: IExportOptions);
+        dispose(): void;
         /**
          * Registers a glTF exporter extension
          * @param name Name of the extension to export
@@ -1850,9 +1948,10 @@ declare module BABYLON.GLTF2.Exporter {
         /**
          * Generates data for .gltf and .bin files based on the glTF prefix string
          * @param glTFPrefix Text to use when prefixing a glTF file
+         * @param dispose Dispose the exporter
          * @returns GLTFData with glTF file data
          */
-        _generateGLTFAsync(glTFPrefix: string): Promise<GLTFData>;
+        _generateGLTFAsync(glTFPrefix: string, dispose?: boolean): Promise<GLTFData>;
         /**
          * Creates a binary buffer for glTF
          * @returns array buffer for binary data
@@ -1865,12 +1964,9 @@ declare module BABYLON.GLTF2.Exporter {
          */
         private _getPadding;
         /**
-         * Generates a glb file from the json and binary data
-         * Returns an object with the glb file name as the key and data as the value
-         * @param glTFPrefix
-         * @returns object with glb filename as key and data as value
+         * @hidden
          */
-        _generateGLBAsync(glTFPrefix: string): Promise<GLTFData>;
+        _generateGLBAsync(glTFPrefix: string, dispose?: boolean): Promise<GLTFData>;
         /**
          * Sets the TRS for each node
          * @param node glTF Node for storing the transformation data
@@ -2186,6 +2282,7 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
      * @hidden
      */
     export class KHR_texture_transform implements IGLTFExporterExtensionV2 {
+        private _recordedTextures;
         /** Name of this extension */
         readonly name: string;
         /** Defines whether this extension is enabled */
@@ -2193,10 +2290,13 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
         /** Defines whether this extension is required */
         required: boolean;
         /** Reference to the glTF exporter */
-        private _exporter;
+        private _wasUsed;
         constructor(exporter: _Exporter);
         dispose(): void;
-        preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Nullable<Promise<Texture>>;
+        /** @hidden */
+        readonly wasUsed: boolean;
+        postExportTexture?(context: string, textureInfo: ITextureInfo, babylonTexture: Texture): void;
+        preExportTextureAsync(context: string, babylonTexture: Texture, mimeType: ImageMimeType): Promise<Texture>;
         /**
          * Transform the babylon texture by the offset, rotation and scale parameters using a procedural texture
          * @param babylonTexture
@@ -2227,6 +2327,8 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
         /** @hidden */
         dispose(): void;
         /** @hidden */
+        readonly wasUsed: boolean;
+        /** @hidden */
         onExporting(): void;
         /**
          * Define this method to modify the default behavior when exporting a node
@@ -2235,7 +2337,32 @@ declare module BABYLON.GLTF2.Exporter.Extensions {
          * @param babylonNode BabylonJS node
          * @returns nullable INode promise
          */
-        postExportNodeAsync(context: string, node: INode, babylonNode: Node): Nullable<Promise<INode>>;
+        postExportNodeAsync(context: string, node: INode, babylonNode: Node): Promise<INode>;
+    }
+}
+declare module BABYLON.GLTF2.Exporter.Extensions {
+    /**
+     * @hidden
+     */
+    export class KHR_materials_sheen implements IGLTFExporterExtensionV2 {
+        /** Name of this extension */
+        readonly name: string;
+        /** Defines whether this extension is enabled */
+        enabled: boolean;
+        /** Defines whether this extension is required */
+        required: boolean;
+        /** Reference to the glTF exporter */
+        private _textureInfos;
+        private _exportedTextures;
+        private _wasUsed;
+        constructor(exporter: _Exporter);
+        dispose(): void;
+        /** @hidden */
+        readonly wasUsed: boolean;
+        private _getTextureIndex;
+        postExportTexture?(context: string, textureInfo: ITextureInfo, babylonTexture: Texture): void;
+        postExportMaterialAdditionalTextures?(context: string, node: IMaterial, babylonMaterial: Material): BaseTexture[];
+        postExportMaterialAsync?(context: string, node: IMaterial, babylonMaterial: Material): Promise<IMaterial>;
     }
 }
 declare module BABYLON {

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

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

File diff suppressed because it is too large
+ 2439 - 203
dist/preview release/viewer/babylon.module.d.ts


File diff suppressed because it is too large
+ 183 - 143
dist/preview release/viewer/babylon.viewer.js


File diff suppressed because it is too large
+ 3 - 3
dist/preview release/viewer/babylon.viewer.max.js


+ 17 - 0
dist/preview release/what's new.md

@@ -35,6 +35,7 @@
 - Display Oculus Quest controller when using a Quest in WebVR ([TrevorDev](https://github.com/TrevorDev))
 - Added startAndReleaseDragOnPointerEvents property to pointerDragBehavior which can be set to false for custom drag triggering ([TrevorDev](https://github.com/TrevorDev))
 - Added optional picking predicate to pointerDragBehavior for filtering affected meshes ([Exolun](https://github.com/Exolun))
+- Added accessor functions for `PointerDragBehavior._options` ([Popov72](https://github.com/Popov72))
 - Effect renderer to render one or multiple shader effects to a texture ([TrevorDev](https://github.com/TrevorDev))
 - Added url parameters to web request modifiers ([PierreLeBlond](https://github.com/PierreLeBlond))
 - Added `VRExperienceHelper.exitVROnDoubleTap` ([Deltakosh](https://github.com/deltakosh/))
@@ -48,6 +49,7 @@
 - Added various (interpolation) functions to Path3D, also `alignTangentsWithPath`, `slice`, `getClosestPositionTo` ([Poolminer](https://github.com/Poolminer/))
 - Allow setting of `BABYLON.Basis.JSModuleURL` and `BABYLON.Basis.WasmModuleURL`, for hosting the Basis transcoder locally ([JasonAyre])(https://github.com/jasonyre))
 - PNG support for browsers not supporting SVG ([RaananW](https://github.com/RaananW/))
+- Device orientation event permissions for iOS 13+ ([RaananW](https://github.com/RaananW/))
 
 ### Engine
 
@@ -73,6 +75,8 @@
 - Added support for inspectable strings ([Deltakosh](https://github.com/deltakosh/))
 - Added support for CreateScreenshotUsingRenderTarget ([13djwright](https://github.com/13djwright/))
 - Added support for `Material.depthFunction` property ([Popov72](https://github.com/Popov72))
+- Added an optional config option `initialTab` ([ycw](https://github.com/ycw/)) 
+- Added support for ImportAnimations ([noalak](https://github.com/noalak/))
 
 ### Tools
 
@@ -121,6 +125,7 @@
 - Added support for GLTF sheen extension [Sebavan](https://github.com/sebavan/)
 - Added support for GLTF mesh quantization extension ([zeux](https://github.com/zeux))
 - Added support for 8 bone influences to glTF loader ([zeux](https://github.com/zeux))
+- Added support for animations import from separate files ([noalak](https://github.com/noalak/))
 
 ### Materials
 
@@ -132,6 +137,7 @@
 - Added `pbrBRDFConfiguration.useSpecularGlossinessInputEnergyConservation` to allow Specular-Workflow energy conservation to be turned off ([ColorDigital-PS](https://github.com/ColorDigital-PS)).
 - Added support for the `freeze` / `unfreeze` functions in `ShaderMaterial` ([Popov72](https://github.com/Popov72))
 - Added `depthFunction` new property to `Material` base class ([Popov72](https://github.com/Popov72))
+- Added `setCompressedTextureExclusions` method to `Engine` to allow for skipping compressed textures on certain files ([abogartz](https://github.com/abogartz))
 
 ### ScreenshotTools
 
@@ -147,6 +153,8 @@
 
 - SpritePackedManager extends SpriteManager so that a sprite sheet with different size sprites can be used ([JohnK](https://github.com/BabylonJSGuide))
 - MultiPickSprite and multiPickSpriteWithRay added to sprites ([JohnK](https://github.com/BabylonJSGuide))
+- SpritePackedManager support for JSON Objects that where not stringified, of with the frames parameter accepting Objects and Arrays ([Pryme8](https://github.com/Pryme8))
+- Added `SpriteMap` for creation of grid-based dynamically animated sprite atlas rendering (Beta) ([Pryme8](https://github.com/Pryme8))
 
 ### WebXR / WebVR
 
@@ -165,6 +173,11 @@
 - VRExperienceHelper has now an XR fallback to force XR usage (Beta) ([RaananW](https://github.com/RaananW/))
 - Added option to change the teleportation easing function in the VRExperienceHelper class ([https://github.com/LeoRodz](https://github.com/LeoRodz))
 - Windows motion controller mapping corrected to XR ([RaananW](https://github.com/RaananW/))
+- Pointer-Event simulation for screen target ray mode ([RaananW](https://github.com/RaananW/))
+- New observable that triggers when a session was initialized ([RaananW](https://github.com/RaananW/))
+- WebXR teleportation can now be disabled after initialized ([RaananW](https://github.com/RaananW/))
+- New Features Manager for WebXR features ([RaananW](https://github.com/RaananW/))
+- New features - Plane detection, Hit Test, Background remover ([RaananW](https://github.com/RaananW/))
 
 ### Ray
 
@@ -244,6 +257,9 @@
 - WebXR UI BUtton will only change to "In XR" after XR Session started ([RaananW](https://github.com/RaananW/))
 - Fix bug when we call `Mesh.render` twice and the material is still not ready on the second call ([barroij](https://github.com/barroij/))
 - Fixed an issue with pose input in webxr ([RaananW](https://github.com/RaananW/))
+- Fixed bug when parsing animation group without 'to' value ([noalak](https://github.com/noalak/))
+- isRightCamer and isLeftCamera were not set in WebXR ([RaananW](https://github.com/RaananW/))
+- Sandbox will now load assets relatively path-ed to same folder([Kyle Belfort](https://github.com/belfortk))
 
 ## Breaking changes
 
@@ -253,3 +269,4 @@
 - Removed external data from Engine (`addExternalData`, `getExternalData`, `getOrAddExternalDataWithFactory`, `removeExternalData`) ([Deltakosh](https://github.com/deltakosh/))
 - The glTF loader extensions that map to glTF 2.0 extensions will now be disabled if the extension is not present in `extensionsUsed`. ([bghgary](https://github.com/bghgary))
 - The STL loader does not create light or camera automatically, please use `scene.createDefaultCameraOrLight();` in your code [Sebavan](https://github.com/sebavan/)
+- The glTF2 exporter extension no longer ignores childless empty nodes.([drigax](https://github.com/drigax))

+ 34 - 0
gui/src/2D/controls/image.ts

@@ -260,6 +260,28 @@ export class Image extends Control {
         this._markAsDirty();
     }
 
+    /** @hidden */
+    public _rotate90(n: number): Image {
+        let canvas = document.createElement('canvas');
+
+        const context = canvas.getContext('2d')!;
+        const width = this._domImage.width;
+        const height = this._domImage.height;
+
+        canvas.width = height;
+        canvas.height = width;
+
+        context.translate(canvas.width / 2, canvas.height / 2);
+        context.rotate(n * Math.PI / 2);
+
+        context.drawImage(this._domImage, 0, 0, width, height, -width / 2, -height / 2, width, height);
+
+        const dataUrl: string = canvas.toDataURL("image/jpg");
+        const rotatedImage = new Image(this.name + "rotated", dataUrl);
+
+        return rotatedImage;
+    }
+
     /**
      * Gets or sets the internal DOM image used to render the control
      */
@@ -384,6 +406,18 @@ export class Image extends Control {
             // check if object alr exist in document
             var svgExist = <HTMLObjectElement> document.body.querySelector('object[data="' + svgsrc + '"]');
             if (svgExist) {
+                var svgDoc = svgExist.contentDocument;
+                // get viewbox width and height, get svg document width and height in px
+                if (svgDoc && svgDoc.documentElement) {
+                    var vb = svgDoc.documentElement.getAttribute("viewBox");
+                    var docwidth = Number(svgDoc.documentElement.getAttribute("width"));
+                    var docheight = Number(svgDoc.documentElement.getAttribute("height"));
+                    if (vb && docwidth && docheight) {
+                        this._getSVGAttribs(svgExist, elemid);
+                        return value;
+                    }
+                }
+
                 // wait for object to load
                 svgExist.addEventListener("load", () => {
                     this._getSVGAttribs(svgExist, elemid);

+ 57 - 13
gui/src/2D/controls/sliders/imageScrollBar.ts

@@ -8,53 +8,97 @@ import { Measure } from "../../measure";
  * Class used to create slider controls
  */
 export class ImageScrollBar extends BaseSlider {
+    private _backgroundBaseImage: Image;
     private _backgroundImage: Image;
     private _thumbImage: Image;
+    private _thumbBaseImage: Image;
     private _thumbLength: number = 0.5;
     private _thumbHeight: number = 1;
     private _barImageHeight: number = 1;
     private _tempMeasure = new Measure(0, 0, 0, 0);
 
     /**
-     * Gets or sets the image used to render the background
+     * Gets or sets the image used to render the background for horizontal bar
      */
     public get backgroundImage(): Image {
-        return this._backgroundImage;
+        return this._backgroundBaseImage;
     }
 
     public set backgroundImage(value: Image) {
-        if (this._backgroundImage === value) {
+        if (this._backgroundBaseImage === value) {
             return;
         }
 
-        this._backgroundImage = value;
+        this._backgroundBaseImage = value;
 
-        if (value && !value.isLoaded) {
-            value.onImageLoadedObservable.addOnce(() => this._markAsDirty());
+        if (this.isVertical) {
+            if (value && !value.isLoaded) {
+                value.onImageLoadedObservable.addOnce(() => {
+                    const rotatedValue = value._rotate90(1);
+                    this._backgroundImage = rotatedValue;
+                    if (!rotatedValue.isLoaded) {
+                        rotatedValue.onImageLoadedObservable.addOnce(() => {
+                            this._markAsDirty();
+                        });
+                    }
+                    this._markAsDirty();
+                });
+            }
+            this._backgroundImage = value._rotate90(1);
+            this._markAsDirty();
         }
+        else {
+            this._backgroundImage = value;
+            if (value && !value.isLoaded) {
+                value.onImageLoadedObservable.addOnce(() => {
+                    this._markAsDirty();
+                });
+            }
 
-        this._markAsDirty();
+            this._markAsDirty();
+        }
     }
 
     /**
      * Gets or sets the image used to render the thumb
      */
     public get thumbImage(): Image {
-        return this._thumbImage;
+        return this._thumbBaseImage;
     }
 
     public set thumbImage(value: Image) {
-        if (this._thumbImage === value) {
+        if (this._thumbBaseImage === value) {
             return;
         }
 
-        this._thumbImage = value;
+        this._thumbBaseImage = value;
 
-        if (value && !value.isLoaded) {
-            value.onImageLoadedObservable.addOnce(() => this._markAsDirty());
+        if (this.isVertical) {
+            if (value && !value.isLoaded) {
+                value.onImageLoadedObservable.addOnce(() => {
+                    var rotatedValue = value._rotate90(-1);
+                    this._thumbImage = rotatedValue;
+                    if (!rotatedValue.isLoaded) {
+                        rotatedValue.onImageLoadedObservable.addOnce(() => {
+                            this._markAsDirty();
+                        });
+                    }
+                    this._markAsDirty();
+                });
+            }
+            this._thumbImage = value._rotate90(-1);
+            this._markAsDirty();
         }
+        else {
+            this._thumbImage = value;
+            if (value && !value.isLoaded) {
+                value.onImageLoadedObservable.addOnce(() => {
+                    this._markAsDirty();
+                });
+            }
 
-        this._markAsDirty();
+            this._markAsDirty();
+        }
     }
 
     /**

+ 0 - 0
gui/src/3D/controls/holographicButton.ts


Some files were not shown because too many files changed in this diff