Browse Source

Merge remote-tracking branch 'BabylonJS/master'

MackeyK24 8 years ago
parent
commit
92167c72ab
30 changed files with 3671 additions and 2986 deletions
  1. 1 1
      dist/babylon.d.ts
  2. 558 542
      dist/preview release/babylon.d.ts
  3. 29 29
      dist/preview release/babylon.js
  4. 127 15
      dist/preview release/babylon.max.js
  5. 558 542
      dist/preview release/babylon.module.d.ts
  6. 29 29
      dist/preview release/babylon.worker.js
  7. 873 857
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts
  8. 20 20
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.js
  9. 187 28
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js
  10. 873 857
      dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts
  11. 6 6
      gui/package.json
  12. 11 0
      dist/preview release/loaders/babylon.glTF1FileLoader.d.ts
  13. 20 0
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  14. 60 13
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  15. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  16. 20 0
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  17. 60 13
      dist/preview release/loaders/babylon.glTFFileLoader.js
  18. 3 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  19. 26 4
      loaders/src/glTF/2.0/Extensions/MSFT_lod.ts
  20. 39 10
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  21. 11 0
      loaders/src/glTF/babylon.glTFFileLoader.ts
  22. 0 1
      readme.md
  23. 14 0
      sandbox/index.js
  24. 36 0
      src/Lights/Shadows/babylon.shadowGenerator.ts
  25. 4 0
      src/Loading/babylon.sceneLoader.ts
  26. 2 2
      src/Materials/Textures/babylon.renderTargetTexture.ts
  27. 5 3
      src/Materials/babylon.material.ts
  28. 4 1
      src/Mesh/babylon.geometry.ts
  29. 86 9
      src/Tools/babylon.filesInput.ts
  30. 8 1
      src/babylon.engine.ts

+ 1 - 1
dist/babylon.d.ts

@@ -9169,7 +9169,7 @@ declare module BABYLON {
          * Clones the mesh, used by the class Mesh.
          * Clones the mesh, used by the class Mesh.
          * Just returns `null` for an AbstractMesh.
          * Just returns `null` for an AbstractMesh.
          */
          */
-        clone(name: string, newParent: Node, doNotCloneChildren?: boolean): AbstractMesh;
+        clone(name: string, newParent?: Node, doNotCloneChildren?: boolean): AbstractMesh;
         /**
         /**
          * Disposes all the mesh submeshes.
          * Disposes all the mesh submeshes.
          * Returns the AbstractMesh.
          * Returns the AbstractMesh.

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


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


+ 127 - 15
dist/preview release/babylon.max.js

@@ -10555,9 +10555,13 @@ var BABYLON;
             }
             }
         };
         };
         Engine.prototype._setAnisotropicLevel = function (key, texture) {
         Engine.prototype._setAnisotropicLevel = function (key, texture) {
+            var internalTexture = texture.getInternalTexture();
+            if (!internalTexture) {
+                return;
+            }
             var anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
             var anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
             var value = texture.anisotropicFilteringLevel;
             var value = texture.anisotropicFilteringLevel;
-            if (texture.getInternalTexture().samplingMode === BABYLON.Texture.NEAREST_SAMPLINGMODE) {
+            if (internalTexture.samplingMode === BABYLON.Texture.NEAREST_SAMPLINGMODE) {
                 value = 1;
                 value = 1;
             }
             }
             if (anisotropicFilterExtension && texture._cachedAnisotropicFilteringLevel !== value) {
             if (anisotropicFilterExtension && texture._cachedAnisotropicFilteringLevel !== value) {
@@ -24889,7 +24893,9 @@ var BABYLON;
             }
             }
             return result;
             return result;
         };
         };
-        // Force shader compilation including textures ready check
+        /**
+         * Force shader compilation including textures ready check
+         */
         Material.prototype.forceCompilation = function (mesh, onCompiled, options) {
         Material.prototype.forceCompilation = function (mesh, onCompiled, options) {
             var _this = this;
             var _this = this;
             var subMesh = new BABYLON.BaseSubMesh();
             var subMesh = new BABYLON.BaseSubMesh();
@@ -24902,7 +24908,7 @@ var BABYLON;
                 var alphaTestState = engine.getAlphaTesting();
                 var alphaTestState = engine.getAlphaTesting();
                 var clipPlaneState = scene.clipPlane;
                 var clipPlaneState = scene.clipPlane;
                 engine.setAlphaTesting(options ? options.alphaTest : _this.needAlphaTesting());
                 engine.setAlphaTesting(options ? options.alphaTest : _this.needAlphaTesting());
-                if (options.clipPlane) {
+                if (options && options.clipPlane) {
                     scene.clipPlane = new BABYLON.Plane(0, 0, 0, 1);
                     scene.clipPlane = new BABYLON.Plane(0, 0, 0, 1);
                 }
                 }
                 if (_this.storeEffectOnSubMeshes) {
                 if (_this.storeEffectOnSubMeshes) {
@@ -24926,7 +24932,7 @@ var BABYLON;
                     }
                     }
                 }
                 }
                 engine.setAlphaTesting(alphaTestState);
                 engine.setAlphaTesting(alphaTestState);
-                if (options.clipPlane) {
+                if (options && options.clipPlane) {
                     scene.clipPlane = clipPlaneState;
                     scene.clipPlane = clipPlaneState;
                 }
                 }
             };
             };
@@ -27816,6 +27822,7 @@ var BABYLON;
             //Init vertex buffer cache
             //Init vertex buffer cache
             this._vertexBuffers = {};
             this._vertexBuffers = {};
             this._indices = [];
             this._indices = [];
+            this._updatable = updatable;
             // vertexData
             // vertexData
             if (vertexData) {
             if (vertexData) {
                 this.setAllVerticesData(vertexData, updatable);
                 this.setAllVerticesData(vertexData, updatable);
@@ -28327,6 +28334,7 @@ var BABYLON;
         Geometry.prototype.serialize = function () {
         Geometry.prototype.serialize = function () {
             var serializationObject = {};
             var serializationObject = {};
             serializationObject.id = this.id;
             serializationObject.id = this.id;
+            serializationObject.updatable = this._updatable;
             if (BABYLON.Tags && BABYLON.Tags.HasTags(this)) {
             if (BABYLON.Tags && BABYLON.Tags.HasTags(this)) {
                 serializationObject.tags = BABYLON.Tags.GetTags(this);
                 serializationObject.tags = BABYLON.Tags.GetTags(this);
             }
             }
@@ -28604,7 +28612,7 @@ var BABYLON;
             if (scene.getGeometryByID(parsedVertexData.id)) {
             if (scene.getGeometryByID(parsedVertexData.id)) {
                 return null; // null since geometry could be something else than a box...
                 return null; // null since geometry could be something else than a box...
             }
             }
-            var geometry = new Geometry(parsedVertexData.id, scene);
+            var geometry = new Geometry(parsedVertexData.id, scene, null, parsedVertexData.updatable);
             if (BABYLON.Tags) {
             if (BABYLON.Tags) {
                 BABYLON.Tags.AddTagsTo(geometry, parsedVertexData.tags);
                 BABYLON.Tags.AddTagsTo(geometry, parsedVertexData.tags);
             }
             }
@@ -44830,14 +44838,14 @@ var BABYLON;
             var camera;
             var camera;
             if (this.activeCamera) {
             if (this.activeCamera) {
                 camera = this.activeCamera;
                 camera = this.activeCamera;
-                engine.setViewport(this.activeCamera.viewport);
+                engine.setViewport(this.activeCamera.viewport, this._size, this._size);
                 if (this.activeCamera !== scene.activeCamera) {
                 if (this.activeCamera !== scene.activeCamera) {
                     scene.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(true));
                     scene.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(true));
                 }
                 }
             }
             }
             else {
             else {
                 camera = scene.activeCamera;
                 camera = scene.activeCamera;
-                engine.setViewport(scene.activeCamera.viewport);
+                engine.setViewport(scene.activeCamera.viewport, this._size, this._size);
             }
             }
             // Prepare renderingManager
             // Prepare renderingManager
             this._renderingManager.reset();
             this._renderingManager.reset();
@@ -46472,6 +46480,36 @@ var BABYLON;
             }
             }
         };
         };
         /**
         /**
+         * Force shader compilation including textures ready check
+         */
+        ShadowGenerator.prototype.forceCompilation = function (onCompiled, options) {
+            var _this = this;
+            var scene = this._scene;
+            var engine = scene.getEngine();
+            var subMeshes = new Array();
+            var currentIndex = 0;
+            for (var _i = 0, _a = this.getShadowMap().renderList; _i < _a.length; _i++) {
+                var mesh = _a[_i];
+                subMeshes.push.apply(subMeshes, mesh.subMeshes);
+            }
+            var checkReady = function () {
+                var subMesh = subMeshes[currentIndex];
+                if (_this.isReady(subMesh, options ? options.useInstances : false)) {
+                    currentIndex++;
+                    if (currentIndex >= subMeshes.length) {
+                        if (onCompiled) {
+                            onCompiled(_this);
+                        }
+                        return;
+                    }
+                }
+                setTimeout(checkReady, 16);
+            };
+            if (subMeshes.length > 0) {
+                checkReady();
+            }
+        };
+        /**
          * Boolean : true when the ShadowGenerator is finally computed.
          * Boolean : true when the ShadowGenerator is finally computed.
          */
          */
         ShadowGenerator.prototype.isReady = function (subMesh, useInstances) {
         ShadowGenerator.prototype.isReady = function (subMesh, useInstances) {
@@ -46981,6 +47019,7 @@ var BABYLON;
             var plugin = registeredPlugin.plugin;
             var plugin = registeredPlugin.plugin;
             var useArrayBuffer = registeredPlugin.isBinary;
             var useArrayBuffer = registeredPlugin.isBinary;
             var database;
             var database;
+            SceneLoader.OnPluginActivatedObservable.notifyObservers(registeredPlugin.plugin);
             var dataCallback = function (data) {
             var dataCallback = function (data) {
                 if (scene.isDisposed) {
                 if (scene.isDisposed) {
                     onError("Scene has been disposed");
                     onError("Scene has been disposed");
@@ -47172,6 +47211,7 @@ var BABYLON;
     SceneLoader._ShowLoadingScreen = true;
     SceneLoader._ShowLoadingScreen = true;
     SceneLoader._loggingLevel = SceneLoader.NO_LOGGING;
     SceneLoader._loggingLevel = SceneLoader.NO_LOGGING;
     // Members
     // Members
+    SceneLoader.OnPluginActivatedObservable = new BABYLON.Observable();
     SceneLoader._registeredPlugins = {};
     SceneLoader._registeredPlugins = {};
     BABYLON.SceneLoader = SceneLoader;
     BABYLON.SceneLoader = SceneLoader;
     ;
     ;
@@ -47783,7 +47823,47 @@ var BABYLON;
             eventDrop.preventDefault();
             eventDrop.preventDefault();
             this.loadFiles(eventDrop);
             this.loadFiles(eventDrop);
         };
         };
+        FilesInput.prototype._handleFolderDrop = function (entry, files, callback) {
+            var reader = entry.createReader(), relativePath = entry.fullPath.replace(/^\//, "").replace(/(.+?)\/?$/, "$1/");
+            reader.readEntries(function (fileEntries) {
+                var remaining = fileEntries.length;
+                for (var _i = 0, fileEntries_1 = fileEntries; _i < fileEntries_1.length; _i++) {
+                    var fileEntry = fileEntries_1[_i];
+                    if (fileEntry.isFile) {
+                        fileEntry.file(function (file) {
+                            file.correctName = relativePath + file.name;
+                            files.push(file);
+                            remaining--;
+                            if (remaining === 0) {
+                                callback();
+                            }
+                        });
+                    }
+                    else {
+                        remaining--;
+                        if (remaining === 0) {
+                            callback();
+                        }
+                    }
+                }
+            });
+        };
+        FilesInput.prototype._processFiles = function (files) {
+            for (var i = 0; i < files.length; i++) {
+                var name = files[i].correctName.toLowerCase();
+                var extension = name.split('.').pop();
+                if ((extension === "babylon" || extension === "stl" || extension === "obj" || extension === "gltf" || extension === "glb")
+                    && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
+                    this._sceneFileToLoad = files[i];
+                }
+                else {
+                    FilesInput.FilesToLoad[name] = files[i];
+                }
+            }
+            this.reload();
+        };
         FilesInput.prototype.loadFiles = function (event) {
         FilesInput.prototype.loadFiles = function (event) {
+            var _this = this;
             if (this._startingProcessingFilesCallback)
             if (this._startingProcessingFilesCallback)
                 this._startingProcessingFilesCallback();
                 this._startingProcessingFilesCallback();
             // Handling data transfer via drag'n'drop
             // Handling data transfer via drag'n'drop
@@ -47795,19 +47875,51 @@ var BABYLON;
                 this._filesToLoad = event.target.files;
                 this._filesToLoad = event.target.files;
             }
             }
             if (this._filesToLoad && this._filesToLoad.length > 0) {
             if (this._filesToLoad && this._filesToLoad.length > 0) {
+                var files_1 = [];
+                var folders = [];
                 for (var i = 0; i < this._filesToLoad.length; i++) {
                 for (var i = 0; i < this._filesToLoad.length; i++) {
-                    var name_1 = this._filesToLoad[i].name.toLowerCase();
-                    var extension = name_1.split('.').pop();
-                    var type = this._filesToLoad[i].type;
-                    if ((extension === "babylon" || extension === "stl" || extension === "obj" || extension === "gltf" || extension === "glb")
-                        && name_1.indexOf(".binary.babylon") === -1 && name_1.indexOf(".incremental.babylon") === -1) {
-                        this._sceneFileToLoad = this._filesToLoad[i];
+                    var fileToLoad = this._filesToLoad[i];
+                    var name_1 = fileToLoad.name.toLowerCase();
+                    var type = fileToLoad.type;
+                    var entry = void 0;
+                    fileToLoad.correctName = name_1;
+                    if (event.dataTransfer.items) {
+                        var item = event.dataTransfer.items[i];
+                        if (item.getAsEntry) {
+                            entry = item.getAsEntry();
+                        }
+                        else if (item.webkitGetAsEntry) {
+                            entry = item.webkitGetAsEntry();
+                        }
+                    }
+                    if (!entry) {
+                        files_1.push(fileToLoad);
                     }
                     }
                     else {
                     else {
-                        FilesInput.FilesToLoad[name_1] = this._filesToLoad[i];
+                        if (entry.isDirectory) {
+                            folders.push(entry);
+                        }
+                        else {
+                            files_1.push(fileToLoad);
+                        }
+                    }
+                }
+                if (folders.length === 0) {
+                    this._processFiles(files_1);
+                }
+                else {
+                    var remaining = folders.length;
+                    // Extract folder content
+                    for (var _i = 0, folders_1 = folders; _i < folders_1.length; _i++) {
+                        var folder = folders_1[_i];
+                        this._handleFolderDrop(folder, files_1, function () {
+                            remaining--;
+                            if (remaining === 0) {
+                                _this._processFiles(files_1);
+                            }
+                        });
                     }
                     }
                 }
                 }
-                this.reload();
             }
             }
         };
         };
         FilesInput.prototype.reload = function () {
         FilesInput.prototype.reload = function () {

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


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


File diff suppressed because it is too large
+ 873 - 857
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts


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


+ 187 - 28
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -10555,9 +10555,13 @@ var BABYLON;
             }
             }
         };
         };
         Engine.prototype._setAnisotropicLevel = function (key, texture) {
         Engine.prototype._setAnisotropicLevel = function (key, texture) {
+            var internalTexture = texture.getInternalTexture();
+            if (!internalTexture) {
+                return;
+            }
             var anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
             var anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
             var value = texture.anisotropicFilteringLevel;
             var value = texture.anisotropicFilteringLevel;
-            if (texture.getInternalTexture().samplingMode === BABYLON.Texture.NEAREST_SAMPLINGMODE) {
+            if (internalTexture.samplingMode === BABYLON.Texture.NEAREST_SAMPLINGMODE) {
                 value = 1;
                 value = 1;
             }
             }
             if (anisotropicFilterExtension && texture._cachedAnisotropicFilteringLevel !== value) {
             if (anisotropicFilterExtension && texture._cachedAnisotropicFilteringLevel !== value) {
@@ -24889,7 +24893,9 @@ var BABYLON;
             }
             }
             return result;
             return result;
         };
         };
-        // Force shader compilation including textures ready check
+        /**
+         * Force shader compilation including textures ready check
+         */
         Material.prototype.forceCompilation = function (mesh, onCompiled, options) {
         Material.prototype.forceCompilation = function (mesh, onCompiled, options) {
             var _this = this;
             var _this = this;
             var subMesh = new BABYLON.BaseSubMesh();
             var subMesh = new BABYLON.BaseSubMesh();
@@ -24902,7 +24908,7 @@ var BABYLON;
                 var alphaTestState = engine.getAlphaTesting();
                 var alphaTestState = engine.getAlphaTesting();
                 var clipPlaneState = scene.clipPlane;
                 var clipPlaneState = scene.clipPlane;
                 engine.setAlphaTesting(options ? options.alphaTest : _this.needAlphaTesting());
                 engine.setAlphaTesting(options ? options.alphaTest : _this.needAlphaTesting());
-                if (options.clipPlane) {
+                if (options && options.clipPlane) {
                     scene.clipPlane = new BABYLON.Plane(0, 0, 0, 1);
                     scene.clipPlane = new BABYLON.Plane(0, 0, 0, 1);
                 }
                 }
                 if (_this.storeEffectOnSubMeshes) {
                 if (_this.storeEffectOnSubMeshes) {
@@ -24926,7 +24932,7 @@ var BABYLON;
                     }
                     }
                 }
                 }
                 engine.setAlphaTesting(alphaTestState);
                 engine.setAlphaTesting(alphaTestState);
-                if (options.clipPlane) {
+                if (options && options.clipPlane) {
                     scene.clipPlane = clipPlaneState;
                     scene.clipPlane = clipPlaneState;
                 }
                 }
             };
             };
@@ -27816,6 +27822,7 @@ var BABYLON;
             //Init vertex buffer cache
             //Init vertex buffer cache
             this._vertexBuffers = {};
             this._vertexBuffers = {};
             this._indices = [];
             this._indices = [];
+            this._updatable = updatable;
             // vertexData
             // vertexData
             if (vertexData) {
             if (vertexData) {
                 this.setAllVerticesData(vertexData, updatable);
                 this.setAllVerticesData(vertexData, updatable);
@@ -28327,6 +28334,7 @@ var BABYLON;
         Geometry.prototype.serialize = function () {
         Geometry.prototype.serialize = function () {
             var serializationObject = {};
             var serializationObject = {};
             serializationObject.id = this.id;
             serializationObject.id = this.id;
+            serializationObject.updatable = this._updatable;
             if (BABYLON.Tags && BABYLON.Tags.HasTags(this)) {
             if (BABYLON.Tags && BABYLON.Tags.HasTags(this)) {
                 serializationObject.tags = BABYLON.Tags.GetTags(this);
                 serializationObject.tags = BABYLON.Tags.GetTags(this);
             }
             }
@@ -28604,7 +28612,7 @@ var BABYLON;
             if (scene.getGeometryByID(parsedVertexData.id)) {
             if (scene.getGeometryByID(parsedVertexData.id)) {
                 return null; // null since geometry could be something else than a box...
                 return null; // null since geometry could be something else than a box...
             }
             }
-            var geometry = new Geometry(parsedVertexData.id, scene);
+            var geometry = new Geometry(parsedVertexData.id, scene, null, parsedVertexData.updatable);
             if (BABYLON.Tags) {
             if (BABYLON.Tags) {
                 BABYLON.Tags.AddTagsTo(geometry, parsedVertexData.tags);
                 BABYLON.Tags.AddTagsTo(geometry, parsedVertexData.tags);
             }
             }
@@ -32441,14 +32449,14 @@ var BABYLON;
             var camera;
             var camera;
             if (this.activeCamera) {
             if (this.activeCamera) {
                 camera = this.activeCamera;
                 camera = this.activeCamera;
-                engine.setViewport(this.activeCamera.viewport);
+                engine.setViewport(this.activeCamera.viewport, this._size, this._size);
                 if (this.activeCamera !== scene.activeCamera) {
                 if (this.activeCamera !== scene.activeCamera) {
                     scene.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(true));
                     scene.setTransformMatrix(this.activeCamera.getViewMatrix(), this.activeCamera.getProjectionMatrix(true));
                 }
                 }
             }
             }
             else {
             else {
                 camera = scene.activeCamera;
                 camera = scene.activeCamera;
-                engine.setViewport(scene.activeCamera.viewport);
+                engine.setViewport(scene.activeCamera.viewport, this._size, this._size);
             }
             }
             // Prepare renderingManager
             // Prepare renderingManager
             this._renderingManager.reset();
             this._renderingManager.reset();
@@ -34907,6 +34915,36 @@ var BABYLON;
             }
             }
         };
         };
         /**
         /**
+         * Force shader compilation including textures ready check
+         */
+        ShadowGenerator.prototype.forceCompilation = function (onCompiled, options) {
+            var _this = this;
+            var scene = this._scene;
+            var engine = scene.getEngine();
+            var subMeshes = new Array();
+            var currentIndex = 0;
+            for (var _i = 0, _a = this.getShadowMap().renderList; _i < _a.length; _i++) {
+                var mesh = _a[_i];
+                subMeshes.push.apply(subMeshes, mesh.subMeshes);
+            }
+            var checkReady = function () {
+                var subMesh = subMeshes[currentIndex];
+                if (_this._scene && _this._scene.getEngine() && _this.isReady(subMesh, options ? options.useInstances : false)) {
+                    currentIndex++;
+                    if (currentIndex >= subMeshes.length) {
+                        if (onCompiled) {
+                            onCompiled(_this);
+                        }
+                        return;
+                    }
+                }
+                setTimeout(checkReady, 16);
+            };
+            if (subMeshes.length > 0) {
+                checkReady();
+            }
+        };
+        /**
          * Boolean : true when the ShadowGenerator is finally computed.
          * Boolean : true when the ShadowGenerator is finally computed.
          */
          */
         ShadowGenerator.prototype.isReady = function (subMesh, useInstances) {
         ShadowGenerator.prototype.isReady = function (subMesh, useInstances) {
@@ -48389,6 +48427,7 @@ var BABYLON;
             var plugin = registeredPlugin.plugin;
             var plugin = registeredPlugin.plugin;
             var useArrayBuffer = registeredPlugin.isBinary;
             var useArrayBuffer = registeredPlugin.isBinary;
             var database;
             var database;
+            SceneLoader.OnPluginActivatedObservable.notifyObservers(registeredPlugin.plugin);
             var dataCallback = function (data) {
             var dataCallback = function (data) {
                 if (scene.isDisposed) {
                 if (scene.isDisposed) {
                     onError("Scene has been disposed");
                     onError("Scene has been disposed");
@@ -48580,6 +48619,7 @@ var BABYLON;
     SceneLoader._ShowLoadingScreen = true;
     SceneLoader._ShowLoadingScreen = true;
     SceneLoader._loggingLevel = SceneLoader.NO_LOGGING;
     SceneLoader._loggingLevel = SceneLoader.NO_LOGGING;
     // Members
     // Members
+    SceneLoader.OnPluginActivatedObservable = new BABYLON.Observable();
     SceneLoader._registeredPlugins = {};
     SceneLoader._registeredPlugins = {};
     BABYLON.SceneLoader = SceneLoader;
     BABYLON.SceneLoader = SceneLoader;
     ;
     ;
@@ -49191,7 +49231,47 @@ var BABYLON;
             eventDrop.preventDefault();
             eventDrop.preventDefault();
             this.loadFiles(eventDrop);
             this.loadFiles(eventDrop);
         };
         };
+        FilesInput.prototype._handleFolderDrop = function (entry, files, callback) {
+            var reader = entry.createReader(), relativePath = entry.fullPath.replace(/^\//, "").replace(/(.+?)\/?$/, "$1/");
+            reader.readEntries(function (fileEntries) {
+                var remaining = fileEntries.length;
+                for (var _i = 0, fileEntries_1 = fileEntries; _i < fileEntries_1.length; _i++) {
+                    var fileEntry = fileEntries_1[_i];
+                    if (fileEntry.isFile) {
+                        fileEntry.file(function (file) {
+                            file.correctName = relativePath + file.name;
+                            files.push(file);
+                            remaining--;
+                            if (remaining === 0) {
+                                callback();
+                            }
+                        });
+                    }
+                    else {
+                        remaining--;
+                        if (remaining === 0) {
+                            callback();
+                        }
+                    }
+                }
+            });
+        };
+        FilesInput.prototype._processFiles = function (files) {
+            for (var i = 0; i < files.length; i++) {
+                var name = files[i].correctName.toLowerCase();
+                var extension = name.split('.').pop();
+                if ((extension === "babylon" || extension === "stl" || extension === "obj" || extension === "gltf" || extension === "glb")
+                    && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
+                    this._sceneFileToLoad = files[i];
+                }
+                else {
+                    FilesInput.FilesToLoad[name] = files[i];
+                }
+            }
+            this.reload();
+        };
         FilesInput.prototype.loadFiles = function (event) {
         FilesInput.prototype.loadFiles = function (event) {
+            var _this = this;
             if (this._startingProcessingFilesCallback)
             if (this._startingProcessingFilesCallback)
                 this._startingProcessingFilesCallback();
                 this._startingProcessingFilesCallback();
             // Handling data transfer via drag'n'drop
             // Handling data transfer via drag'n'drop
@@ -49203,19 +49283,51 @@ var BABYLON;
                 this._filesToLoad = event.target.files;
                 this._filesToLoad = event.target.files;
             }
             }
             if (this._filesToLoad && this._filesToLoad.length > 0) {
             if (this._filesToLoad && this._filesToLoad.length > 0) {
+                var files_1 = [];
+                var folders = [];
                 for (var i = 0; i < this._filesToLoad.length; i++) {
                 for (var i = 0; i < this._filesToLoad.length; i++) {
-                    var name_1 = this._filesToLoad[i].name.toLowerCase();
-                    var extension = name_1.split('.').pop();
-                    var type = this._filesToLoad[i].type;
-                    if ((extension === "babylon" || extension === "stl" || extension === "obj" || extension === "gltf" || extension === "glb")
-                        && name_1.indexOf(".binary.babylon") === -1 && name_1.indexOf(".incremental.babylon") === -1) {
-                        this._sceneFileToLoad = this._filesToLoad[i];
+                    var fileToLoad = this._filesToLoad[i];
+                    var name_1 = fileToLoad.name.toLowerCase();
+                    var type = fileToLoad.type;
+                    var entry = void 0;
+                    fileToLoad.correctName = name_1;
+                    if (event.dataTransfer && event.dataTransfer.items) {
+                        var item = event.dataTransfer.items[i];
+                        if (item.getAsEntry) {
+                            entry = item.getAsEntry();
+                        }
+                        else if (item.webkitGetAsEntry) {
+                            entry = item.webkitGetAsEntry();
+                        }
+                    }
+                    if (!entry) {
+                        files_1.push(fileToLoad);
                     }
                     }
                     else {
                     else {
-                        FilesInput.FilesToLoad[name_1] = this._filesToLoad[i];
+                        if (entry.isDirectory) {
+                            folders.push(entry);
+                        }
+                        else {
+                            files_1.push(fileToLoad);
+                        }
+                    }
+                }
+                if (folders.length === 0) {
+                    this._processFiles(files_1);
+                }
+                else {
+                    var remaining = folders.length;
+                    // Extract folder content
+                    for (var _i = 0, folders_1 = folders; _i < folders_1.length; _i++) {
+                        var folder = folders_1[_i];
+                        this._handleFolderDrop(folder, files_1, function () {
+                            remaining--;
+                            if (remaining === 0) {
+                                _this._processFiles(files_1);
+                            }
+                        });
                     }
                     }
                 }
                 }
-                this.reload();
             }
             }
         };
         };
         FilesInput.prototype.reload = function () {
         FilesInput.prototype.reload = function () {
@@ -51911,6 +52023,7 @@ var BABYLON;
                 this._renderReady = false;
                 this._renderReady = false;
                 this._disposed = false;
                 this._disposed = false;
                 this._objectURLs = new Array();
                 this._objectURLs = new Array();
+                this._blockPendingTracking = false;
                 // Observable with boolean indicating success or error.
                 // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 // Count of pending work that needs to complete before the asset is rendered.
@@ -52020,11 +52133,15 @@ var BABYLON;
                 this._renderReadyObservable.notifyObservers(this);
                 this._renderReadyObservable.notifyObservers(this);
             };
             };
             GLTFLoader.prototype._onLoaderComplete = function () {
             GLTFLoader.prototype._onLoaderComplete = function () {
-                this.dispose();
                 if (this._parent.onComplete) {
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                     this._parent.onComplete();
                 }
                 }
             };
             };
+            GLTFLoader.prototype._onLoaderFirstLODComplete = function () {
+                if (this._parent.onFirstLODComplete) {
+                    this._parent.onFirstLODComplete();
+                }
+            };
             GLTFLoader.prototype._loadData = function (data) {
             GLTFLoader.prototype._loadData = function (data) {
                 this._gltf = data.json;
                 this._gltf = data.json;
                 var binaryBuffer;
                 var binaryBuffer;
@@ -52234,13 +52351,14 @@ var BABYLON;
                                         if (isNew && _this._parent.onMaterialLoaded) {
                                         if (isNew && _this._parent.onMaterialLoaded) {
                                             _this._parent.onMaterialLoaded(babylonMaterial);
                                             _this._parent.onMaterialLoaded(babylonMaterial);
                                         }
                                         }
-                                        // Note: Removing force compilation from loader as this will be delegated to users as they
-                                        // may want to add more options to the material before compiling it
-                                        //this.addPendingData(material);
-                                        //babylonMaterial.forceCompilation(babylonMesh, babylonMaterial => {
-                                        babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                        //    this.removePendingData(material);
-                                        //});
+                                        if (_this._parent.onBeforeMaterialReadyAsync) {
+                                            _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
+                                                babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                            });
+                                        }
+                                        else {
+                                            babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                        }
                                     });
                                     });
                                 }
                                 }
                             }
                             }
@@ -52653,6 +52771,13 @@ var BABYLON;
                         return 0;
                         return 0;
                 }
                 }
             };
             };
+            Object.defineProperty(GLTFLoader.prototype, "blockPendingTracking", {
+                set: function (value) {
+                    this._blockPendingTracking = value;
+                },
+                enumerable: true,
+                configurable: true
+            });
             GLTFLoader.prototype.addPendingData = function (data) {
             GLTFLoader.prototype.addPendingData = function (data) {
                 if (!this._renderReady) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
                     this._renderPendingCount++;
@@ -52668,12 +52793,30 @@ var BABYLON;
                 }
                 }
                 this.removeLoaderPendingData(data);
                 this.removeLoaderPendingData(data);
             };
             };
+            GLTFLoader.prototype.addLoaderNonBlockingPendingData = function (data) {
+                if (!this._nonBlockingData) {
+                    this._nonBlockingData = new Array();
+                }
+                this._nonBlockingData.push(data);
+            };
             GLTFLoader.prototype.addLoaderPendingData = function (data) {
             GLTFLoader.prototype.addLoaderPendingData = function (data) {
+                if (this._blockPendingTracking) {
+                    this.addLoaderNonBlockingPendingData(data);
+                    return;
+                }
                 this._loaderPendingCount++;
                 this._loaderPendingCount++;
             };
             };
             GLTFLoader.prototype.removeLoaderPendingData = function (data) {
             GLTFLoader.prototype.removeLoaderPendingData = function (data) {
-                if (--this._loaderPendingCount === 0) {
+                var indexInPending = this._nonBlockingData ? this._nonBlockingData.indexOf(data) : -1;
+                if (indexInPending !== -1) {
+                    this._nonBlockingData.splice(indexInPending, 1);
+                }
+                else if (--this._loaderPendingCount === 0) {
+                    this._onLoaderFirstLODComplete();
+                }
+                if ((!this._nonBlockingData || this._nonBlockingData.length === 0) && this._loaderPendingCount === 0) {
                     this._onLoaderComplete();
                     this._onLoaderComplete();
+                    this.dispose();
                 }
                 }
             };
             };
             GLTFLoader.prototype._getDefaultMaterial = function () {
             GLTFLoader.prototype._getDefaultMaterial = function () {
@@ -53031,33 +53174,49 @@ var BABYLON;
                     // Clear out the extension so that it won't get loaded again.
                     // Clear out the extension so that it won't get loaded again.
                     material.extensions[this.name] = undefined;
                     material.extensions[this.name] = undefined;
                     // Tell the loader not to clear its state until the highest LOD is loaded.
                     // Tell the loader not to clear its state until the highest LOD is loaded.
+                    var materialLODs = [material.index].concat(properties.ids);
                     loader.addLoaderPendingData(material);
                     loader.addLoaderPendingData(material);
+                    for (var index = 0; index < materialLODs.length; index++) {
+                        loader.addLoaderNonBlockingPendingData(index);
+                    }
                     // Start with the lowest quality LOD.
                     // Start with the lowest quality LOD.
-                    var materialLODs = [material.index].concat(properties.ids);
                     this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
                     this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
                     return true;
                     return true;
                 };
                 };
                 MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
                 MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
                     var _this = this;
                     var _this = this;
                     var materialLOD = loader.gltf.materials[materialLODs[lod]];
                     var materialLOD = loader.gltf.materials[materialLODs[lod]];
+                    if (lod !== materialLODs.length - 1) {
+                        loader.blockPendingTracking = true;
+                    }
                     loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
                     loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
                         assign(babylonMaterial, isNew);
                         assign(babylonMaterial, isNew);
-                        // Loading is complete if this is the highest quality LOD.
-                        if (lod === 0) {
+                        loader.removeLoaderPendingData(lod);
+                        // Loading is considered complete if this is the lowest quality LOD.
+                        if (lod === materialLODs.length - 1) {
                             loader.removeLoaderPendingData(material);
                             loader.removeLoaderPendingData(material);
+                        }
+                        if (lod === 0) {
+                            loader.blockPendingTracking = false;
                             return;
                             return;
                         }
                         }
                         // Load the next LOD when the loader is ready to render and
                         // Load the next LOD when the loader is ready to render and
                         // all active material textures of the current LOD are loaded.
                         // all active material textures of the current LOD are loaded.
                         loader.executeWhenRenderReady(function () {
                         loader.executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
-                                _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                setTimeout(function () {
+                                    _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                }, MSFTLOD.MinimalLODDelay);
                             });
                             });
                         });
                         });
                     });
                     });
                 };
                 };
                 return MSFTLOD;
                 return MSFTLOD;
             }(GLTF2.GLTFLoaderExtension));
             }(GLTF2.GLTFLoaderExtension));
+            /**
+             * Specify the minimal delay between LODs in ms (default = 250)
+             */
+            MSFTLOD.MinimalLODDelay = 250;
             Extensions.MSFTLOD = MSFTLOD;
             Extensions.MSFTLOD = MSFTLOD;
             GLTF2.GLTFLoader.RegisterExtension(new MSFTLOD());
             GLTF2.GLTFLoader.RegisterExtension(new MSFTLOD());
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));

File diff suppressed because it is too large
+ 873 - 857
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts


+ 6 - 6
gui/package.json

@@ -4,20 +4,20 @@
   },
   },
   "name": "babylonjs-gui",
   "name": "babylonjs-gui",
   "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
   "description": "The Babylon.js GUI library is an extension you can use to generate interactive user interface. It is build on top of the DynamicTexture.",
-  "version": "3.1.0-alpha1.1",
+  "version": "3.1.0-alpha1.2",
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",
     "url": "https://github.com/BabylonJS/Babylon.js.git"
     "url": "https://github.com/BabylonJS/Babylon.js.git"
   },
   },
-  "main": "../dist/preview release/gui/babylon.gui.js",
+  "main": "babylon.gui.js",
   "files": [
   "files": [
-    "../dist/preview release/gui/babylon.gui.js",
-    "../dist/preview release/gui/babylon.gui.min.js",
-    "../dist/preview release/gui/babylon.gui.d.ts",
+    "babylon.gui.js",
+    "babylon.gui.min.js",
+    "babylon.gui.d.ts",
 
 
     "package.json"
     "package.json"
   ],
   ],
-  "typings": "../dist/preview release/gui/babylon.gui.d.ts",
+  "typings": "babylon.gui.d.ts",
   "keywords": [
   "keywords": [
     "3D",
     "3D",
     "javascript",
     "javascript",

+ 11 - 0
dist/preview release/loaders/babylon.glTF1FileLoader.d.ts

@@ -21,7 +21,18 @@ declare module BABYLON {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         onTextureLoaded: (texture: BaseTexture) => void;
         onTextureLoaded: (texture: BaseTexture) => void;
         onMaterialLoaded: (material: Material) => void;
         onMaterialLoaded: (material: Material) => void;
+        /**
+         * Let the user decides if he needs to process the material (like precompilation) before affecting it to meshes
+         */
+        onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
+        /**
+         * Raised when all LODs are complete (or if there is no LOD and model is complete)
+         */
         onComplete: () => void;
         onComplete: () => void;
+        /**
+         * Raised when first LOD complete (or if there is no LOD and model is complete)
+         */
+        onFirstLODComplete: () => void;
         name: string;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         extensions: ISceneLoaderPluginExtensions;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;

+ 20 - 0
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -21,7 +21,18 @@ declare module BABYLON {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         onTextureLoaded: (texture: BaseTexture) => void;
         onTextureLoaded: (texture: BaseTexture) => void;
         onMaterialLoaded: (material: Material) => void;
         onMaterialLoaded: (material: Material) => void;
+        /**
+         * Let the user decides if he needs to process the material (like precompilation) before affecting it to meshes
+         */
+        onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
+        /**
+         * Raised when all LODs are complete (or if there is no LOD and model is complete)
+         */
         onComplete: () => void;
         onComplete: () => void;
+        /**
+         * Raised when first LOD complete (or if there is no LOD and model is complete)
+         */
+        onFirstLODComplete: () => void;
         name: string;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         extensions: ISceneLoaderPluginExtensions;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -289,6 +300,8 @@ declare module BABYLON.GLTF2 {
         private _renderReady;
         private _renderReady;
         private _disposed;
         private _disposed;
         private _objectURLs;
         private _objectURLs;
+        private _blockPendingTracking;
+        private _nonBlockingData;
         private _renderReadyObservable;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _renderPendingCount;
         private _loaderPendingCount;
         private _loaderPendingCount;
@@ -308,6 +321,7 @@ declare module BABYLON.GLTF2 {
         private _onProgress(event);
         private _onProgress(event);
         private _onRenderReady();
         private _onRenderReady();
         private _onLoaderComplete();
         private _onLoaderComplete();
+        private _onLoaderFirstLODComplete();
         private _loadData(data);
         private _loadData(data);
         private _addRightHandToLeftHandRootTransform();
         private _addRightHandToLeftHandRootTransform();
         private _getMeshes();
         private _getMeshes();
@@ -333,8 +347,10 @@ declare module BABYLON.GLTF2 {
         private _loadBufferViewAsync(bufferView, byteOffset, byteLength, componentType, onSuccess);
         private _loadBufferViewAsync(bufferView, byteOffset, byteLength, componentType, onSuccess);
         private _loadAccessorAsync(accessor, onSuccess);
         private _loadAccessorAsync(accessor, onSuccess);
         private _getByteStrideFromType(accessor);
         private _getByteStrideFromType(accessor);
+        blockPendingTracking: boolean;
         addPendingData(data: any): void;
         addPendingData(data: any): void;
         removePendingData(data: any): void;
         removePendingData(data: any): void;
+        addLoaderNonBlockingPendingData(data: any): void;
         addLoaderPendingData(data: any): void;
         addLoaderPendingData(data: any): void;
         removeLoaderPendingData(data: any): void;
         removeLoaderPendingData(data: any): void;
         private _getDefaultMaterial();
         private _getDefaultMaterial();
@@ -389,6 +405,10 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class MSFTLOD extends GLTFLoaderExtension {
     class MSFTLOD extends GLTFLoaderExtension {
+        /**
+         * Specify the minimal delay between LODs in ms (default = 250)
+         */
+        static MinimalLODDelay: number;
         readonly name: string;
         readonly name: string;
         protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private loadMaterialLOD(loader, material, materialLODs, lod, assign);
         private loadMaterialLOD(loader, material, materialLODs, lod, assign);

+ 60 - 13
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -319,6 +319,7 @@ var BABYLON;
                 this._renderReady = false;
                 this._renderReady = false;
                 this._disposed = false;
                 this._disposed = false;
                 this._objectURLs = new Array();
                 this._objectURLs = new Array();
+                this._blockPendingTracking = false;
                 // Observable with boolean indicating success or error.
                 // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 // Count of pending work that needs to complete before the asset is rendered.
@@ -428,11 +429,15 @@ var BABYLON;
                 this._renderReadyObservable.notifyObservers(this);
                 this._renderReadyObservable.notifyObservers(this);
             };
             };
             GLTFLoader.prototype._onLoaderComplete = function () {
             GLTFLoader.prototype._onLoaderComplete = function () {
-                this.dispose();
                 if (this._parent.onComplete) {
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                     this._parent.onComplete();
                 }
                 }
             };
             };
+            GLTFLoader.prototype._onLoaderFirstLODComplete = function () {
+                if (this._parent.onFirstLODComplete) {
+                    this._parent.onFirstLODComplete();
+                }
+            };
             GLTFLoader.prototype._loadData = function (data) {
             GLTFLoader.prototype._loadData = function (data) {
                 this._gltf = data.json;
                 this._gltf = data.json;
                 var binaryBuffer;
                 var binaryBuffer;
@@ -642,13 +647,14 @@ var BABYLON;
                                         if (isNew && _this._parent.onMaterialLoaded) {
                                         if (isNew && _this._parent.onMaterialLoaded) {
                                             _this._parent.onMaterialLoaded(babylonMaterial);
                                             _this._parent.onMaterialLoaded(babylonMaterial);
                                         }
                                         }
-                                        // Note: Removing force compilation from loader as this will be delegated to users as they
-                                        // may want to add more options to the material before compiling it
-                                        //this.addPendingData(material);
-                                        //babylonMaterial.forceCompilation(babylonMesh, babylonMaterial => {
-                                        babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                        //    this.removePendingData(material);
-                                        //});
+                                        if (_this._parent.onBeforeMaterialReadyAsync) {
+                                            _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
+                                                babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                            });
+                                        }
+                                        else {
+                                            babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                        }
                                     });
                                     });
                                 }
                                 }
                             }
                             }
@@ -1061,6 +1067,13 @@ var BABYLON;
                         return 0;
                         return 0;
                 }
                 }
             };
             };
+            Object.defineProperty(GLTFLoader.prototype, "blockPendingTracking", {
+                set: function (value) {
+                    this._blockPendingTracking = value;
+                },
+                enumerable: true,
+                configurable: true
+            });
             GLTFLoader.prototype.addPendingData = function (data) {
             GLTFLoader.prototype.addPendingData = function (data) {
                 if (!this._renderReady) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
                     this._renderPendingCount++;
@@ -1076,12 +1089,30 @@ var BABYLON;
                 }
                 }
                 this.removeLoaderPendingData(data);
                 this.removeLoaderPendingData(data);
             };
             };
+            GLTFLoader.prototype.addLoaderNonBlockingPendingData = function (data) {
+                if (!this._nonBlockingData) {
+                    this._nonBlockingData = new Array();
+                }
+                this._nonBlockingData.push(data);
+            };
             GLTFLoader.prototype.addLoaderPendingData = function (data) {
             GLTFLoader.prototype.addLoaderPendingData = function (data) {
+                if (this._blockPendingTracking) {
+                    this.addLoaderNonBlockingPendingData(data);
+                    return;
+                }
                 this._loaderPendingCount++;
                 this._loaderPendingCount++;
             };
             };
             GLTFLoader.prototype.removeLoaderPendingData = function (data) {
             GLTFLoader.prototype.removeLoaderPendingData = function (data) {
-                if (--this._loaderPendingCount === 0) {
+                var indexInPending = this._nonBlockingData ? this._nonBlockingData.indexOf(data) : -1;
+                if (indexInPending !== -1) {
+                    this._nonBlockingData.splice(indexInPending, 1);
+                }
+                else if (--this._loaderPendingCount === 0) {
+                    this._onLoaderFirstLODComplete();
+                }
+                if ((!this._nonBlockingData || this._nonBlockingData.length === 0) && this._loaderPendingCount === 0) {
                     this._onLoaderComplete();
                     this._onLoaderComplete();
+                    this.dispose();
                 }
                 }
             };
             };
             GLTFLoader.prototype._getDefaultMaterial = function () {
             GLTFLoader.prototype._getDefaultMaterial = function () {
@@ -1448,33 +1479,49 @@ var BABYLON;
                     // Clear out the extension so that it won't get loaded again.
                     // Clear out the extension so that it won't get loaded again.
                     material.extensions[this.name] = undefined;
                     material.extensions[this.name] = undefined;
                     // Tell the loader not to clear its state until the highest LOD is loaded.
                     // Tell the loader not to clear its state until the highest LOD is loaded.
+                    var materialLODs = [material.index].concat(properties.ids);
                     loader.addLoaderPendingData(material);
                     loader.addLoaderPendingData(material);
+                    for (var index = 0; index < materialLODs.length; index++) {
+                        loader.addLoaderNonBlockingPendingData(index);
+                    }
                     // Start with the lowest quality LOD.
                     // Start with the lowest quality LOD.
-                    var materialLODs = [material.index].concat(properties.ids);
                     this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
                     this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
                     return true;
                     return true;
                 };
                 };
                 MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
                 MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
                     var _this = this;
                     var _this = this;
                     var materialLOD = loader.gltf.materials[materialLODs[lod]];
                     var materialLOD = loader.gltf.materials[materialLODs[lod]];
+                    if (lod !== materialLODs.length - 1) {
+                        loader.blockPendingTracking = true;
+                    }
                     loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
                     loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
                         assign(babylonMaterial, isNew);
                         assign(babylonMaterial, isNew);
-                        // Loading is complete if this is the highest quality LOD.
-                        if (lod === 0) {
+                        loader.removeLoaderPendingData(lod);
+                        // Loading is considered complete if this is the lowest quality LOD.
+                        if (lod === materialLODs.length - 1) {
                             loader.removeLoaderPendingData(material);
                             loader.removeLoaderPendingData(material);
+                        }
+                        if (lod === 0) {
+                            loader.blockPendingTracking = false;
                             return;
                             return;
                         }
                         }
                         // Load the next LOD when the loader is ready to render and
                         // Load the next LOD when the loader is ready to render and
                         // all active material textures of the current LOD are loaded.
                         // all active material textures of the current LOD are loaded.
                         loader.executeWhenRenderReady(function () {
                         loader.executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
-                                _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                setTimeout(function () {
+                                    _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                }, MSFTLOD.MinimalLODDelay);
                             });
                             });
                         });
                         });
                     });
                     });
                 };
                 };
                 return MSFTLOD;
                 return MSFTLOD;
             }(GLTF2.GLTFLoaderExtension));
             }(GLTF2.GLTFLoaderExtension));
+            /**
+             * Specify the minimal delay between LODs in ms (default = 250)
+             */
+            MSFTLOD.MinimalLODDelay = 250;
             Extensions.MSFTLOD = MSFTLOD;
             Extensions.MSFTLOD = MSFTLOD;
             GLTF2.GLTFLoader.RegisterExtension(new MSFTLOD());
             GLTF2.GLTFLoader.RegisterExtension(new MSFTLOD());
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));

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


+ 20 - 0
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -21,7 +21,18 @@ declare module BABYLON {
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         coordinateSystemMode: GLTFLoaderCoordinateSystemMode;
         onTextureLoaded: (texture: BaseTexture) => void;
         onTextureLoaded: (texture: BaseTexture) => void;
         onMaterialLoaded: (material: Material) => void;
         onMaterialLoaded: (material: Material) => void;
+        /**
+         * Let the user decides if he needs to process the material (like precompilation) before affecting it to meshes
+         */
+        onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
+        /**
+         * Raised when all LODs are complete (or if there is no LOD and model is complete)
+         */
         onComplete: () => void;
         onComplete: () => void;
+        /**
+         * Raised when first LOD complete (or if there is no LOD and model is complete)
+         */
+        onFirstLODComplete: () => void;
         name: string;
         name: string;
         extensions: ISceneLoaderPluginExtensions;
         extensions: ISceneLoaderPluginExtensions;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
@@ -784,6 +795,8 @@ declare module BABYLON.GLTF2 {
         private _renderReady;
         private _renderReady;
         private _disposed;
         private _disposed;
         private _objectURLs;
         private _objectURLs;
+        private _blockPendingTracking;
+        private _nonBlockingData;
         private _renderReadyObservable;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _renderPendingCount;
         private _loaderPendingCount;
         private _loaderPendingCount;
@@ -803,6 +816,7 @@ declare module BABYLON.GLTF2 {
         private _onProgress(event);
         private _onProgress(event);
         private _onRenderReady();
         private _onRenderReady();
         private _onLoaderComplete();
         private _onLoaderComplete();
+        private _onLoaderFirstLODComplete();
         private _loadData(data);
         private _loadData(data);
         private _addRightHandToLeftHandRootTransform();
         private _addRightHandToLeftHandRootTransform();
         private _getMeshes();
         private _getMeshes();
@@ -828,8 +842,10 @@ declare module BABYLON.GLTF2 {
         private _loadBufferViewAsync(bufferView, byteOffset, byteLength, componentType, onSuccess);
         private _loadBufferViewAsync(bufferView, byteOffset, byteLength, componentType, onSuccess);
         private _loadAccessorAsync(accessor, onSuccess);
         private _loadAccessorAsync(accessor, onSuccess);
         private _getByteStrideFromType(accessor);
         private _getByteStrideFromType(accessor);
+        blockPendingTracking: boolean;
         addPendingData(data: any): void;
         addPendingData(data: any): void;
         removePendingData(data: any): void;
         removePendingData(data: any): void;
+        addLoaderNonBlockingPendingData(data: any): void;
         addLoaderPendingData(data: any): void;
         addLoaderPendingData(data: any): void;
         removeLoaderPendingData(data: any): void;
         removeLoaderPendingData(data: any): void;
         private _getDefaultMaterial();
         private _getDefaultMaterial();
@@ -884,6 +900,10 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2.Extensions {
 declare module BABYLON.GLTF2.Extensions {
     class MSFTLOD extends GLTFLoaderExtension {
     class MSFTLOD extends GLTFLoaderExtension {
+        /**
+         * Specify the minimal delay between LODs in ms (default = 250)
+         */
+        static MinimalLODDelay: number;
         readonly name: string;
         readonly name: string;
         protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         protected loadMaterial(loader: GLTFLoader, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean;
         private loadMaterialLOD(loader, material, materialLODs, lod, assign);
         private loadMaterialLOD(loader, material, materialLODs, lod, assign);

+ 60 - 13
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2477,6 +2477,7 @@ var BABYLON;
                 this._renderReady = false;
                 this._renderReady = false;
                 this._disposed = false;
                 this._disposed = false;
                 this._objectURLs = new Array();
                 this._objectURLs = new Array();
+                this._blockPendingTracking = false;
                 // Observable with boolean indicating success or error.
                 // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
                 this._renderReadyObservable = new BABYLON.Observable();
                 // Count of pending work that needs to complete before the asset is rendered.
                 // Count of pending work that needs to complete before the asset is rendered.
@@ -2586,11 +2587,15 @@ var BABYLON;
                 this._renderReadyObservable.notifyObservers(this);
                 this._renderReadyObservable.notifyObservers(this);
             };
             };
             GLTFLoader.prototype._onLoaderComplete = function () {
             GLTFLoader.prototype._onLoaderComplete = function () {
-                this.dispose();
                 if (this._parent.onComplete) {
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                     this._parent.onComplete();
                 }
                 }
             };
             };
+            GLTFLoader.prototype._onLoaderFirstLODComplete = function () {
+                if (this._parent.onFirstLODComplete) {
+                    this._parent.onFirstLODComplete();
+                }
+            };
             GLTFLoader.prototype._loadData = function (data) {
             GLTFLoader.prototype._loadData = function (data) {
                 this._gltf = data.json;
                 this._gltf = data.json;
                 var binaryBuffer;
                 var binaryBuffer;
@@ -2800,13 +2805,14 @@ var BABYLON;
                                         if (isNew && _this._parent.onMaterialLoaded) {
                                         if (isNew && _this._parent.onMaterialLoaded) {
                                             _this._parent.onMaterialLoaded(babylonMaterial);
                                             _this._parent.onMaterialLoaded(babylonMaterial);
                                         }
                                         }
-                                        // Note: Removing force compilation from loader as this will be delegated to users as they
-                                        // may want to add more options to the material before compiling it
-                                        //this.addPendingData(material);
-                                        //babylonMaterial.forceCompilation(babylonMesh, babylonMaterial => {
-                                        babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                        //    this.removePendingData(material);
-                                        //});
+                                        if (_this._parent.onBeforeMaterialReadyAsync) {
+                                            _this._parent.onBeforeMaterialReadyAsync(babylonMaterial, babylonMesh, babylonMultiMaterial.subMaterials[i] != null, function () {
+                                                babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                            });
+                                        }
+                                        else {
+                                            babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                        }
                                     });
                                     });
                                 }
                                 }
                             }
                             }
@@ -3219,6 +3225,13 @@ var BABYLON;
                         return 0;
                         return 0;
                 }
                 }
             };
             };
+            Object.defineProperty(GLTFLoader.prototype, "blockPendingTracking", {
+                set: function (value) {
+                    this._blockPendingTracking = value;
+                },
+                enumerable: true,
+                configurable: true
+            });
             GLTFLoader.prototype.addPendingData = function (data) {
             GLTFLoader.prototype.addPendingData = function (data) {
                 if (!this._renderReady) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
                     this._renderPendingCount++;
@@ -3234,12 +3247,30 @@ var BABYLON;
                 }
                 }
                 this.removeLoaderPendingData(data);
                 this.removeLoaderPendingData(data);
             };
             };
+            GLTFLoader.prototype.addLoaderNonBlockingPendingData = function (data) {
+                if (!this._nonBlockingData) {
+                    this._nonBlockingData = new Array();
+                }
+                this._nonBlockingData.push(data);
+            };
             GLTFLoader.prototype.addLoaderPendingData = function (data) {
             GLTFLoader.prototype.addLoaderPendingData = function (data) {
+                if (this._blockPendingTracking) {
+                    this.addLoaderNonBlockingPendingData(data);
+                    return;
+                }
                 this._loaderPendingCount++;
                 this._loaderPendingCount++;
             };
             };
             GLTFLoader.prototype.removeLoaderPendingData = function (data) {
             GLTFLoader.prototype.removeLoaderPendingData = function (data) {
-                if (--this._loaderPendingCount === 0) {
+                var indexInPending = this._nonBlockingData ? this._nonBlockingData.indexOf(data) : -1;
+                if (indexInPending !== -1) {
+                    this._nonBlockingData.splice(indexInPending, 1);
+                }
+                else if (--this._loaderPendingCount === 0) {
+                    this._onLoaderFirstLODComplete();
+                }
+                if ((!this._nonBlockingData || this._nonBlockingData.length === 0) && this._loaderPendingCount === 0) {
                     this._onLoaderComplete();
                     this._onLoaderComplete();
+                    this.dispose();
                 }
                 }
             };
             };
             GLTFLoader.prototype._getDefaultMaterial = function () {
             GLTFLoader.prototype._getDefaultMaterial = function () {
@@ -3606,33 +3637,49 @@ var BABYLON;
                     // Clear out the extension so that it won't get loaded again.
                     // Clear out the extension so that it won't get loaded again.
                     material.extensions[this.name] = undefined;
                     material.extensions[this.name] = undefined;
                     // Tell the loader not to clear its state until the highest LOD is loaded.
                     // Tell the loader not to clear its state until the highest LOD is loaded.
+                    var materialLODs = [material.index].concat(properties.ids);
                     loader.addLoaderPendingData(material);
                     loader.addLoaderPendingData(material);
+                    for (var index = 0; index < materialLODs.length; index++) {
+                        loader.addLoaderNonBlockingPendingData(index);
+                    }
                     // Start with the lowest quality LOD.
                     // Start with the lowest quality LOD.
-                    var materialLODs = [material.index].concat(properties.ids);
                     this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
                     this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
                     return true;
                     return true;
                 };
                 };
                 MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
                 MSFTLOD.prototype.loadMaterialLOD = function (loader, material, materialLODs, lod, assign) {
                     var _this = this;
                     var _this = this;
                     var materialLOD = loader.gltf.materials[materialLODs[lod]];
                     var materialLOD = loader.gltf.materials[materialLODs[lod]];
+                    if (lod !== materialLODs.length - 1) {
+                        loader.blockPendingTracking = true;
+                    }
                     loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
                     loader.loadMaterial(materialLOD, function (babylonMaterial, isNew) {
                         assign(babylonMaterial, isNew);
                         assign(babylonMaterial, isNew);
-                        // Loading is complete if this is the highest quality LOD.
-                        if (lod === 0) {
+                        loader.removeLoaderPendingData(lod);
+                        // Loading is considered complete if this is the lowest quality LOD.
+                        if (lod === materialLODs.length - 1) {
                             loader.removeLoaderPendingData(material);
                             loader.removeLoaderPendingData(material);
+                        }
+                        if (lod === 0) {
+                            loader.blockPendingTracking = false;
                             return;
                             return;
                         }
                         }
                         // Load the next LOD when the loader is ready to render and
                         // Load the next LOD when the loader is ready to render and
                         // all active material textures of the current LOD are loaded.
                         // all active material textures of the current LOD are loaded.
                         loader.executeWhenRenderReady(function () {
                         loader.executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
-                                _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                setTimeout(function () {
+                                    _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                                }, MSFTLOD.MinimalLODDelay);
                             });
                             });
                         });
                         });
                     });
                     });
                 };
                 };
                 return MSFTLOD;
                 return MSFTLOD;
             }(GLTF2.GLTFLoaderExtension));
             }(GLTF2.GLTFLoaderExtension));
+            /**
+             * Specify the minimal delay between LODs in ms (default = 250)
+             */
+            MSFTLOD.MinimalLODDelay = 250;
             Extensions.MSFTLOD = MSFTLOD;
             Extensions.MSFTLOD = MSFTLOD;
             GLTF2.GLTFLoader.RegisterExtension(new MSFTLOD());
             GLTF2.GLTFLoader.RegisterExtension(new MSFTLOD());
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));
         })(Extensions = GLTF2.Extensions || (GLTF2.Extensions = {}));

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


+ 26 - 4
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -6,6 +6,11 @@ module BABYLON.GLTF2.Extensions {
     }
     }
 
 
     export class MSFTLOD extends GLTFLoaderExtension {
     export class MSFTLOD extends GLTFLoaderExtension {
+        /**
+         * Specify the minimal delay between LODs in ms (default = 250)
+         */
+        public static MinimalLODDelay = 250;
+
         public get name() {
         public get name() {
             return "MSFT_lod";
             return "MSFT_lod";
         }
         }
@@ -24,10 +29,14 @@ module BABYLON.GLTF2.Extensions {
             material.extensions[this.name] = undefined;
             material.extensions[this.name] = undefined;
 
 
             // Tell the loader not to clear its state until the highest LOD is loaded.
             // Tell the loader not to clear its state until the highest LOD is loaded.
+            var materialLODs = [material.index, ...properties.ids];
+
             loader.addLoaderPendingData(material);
             loader.addLoaderPendingData(material);
+            for (var index = 0; index < materialLODs.length; index++) {
+                loader.addLoaderNonBlockingPendingData(index);
+            }
 
 
             // Start with the lowest quality LOD.
             // Start with the lowest quality LOD.
-            var materialLODs = [material.index, ...properties.ids];
             this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
             this.loadMaterialLOD(loader, material, materialLODs, materialLODs.length - 1, assign);
 
 
             return true;
             return true;
@@ -35,12 +44,23 @@ module BABYLON.GLTF2.Extensions {
 
 
         private loadMaterialLOD(loader: GLTFLoader, material: IGLTFMaterial, materialLODs: number[], lod: number, assign: (babylonMaterial: Material, isNew: boolean) => void): void {
         private loadMaterialLOD(loader: GLTFLoader, material: IGLTFMaterial, materialLODs: number[], lod: number, assign: (babylonMaterial: Material, isNew: boolean) => void): void {
             var materialLOD = loader.gltf.materials[materialLODs[lod]];
             var materialLOD = loader.gltf.materials[materialLODs[lod]];
+
+            if (lod !== materialLODs.length - 1) {
+                loader.blockPendingTracking = true;
+            }
+            
             loader.loadMaterial(materialLOD, (babylonMaterial, isNew) => {
             loader.loadMaterial(materialLOD, (babylonMaterial, isNew) => {
                 assign(babylonMaterial, isNew);
                 assign(babylonMaterial, isNew);
 
 
-                // Loading is complete if this is the highest quality LOD.
-                if (lod === 0) {
+                loader.removeLoaderPendingData(lod);
+
+                // Loading is considered complete if this is the lowest quality LOD.
+                if (lod === materialLODs.length - 1) {
                     loader.removeLoaderPendingData(material);
                     loader.removeLoaderPendingData(material);
+                }
+
+                if (lod === 0) {
+                    loader.blockPendingTracking = false;
                     return;
                     return;
                 }
                 }
 
 
@@ -48,7 +68,9 @@ module BABYLON.GLTF2.Extensions {
                 // all active material textures of the current LOD are loaded.
                 // all active material textures of the current LOD are loaded.
                 loader.executeWhenRenderReady(() => {
                 loader.executeWhenRenderReady(() => {
                     BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), () => {
                     BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), () => {
-                        this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                        setTimeout(()=> {
+                            this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
+                        }, MSFTLOD.MinimalLODDelay);
                     });
                     });
                 });
                 });
             });
             });

+ 39 - 10
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -13,6 +13,8 @@ module BABYLON.GLTF2 {
         private _renderReady: boolean = false;
         private _renderReady: boolean = false;
         private _disposed: boolean = false;
         private _disposed: boolean = false;
         private _objectURLs: string[] = new Array<string>();
         private _objectURLs: string[] = new Array<string>();
+        private _blockPendingTracking: boolean = false;
+        private _nonBlockingData: Array<any>;
 
 
         // Observable with boolean indicating success or error.
         // Observable with boolean indicating success or error.
         private _renderReadyObservable = new Observable<GLTFLoader>();
         private _renderReadyObservable = new Observable<GLTFLoader>();
@@ -140,13 +142,17 @@ module BABYLON.GLTF2 {
         }
         }
 
 
         private _onLoaderComplete(): void {
         private _onLoaderComplete(): void {
-            this.dispose();
-
             if (this._parent.onComplete) {
             if (this._parent.onComplete) {
                 this._parent.onComplete();
                 this._parent.onComplete();
             }
             }
         }
         }
 
 
+        private _onLoaderFirstLODComplete(): void {
+            if (this._parent.onFirstLODComplete) {
+                this._parent.onFirstLODComplete();
+            }
+        }
+
         private _loadData(data: IGLTFLoaderData): void {
         private _loadData(data: IGLTFLoaderData): void {
             this._gltf = <IGLTF>data.json;
             this._gltf = <IGLTF>data.json;
 
 
@@ -406,14 +412,14 @@ module BABYLON.GLTF2 {
                                     if (isNew && this._parent.onMaterialLoaded) {
                                     if (isNew && this._parent.onMaterialLoaded) {
                                         this._parent.onMaterialLoaded(babylonMaterial);
                                         this._parent.onMaterialLoaded(babylonMaterial);
                                     }
                                     }
-
-                                    // Note: Removing force compilation from loader as this will be delegated to users as they
-                                    // may want to add more options to the material before compiling it
-                                    //this.addPendingData(material);
-                                    //babylonMaterial.forceCompilation(babylonMesh, babylonMaterial => {
+                                    
+                                    if (this._parent.onBeforeMaterialReadyAsync) {
+                                        this._parent.onBeforeMaterialReadyAsync(babylonMaterial, babylonMesh, babylonMultiMaterial.subMaterials[i] != null, () => {
+                                            babylonMultiMaterial.subMaterials[i] = babylonMaterial;
+                                        });
+                                    } else {
                                         babylonMultiMaterial.subMaterials[i] = babylonMaterial;
                                         babylonMultiMaterial.subMaterials[i] = babylonMaterial;
-                                    //    this.removePendingData(material);
-                                    //});
+                                    }
                                 });
                                 });
                             }
                             }
                         }
                         }
@@ -855,6 +861,10 @@ module BABYLON.GLTF2 {
             }
             }
         }
         }
 
 
+        public set blockPendingTracking(value: boolean) {
+            this._blockPendingTracking = value;
+        }
+
         public addPendingData(data: any) {
         public addPendingData(data: any) {
             if (!this._renderReady) {
             if (!this._renderReady) {
                 this._renderPendingCount++;
                 this._renderPendingCount++;
@@ -874,13 +884,32 @@ module BABYLON.GLTF2 {
             this.removeLoaderPendingData(data);
             this.removeLoaderPendingData(data);
         }
         }
 
 
+        public addLoaderNonBlockingPendingData(data: any): void {
+            if (!this._nonBlockingData) {
+                this._nonBlockingData = new Array<any>();
+            }
+            this._nonBlockingData.push(data);
+        }
+
         public addLoaderPendingData(data: any) {
         public addLoaderPendingData(data: any) {
+            if (this._blockPendingTracking) {
+                this.addLoaderNonBlockingPendingData(data);
+                return;
+            }            
             this._loaderPendingCount++;
             this._loaderPendingCount++;
         }
         }
 
 
         public removeLoaderPendingData(data: any) {
         public removeLoaderPendingData(data: any) {
-            if (--this._loaderPendingCount === 0) {
+            var indexInPending = this._nonBlockingData ? this._nonBlockingData.indexOf(data) : -1;
+            if (indexInPending !== -1) {
+                this._nonBlockingData.splice(indexInPending, 1);
+            } else if (--this._loaderPendingCount === 0) {
+                this._onLoaderFirstLODComplete();
+            }
+
+            if ((!this._nonBlockingData || this._nonBlockingData.length === 0) && this._loaderPendingCount === 0) {
                 this._onLoaderComplete();
                 this._onLoaderComplete();
+                this.dispose();
             }
             }
         }
         }
 
 

+ 11 - 0
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -35,7 +35,18 @@ module BABYLON {
         public coordinateSystemMode: GLTFLoaderCoordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
         public coordinateSystemMode: GLTFLoaderCoordinateSystemMode = GLTFLoaderCoordinateSystemMode.AUTO;
         public onTextureLoaded: (texture: BaseTexture) => void;
         public onTextureLoaded: (texture: BaseTexture) => void;
         public onMaterialLoaded: (material: Material) => void;
         public onMaterialLoaded: (material: Material) => void;
+        /**
+         * Let the user decides if he needs to process the material (like precompilation) before affecting it to meshes
+         */
+        public onBeforeMaterialReadyAsync: (material: Material, targetMesh: AbstractMesh, isLOD: boolean, callback: () => void) => void;
+        /**
+         * Raised when all LODs are complete (or if there is no LOD and model is complete)
+         */
         public onComplete: () => void;
         public onComplete: () => void;
+        /**
+         * Raised when first LOD complete (or if there is no LOD and model is complete)
+         */
+        public onFirstLODComplete: () => void;
 
 
         public name = "gltf";
         public name = "gltf";
 
 

+ 0 - 1
readme.md

@@ -29,7 +29,6 @@ If you want to contribute, please read our [contribution guidelines](https://git
 
 
 ## Documentation
 ## Documentation
 - [Documentation](http://doc.babylonjs.com)
 - [Documentation](http://doc.babylonjs.com)
-- [Roadmap](http://doc.babylonjs.com/generals/Roadmap)
 - [Samples](https://github.com/BabylonJS/Samples)
 - [Samples](https://github.com/BabylonJS/Samples)
 - [Video overview (1 hour) of BabylonJS features](http://www.youtube.com/watch?v=z80TYMqsdEM)
 - [Video overview (1 hour) of BabylonJS features](http://www.youtube.com/watch?v=z80TYMqsdEM)
 - [Complete course (8 hours)](http://www.microsoftvirtualacademy.com/training-courses/introduction-to-webgl-3d-with-html5-and-babylon-js)
 - [Complete course (8 hours)](http://www.microsoftvirtualacademy.com/training-courses/introduction-to-webgl-3d-with-html5-and-babylon-js)

+ 14 - 0
sandbox/index.js

@@ -22,6 +22,20 @@
 
 
     if (!currentHelpCounter) currentHelpCounter = 0;
     if (!currentHelpCounter) currentHelpCounter = 0;
 
 
+    // Setting up some GLTF values
+    BABYLON.SceneLoader.OnPluginActivatedObservable.add(function(plugin) {
+        if (plugin.name !== "gltf") {
+            return;
+        }
+        plugin.onBeforeMaterialReadyAsync = function(material, mesh, isLOD, callback) {
+            if (!isLOD) {
+                callback();
+                return;
+            }
+            material.forceCompilation(mesh, callback);
+        }
+    });
+
     // Resize
     // Resize
     window.addEventListener("resize", function () {
     window.addEventListener("resize", function () {
         engine.resize();
         engine.resize();

+ 36 - 0
src/Lights/Shadows/babylon.shadowGenerator.ts

@@ -14,6 +14,8 @@
 
 
         recreateShadowMap(): void;
         recreateShadowMap(): void;
 
 
+        forceCompilation(onCompiled: (generator: ShadowGenerator) => void, options?: { useInstances: boolean }): void;
+
         serialize(): any;
         serialize(): any;
         dispose(): void;
         dispose(): void;
     }
     }
@@ -510,6 +512,40 @@
         }
         }
 
 
         /**
         /**
+         * Force shader compilation including textures ready check
+         */
+        public forceCompilation(onCompiled: (generator: ShadowGenerator) => void, options?: { useInstances: boolean }): void {
+            var scene = this._scene;
+            var engine = scene.getEngine();
+            var subMeshes = new Array<SubMesh>();
+            var currentIndex = 0;
+
+
+            for(var mesh of this.getShadowMap().renderList) {
+                subMeshes.push(...mesh.subMeshes);
+            }
+
+            var checkReady = () => {
+                let subMesh = subMeshes[currentIndex];
+
+                if (this._scene && this._scene.getEngine() && this.isReady(subMesh, options ? options.useInstances : false)) {
+                    currentIndex++;
+                    if (currentIndex >= subMeshes.length) {
+                        if (onCompiled) {
+                            onCompiled(this);
+                        }
+                        return;
+                    }
+                }
+                setTimeout(checkReady, 16);
+            };
+
+            if (subMeshes.length > 0) {
+                checkReady();            
+            }
+        }
+
+        /**
          * Boolean : true when the ShadowGenerator is finally computed.  
          * Boolean : true when the ShadowGenerator is finally computed.  
          */
          */
         public isReady(subMesh: SubMesh, useInstances: boolean): boolean {
         public isReady(subMesh: SubMesh, useInstances: boolean): boolean {

+ 4 - 0
src/Loading/babylon.sceneLoader.ts

@@ -74,6 +74,8 @@
         }
         }
 
 
         // Members
         // Members
+        public static OnPluginActivatedObservable = new Observable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>();
+
         private static _registeredPlugins: { [extension: string]: IRegisteredPlugin } = {};
         private static _registeredPlugins: { [extension: string]: IRegisteredPlugin } = {};
 
 
         private static _getDefaultPlugin(): IRegisteredPlugin {
         private static _getDefaultPlugin(): IRegisteredPlugin {
@@ -134,6 +136,8 @@
             var useArrayBuffer = registeredPlugin.isBinary;
             var useArrayBuffer = registeredPlugin.isBinary;
             var database: Database;
             var database: Database;
 
 
+            SceneLoader.OnPluginActivatedObservable.notifyObservers(registeredPlugin.plugin);
+
             var dataCallback = data => {
             var dataCallback = data => {
                 if (scene.isDisposed) {
                 if (scene.isDisposed) {
                     onError("Scene has been disposed");
                     onError("Scene has been disposed");

+ 2 - 2
src/Materials/Textures/babylon.renderTargetTexture.ts

@@ -327,7 +327,7 @@
             let camera: Camera;
             let camera: Camera;
             if (this.activeCamera) {
             if (this.activeCamera) {
                 camera = this.activeCamera;
                 camera = this.activeCamera;
-                engine.setViewport(this.activeCamera.viewport);
+                engine.setViewport(this.activeCamera.viewport, this._size, this._size);
 
 
                 if (this.activeCamera !== scene.activeCamera)
                 if (this.activeCamera !== scene.activeCamera)
                 {
                 {
@@ -336,7 +336,7 @@
             }
             }
             else {
             else {
                 camera = scene.activeCamera;
                 camera = scene.activeCamera;
-                engine.setViewport(scene.activeCamera.viewport);
+                engine.setViewport(scene.activeCamera.viewport, this._size, this._size);
             }
             }
 
 
             // Prepare renderingManager
             // Prepare renderingManager

+ 5 - 3
src/Materials/babylon.material.ts

@@ -516,7 +516,9 @@
             return result;
             return result;
         }
         }
 
 
-        // Force shader compilation including textures ready check
+        /**
+         * Force shader compilation including textures ready check
+         */
         public forceCompilation(mesh: AbstractMesh, onCompiled: (material: Material) => void, options?: { alphaTest: boolean, clipPlane: boolean }): void {
         public forceCompilation(mesh: AbstractMesh, onCompiled: (material: Material) => void, options?: { alphaTest: boolean, clipPlane: boolean }): void {
             var subMesh = new BaseSubMesh();
             var subMesh = new BaseSubMesh();
             var scene = this.getScene();
             var scene = this.getScene();
@@ -532,7 +534,7 @@
 
 
                 engine.setAlphaTesting(options ? options.alphaTest : this.needAlphaTesting());
                 engine.setAlphaTesting(options ? options.alphaTest : this.needAlphaTesting());
 
 
-                if (options.clipPlane) {
+                if (options && options.clipPlane) {
                     scene.clipPlane = new Plane(0, 0, 0, 1);
                     scene.clipPlane = new Plane(0, 0, 0, 1);
                 }
                 }
 
 
@@ -558,7 +560,7 @@
 
 
                 engine.setAlphaTesting(alphaTestState);
                 engine.setAlphaTesting(alphaTestState);
 
 
-                if (options.clipPlane) {
+                if (options && options.clipPlane) {
                     scene.clipPlane = clipPlaneState;
                     scene.clipPlane = clipPlaneState;
                 }
                 }
             };
             };

+ 4 - 1
src/Mesh/babylon.geometry.ts

@@ -22,6 +22,7 @@
         public _delayLoadingFunction: (any: any, geometry: Geometry) => void;
         public _delayLoadingFunction: (any: any, geometry: Geometry) => void;
         public _softwareSkinningRenderId: number;
         public _softwareSkinningRenderId: number;
         private _vertexArrayObjects: { [key: string]: WebGLVertexArrayObject; };
         private _vertexArrayObjects: { [key: string]: WebGLVertexArrayObject; };
+        private _updatable: boolean;
 
 
         // Cache
         // Cache
         public _positions: Vector3[];
         public _positions: Vector3[];
@@ -52,6 +53,7 @@
             //Init vertex buffer cache
             //Init vertex buffer cache
             this._vertexBuffers = {};
             this._vertexBuffers = {};
             this._indices = [];
             this._indices = [];
+            this._updatable = updatable;
 
 
             // vertexData
             // vertexData
             if (vertexData) {
             if (vertexData) {
@@ -654,6 +656,7 @@
             var serializationObject: any = {};
             var serializationObject: any = {};
 
 
             serializationObject.id = this.id;
             serializationObject.id = this.id;
+            serializationObject.updatable = this._updatable;
 
 
             if (Tags && Tags.HasTags(this)) {
             if (Tags && Tags.HasTags(this)) {
                 serializationObject.tags = Tags.GetTags(this);
                 serializationObject.tags = Tags.GetTags(this);
@@ -993,7 +996,7 @@
                 return null; // null since geometry could be something else than a box...
                 return null; // null since geometry could be something else than a box...
             }
             }
 
 
-            var geometry = new Geometry(parsedVertexData.id, scene);
+            var geometry = new Geometry(parsedVertexData.id, scene, null, parsedVertexData.updatable);
 
 
             if (Tags) {
             if (Tags) {
                 Tags.AddTagsTo(geometry, parsedVertexData.tags);
                 Tags.AddTagsTo(geometry, parsedVertexData.tags);

+ 86 - 9
src/Tools/babylon.filesInput.ts

@@ -66,6 +66,51 @@
             this.loadFiles(eventDrop);
             this.loadFiles(eventDrop);
         }
         }
 
 
+        private _handleFolderDrop(entry: any, files: Array<any>, callback: () => void): void {
+            var reader = entry.createReader(),
+ 			relativePath = entry.fullPath.replace(/^\//, "").replace(/(.+?)\/?$/, "$1/");
+ 			reader.readEntries((fileEntries) => {
+                var remaining = fileEntries.length;
+                for (let fileEntry of fileEntries) {
+                    if (fileEntry.isFile) { // We only support one level
+                        fileEntry.file(function(file) {
+                            file.correctName = relativePath + file.name;
+                            files.push(file);
+            
+                            remaining--;
+
+                            if (remaining === 0) {
+                                callback();
+                            }
+                        });
+                    } else {
+                        remaining--;
+
+                        if (remaining === 0) {
+                            callback();
+                        }
+                    }
+                }
+            });
+        }
+
+        private _processFiles(files: Array<any>): void {
+            for (var i = 0; i < files.length; i++) {
+                var name = files[i].correctName.toLowerCase();
+                var extension = name.split('.').pop();
+                
+                if ((extension === "babylon" || extension === "stl" || extension === "obj" || extension === "gltf" || extension === "glb") 
+                    && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
+                    this._sceneFileToLoad = files[i];
+                }
+                else {
+                    FilesInput.FilesToLoad[name] = files[i];
+                }
+            }
+
+            this.reload();
+        }
+
         public loadFiles(event): void {
         public loadFiles(event): void {
             if (this._startingProcessingFilesCallback) this._startingProcessingFilesCallback();
             if (this._startingProcessingFilesCallback) this._startingProcessingFilesCallback();
 
 
@@ -80,21 +125,53 @@
             }
             }
 
 
             if (this._filesToLoad && this._filesToLoad.length > 0) {
             if (this._filesToLoad && this._filesToLoad.length > 0) {
+        
+                let files = [];
+                let folders = [];
                 for (var i = 0; i < this._filesToLoad.length; i++) {
                 for (var i = 0; i < this._filesToLoad.length; i++) {
-                    let name = this._filesToLoad[i].name.toLowerCase();
-                    let extension = name.split('.').pop();
-                    let type = this._filesToLoad[i].type;
+                    let fileToLoad:any =  this._filesToLoad[i];
+                    let name = fileToLoad.name.toLowerCase();
+                    let type = fileToLoad.type;
+                    let entry;
+
+                    fileToLoad.correctName = name;
                     
                     
-                    if ((extension === "babylon" || extension === "stl" || extension === "obj" || extension === "gltf" || extension === "glb") 
-                        && name.indexOf(".binary.babylon") === -1 && name.indexOf(".incremental.babylon") === -1) {
-                        this._sceneFileToLoad = this._filesToLoad[i];
+                    if (event.dataTransfer && event.dataTransfer.items) {
+                        let item = event.dataTransfer.items[i];
+                        if (item.getAsEntry) {
+                            entry = item.getAsEntry();
+                        } else if (item.webkitGetAsEntry) {
+                            entry = item.webkitGetAsEntry();
+                        }                     
                     }
                     }
-                    else {
-                        FilesInput.FilesToLoad[name] = this._filesToLoad[i];
+
+                    if (!entry) {    
+                        files.push(fileToLoad);
+                    } else {
+                        if (entry.isDirectory) {
+                            folders.push(entry);
+                        } else {
+                            files.push(fileToLoad);
+                        }
                     }
                     }
                 }
                 }
 
 
-                this.reload();
+                if (folders.length === 0) {
+                    this._processFiles(files);
+                } else {
+                    var remaining = folders.length;
+
+                    // Extract folder content
+                    for (var folder of folders) {
+                        this._handleFolderDrop(folder, files, () => {
+                            remaining--;
+
+                            if (remaining === 0) {
+                                this._processFiles(files);
+                            }
+                        });
+                    }
+                }
             }
             }
         }
         }
 
 

+ 8 - 1
src/babylon.engine.ts

@@ -3897,10 +3897,17 @@
         }
         }
 
 
         public _setAnisotropicLevel(key: number, texture: BaseTexture) {
         public _setAnisotropicLevel(key: number, texture: BaseTexture) {
+            var internalTexture = texture.getInternalTexture();
+
+            if (!internalTexture) {
+                return;
+            }
+
             var anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
             var anisotropicFilterExtension = this._caps.textureAnisotropicFilterExtension;
             var value = texture.anisotropicFilteringLevel;
             var value = texture.anisotropicFilteringLevel;
+            
 
 
-            if (texture.getInternalTexture().samplingMode === Texture.NEAREST_SAMPLINGMODE) {
+            if (internalTexture.samplingMode === Texture.NEAREST_SAMPLINGMODE) {
                 value = 1;
                 value = 1;
             }
             }