Browse Source

Fix the fix for button.isHitTestVisible

David Catuhe 8 years ago
parent
commit
beb682043b

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


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


+ 134 - 133
dist/preview release/babylon.max.js

@@ -15400,7 +15400,8 @@ var BABYLON;
                 if ((activeCamera.layerMask & particleSystem.layerMask) === 0) {
                     continue;
                 }
-                if (!particleSystem.emitter.position || !activeMeshes || activeMeshes.indexOf(particleSystem.emitter) !== -1) {
+                var emitter = particleSystem.emitter;
+                if (!emitter.position || !activeMeshes || activeMeshes.indexOf(emitter) !== -1) {
                     this._scene._activeParticles.addCount(particleSystem.render(), false);
                 }
             }
@@ -17316,7 +17317,7 @@ var BABYLON;
         /**
          * get a particle system by id
          * @param id {number} the particle system id
-         * @return {BABYLON.ParticleSystem|null} the corresponding system or null if none found.
+         * @return {BABYLON.IParticleSystem|null} the corresponding system or null if none found.
          */
         Scene.prototype.getParticleSystemByID = function (id) {
             for (var index = 0; index < this.particleSystems.length; index++) {
@@ -17690,10 +17691,11 @@ var BABYLON;
                 BABYLON.Tools.StartPerformanceCounter("Particles", this.particleSystems.length > 0);
                 for (var particleIndex = 0; particleIndex < this.particleSystems.length; particleIndex++) {
                     var particleSystem = this.particleSystems[particleIndex];
-                    if (!particleSystem.isStarted()) {
+                    if (!particleSystem.isStarted() || !particleSystem.emitter) {
                         continue;
                     }
-                    if (!particleSystem.emitter.position || (particleSystem.emitter && particleSystem.emitter.isEnabled())) {
+                    var emitter = particleSystem.emitter;
+                    if (!emitter.position || emitter.isEnabled()) {
                         this._activeParticleSystems.push(particleSystem);
                         particleSystem.animate();
                         this._renderingManager.dispatchParticles(particleSystem);
@@ -21036,7 +21038,8 @@ var BABYLON;
             descendants.push(this);
             for (var index = 0; index < this.getScene().particleSystems.length; index++) {
                 var particleSystem = this.getScene().particleSystems[index];
-                if (descendants.indexOf(particleSystem.emitter) !== -1) {
+                var emitter = particleSystem.emitter;
+                if (emitter.position && descendants.indexOf(emitter) !== -1) {
                     results.push(particleSystem);
                 }
             }
@@ -39145,10 +39148,12 @@ var BABYLON;
             // Add new ones
             var worldMatrix;
             if (this.emitter.position) {
-                worldMatrix = this.emitter.getWorldMatrix();
+                var emitterMesh = this.emitter;
+                worldMatrix = emitterMesh.getWorldMatrix();
             }
             else {
-                worldMatrix = BABYLON.Matrix.Translation(this.emitter.x, this.emitter.y, this.emitter.z);
+                var emitterPosition = this.emitter;
+                worldMatrix = BABYLON.Matrix.Translation(emitterPosition.x, emitterPosition.y, emitterPosition.z);
             }
             var particle;
             for (var index = 0; index < newParticles; index++) {
@@ -39301,7 +39306,9 @@ var BABYLON;
             }
             // Remove from scene
             var index = this._scene.particleSystems.indexOf(this);
-            this._scene.particleSystems.splice(index, 1);
+            if (index > -1) {
+                this._scene.particleSystems.splice(index, 1);
+            }
             // Callback
             this.onDisposeObservable.notifyObservers(this);
             this.onDisposeObservable.clear();
@@ -39336,10 +39343,12 @@ var BABYLON;
             serializationObject.id = this.id;
             // Emitter
             if (this.emitter.position) {
-                serializationObject.emitterId = this.emitter.id;
+                var emitterMesh = this.emitter;
+                serializationObject.emitterId = emitterMesh.id;
             }
             else {
-                serializationObject.emitter = this.emitter.asArray();
+                var emitterPosition = this.emitter;
+                serializationObject.emitter = emitterPosition.asArray();
             }
             serializationObject.capacity = this.getCapacity();
             if (this.particleTexture) {
@@ -44265,10 +44274,11 @@ var BABYLON;
             }
             for (var particleIndex = 0; particleIndex < scene.particleSystems.length; particleIndex++) {
                 var particleSystem = scene.particleSystems[particleIndex];
-                if (!particleSystem.isStarted() || !particleSystem.emitter || !particleSystem.emitter.position || !particleSystem.emitter.isEnabled()) {
+                var emitter = particleSystem.emitter;
+                if (!particleSystem.isStarted() || !emitter || !emitter.position || !emitter.isEnabled()) {
                     continue;
                 }
-                if (currentRenderList.indexOf(particleSystem.emitter) >= 0) {
+                if (currentRenderList.indexOf(emitter) >= 0) {
                     this._renderingManager.dispatchParticles(particleSystem);
                 }
             }
@@ -46367,6 +46377,47 @@ var BABYLON;
             }
             return null;
         };
+        SceneLoader._loadData = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError) {
+            var directLoad = SceneLoader._getDirectLoad(sceneFilename);
+            var registeredPlugin = directLoad ? SceneLoader._getPluginForDirectLoad(sceneFilename) : SceneLoader._getPluginForFilename(sceneFilename);
+            var plugin = registeredPlugin.plugin;
+            var useArrayBuffer = registeredPlugin.isBinary;
+            var database;
+            var dataCallback = function (data) {
+                if (scene.isDisposed) {
+                    onError("Scene has been disposed");
+                    return;
+                }
+                scene.database = database;
+                try {
+                    onSuccess(plugin, data);
+                }
+                catch (e) {
+                    onError(null, e);
+                }
+            };
+            var manifestChecked = function (success) {
+                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, dataCallback, onProgress, database, useArrayBuffer, function (request) {
+                    onError(request.status + " " + request.statusText);
+                });
+            };
+            if (directLoad) {
+                dataCallback(directLoad);
+                return;
+            }
+            if (rootUrl.indexOf("file:") === -1) {
+                if (scene.getEngine().enableOfflineSupport) {
+                    // Checking if a manifest file has been set for this scene and if offline mode has been requested
+                    database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
+                }
+                else {
+                    manifestChecked(true);
+                }
+            }
+            else {
+                BABYLON.Tools.ReadFile(sceneFilename, dataCallback, onProgress, useArrayBuffer);
+            }
+        };
         // Public functions
         SceneLoader.GetPluginForExtension = function (extension) {
             return SceneLoader._getPluginForExtension(extension).plugin;
@@ -46389,180 +46440,130 @@ var BABYLON;
                 });
             }
         };
-        SceneLoader.ImportMesh = function (meshesNames, rootUrl, sceneFilename, scene, onsuccess, progressCallBack, onerror) {
-            if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
-                BABYLON.Tools.Error("Wrong sceneFilename parameter");
-                return;
-            }
+        /**
+        * Import meshes into a scene
+        * @param meshNames an array of mesh names, a single mesh name, or empty string for all meshes that filter what meshes are imported
+        * @param rootUrl a string that defines the root url for scene and resources
+        * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
+        * @param scene the instance of BABYLON.Scene to append to
+        * @param onSuccess a callback with a list of imported meshes, particleSystems, and skeletons when import succeeds
+        * @param onProgress a callback with a progress event for each file being loaded
+        * @param onError a callback with the scene, a message, and possibly an exception when import fails
+        */
+        SceneLoader.ImportMesh = function (meshNames, rootUrl, sceneFilename, scene, onSuccess, onProgress, onError) {
             if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
                 BABYLON.Tools.Error("Wrong sceneFilename parameter");
                 return;
             }
-            var directLoad = SceneLoader._getDirectLoad(sceneFilename);
             var loadingToken = {};
             scene._addPendingData(loadingToken);
-            var manifestChecked = function (success) {
-                scene.database = database;
-                var registeredPlugin = directLoad ? SceneLoader._getPluginForDirectLoad(directLoad) : SceneLoader._getPluginForFilename(sceneFilename);
-                var plugin = registeredPlugin.plugin;
-                var useArrayBuffer = registeredPlugin.isBinary;
-                var importMeshFromData = function (data) {
+            var errorHandler = function (message, exception) {
+                if (onError) {
+                    onError(scene, "Unable to import meshes from " + rootUrl + sceneFilename + (message ? ": " + message : ""));
+                }
+                scene._removePendingData(loadingToken);
+            };
+            var progressHandler = function (event) {
+                if (onProgress) {
+                    onProgress(event);
+                }
+            };
+            SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data) {
+                if (plugin.importMesh) {
+                    var syncedPlugin = plugin;
                     var meshes = [];
                     var particleSystems = [];
                     var skeletons = [];
-                    if (scene.isDisposed) {
-                        if (onerror) {
-                            onerror(scene, 'Scene was disposed before being able to load ' + rootUrl + sceneFilename);
-                        }
+                    if (!syncedPlugin.importMesh(meshNames, scene, data, rootUrl, meshes, particleSystems, skeletons, errorHandler)) {
                         return;
                     }
-                    try {
-                        if (plugin.importMesh) {
-                            var syncedPlugin = plugin;
-                            if (!syncedPlugin.importMesh(meshesNames, scene, data, rootUrl, meshes, particleSystems, skeletons)) {
-                                if (onerror) {
-                                    onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
-                                }
-                                scene._removePendingData(loadingToken);
-                                return;
-                            }
-                            if (onsuccess) {
-                                scene.importedMeshesFiles.push(rootUrl + sceneFilename);
-                                onsuccess(meshes, particleSystems, skeletons);
-                                scene._removePendingData(loadingToken);
-                            }
-                        }
-                        else {
-                            var asyncedPlugin = plugin;
-                            asyncedPlugin.importMeshAsync(meshesNames, scene, data, rootUrl, function (meshes, particleSystems, skeletons) {
-                                if (onsuccess) {
-                                    scene.importedMeshesFiles.push(rootUrl + sceneFilename);
-                                    onsuccess(meshes, particleSystems, skeletons);
-                                    scene._removePendingData(loadingToken);
-                                }
-                            }, function () {
-                                if (onerror) {
-                                    onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename);
-                                }
-                                scene._removePendingData(loadingToken);
-                            });
-                        }
-                    }
-                    catch (e) {
-                        if (onerror) {
-                            onerror(scene, 'Unable to import meshes from ' + rootUrl + sceneFilename, e);
-                        }
+                    if (onSuccess) {
+                        scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                        onSuccess(meshes, particleSystems, skeletons);
                         scene._removePendingData(loadingToken);
                     }
-                };
-                if (directLoad) {
-                    importMeshFromData(directLoad);
-                    return;
                 }
-                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, function (data) {
-                    importMeshFromData(data);
-                }, progressCallBack, database, useArrayBuffer, function () {
-                    if (onerror) {
-                        onerror(scene, 'Unable to load file ' + rootUrl + sceneFilename);
-                    }
-                });
-            };
-            if (scene.getEngine().enableOfflineSupport && !directLoad) {
-                // Checking if a manifest file has been set for this scene and if offline mode has been requested
-                var database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
-            }
-            else {
-                // If the scene is a data stream or offline support is not enabled, it's a direct load
-                manifestChecked(true);
-            }
+                else {
+                    var asyncedPlugin = plugin;
+                    asyncedPlugin.importMeshAsync(meshNames, scene, data, rootUrl, function (meshes, particleSystems, skeletons) {
+                        if (onSuccess) {
+                            scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                            onSuccess(meshes, particleSystems, skeletons);
+                            scene._removePendingData(loadingToken);
+                        }
+                    }, progressHandler, errorHandler);
+                }
+            }, progressHandler, errorHandler);
         };
         /**
         * Load a scene
         * @param rootUrl a string that defines the root url for scene and resources
         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
         * @param engine is the instance of BABYLON.Engine to use to create the scene
+        * @param onSuccess a callback with the scene when import succeeds
+        * @param onProgress a callback with a progress event for each file being loaded
+        * @param onError a callback with the scene, a message, and possibly an exception when import fails
         */
-        SceneLoader.Load = function (rootUrl, sceneFilename, engine, onsuccess, progressCallBack, onerror) {
-            SceneLoader.Append(rootUrl, sceneFilename, new BABYLON.Scene(engine), onsuccess, progressCallBack, onerror);
+        SceneLoader.Load = function (rootUrl, sceneFilename, engine, onSuccess, onProgress, onError) {
+            SceneLoader.Append(rootUrl, sceneFilename, new BABYLON.Scene(engine), onSuccess, onProgress, onError);
         };
         /**
         * Append a scene
         * @param rootUrl a string that defines the root url for scene and resources
         * @param sceneFilename a string that defines the name of the scene file. can start with "data:" following by the stringified version of the scene
         * @param scene is the instance of BABYLON.Scene to append to
+        * @param onSuccess a callback with the scene when import succeeds
+        * @param onProgress a callback with a progress event for each file being loaded
+        * @param onError a callback with the scene, a message, and possibly an exception when import fails
         */
-        SceneLoader.Append = function (rootUrl, sceneFilename, scene, onsuccess, progressCallBack, onerror) {
+        SceneLoader.Append = function (rootUrl, sceneFilename, scene, onSuccess, onProgress, onError) {
             if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
                 BABYLON.Tools.Error("Wrong sceneFilename parameter");
                 return;
             }
-            var directLoad = SceneLoader._getDirectLoad(sceneFilename);
-            var registeredPlugin = directLoad ? SceneLoader._getPluginForDirectLoad(sceneFilename) : SceneLoader._getPluginForFilename(sceneFilename);
-            var plugin = registeredPlugin.plugin;
-            var useArrayBuffer = registeredPlugin.isBinary;
-            var database;
-            var loadingToken = {};
-            scene._addPendingData(loadingToken);
             if (SceneLoader.ShowLoadingScreen) {
                 scene.getEngine().displayLoadingUI();
             }
-            var loadSceneFromData = function (data) {
-                scene.database = database;
+            var loadingToken = {};
+            scene._addPendingData(loadingToken);
+            var errorHandler = function (message, exception) {
+                if (onError) {
+                    onError(scene, "Unable to load from " + rootUrl + sceneFilename + (message ? ": " + message : ""));
+                }
+                scene._removePendingData(loadingToken);
+                scene.getEngine().hideLoadingUI();
+            };
+            var progressHandler = function (event) {
+                if (onProgress) {
+                    onProgress(event);
+                }
+            };
+            SceneLoader._loadData(rootUrl, sceneFilename, scene, function (plugin, data) {
                 if (plugin.load) {
                     var syncedPlugin = plugin;
-                    if (!syncedPlugin.load(scene, data, rootUrl)) {
-                        if (onerror) {
-                            onerror(scene);
-                        }
-                        scene._removePendingData(loadingToken);
-                        scene.getEngine().hideLoadingUI();
+                    if (!syncedPlugin.load(scene, data, rootUrl, errorHandler)) {
                         return;
                     }
-                    if (onsuccess) {
-                        onsuccess(scene);
+                    if (onSuccess) {
+                        onSuccess(scene);
                     }
                     scene._removePendingData(loadingToken);
                 }
                 else {
                     var asyncedPlugin = plugin;
                     asyncedPlugin.loadAsync(scene, data, rootUrl, function () {
-                        if (onsuccess) {
-                            onsuccess(scene);
+                        if (onSuccess) {
+                            onSuccess(scene);
                         }
                         scene._removePendingData(loadingToken);
-                    }, function () {
-                        if (onerror) {
-                            onerror(scene);
-                        }
-                        scene._removePendingData(loadingToken);
-                        scene.getEngine().hideLoadingUI();
-                    });
+                    }, progressHandler, errorHandler);
                 }
                 if (SceneLoader.ShowLoadingScreen) {
                     scene.executeWhenReady(function () {
                         scene.getEngine().hideLoadingUI();
                     });
                 }
-            };
-            var manifestChecked = function (success) {
-                BABYLON.Tools.LoadFile(rootUrl + sceneFilename, loadSceneFromData, progressCallBack, database, useArrayBuffer);
-            };
-            if (directLoad) {
-                loadSceneFromData(directLoad);
-                return;
-            }
-            if (rootUrl.indexOf("file:") === -1) {
-                if (scene.getEngine().enableOfflineSupport) {
-                    // Checking if a manifest file has been set for this scene and if offline mode has been requested
-                    database = new BABYLON.Database(rootUrl + sceneFilename, manifestChecked);
-                }
-                else {
-                    manifestChecked(true);
-                }
-            }
-            else {
-                BABYLON.Tools.ReadFile(sceneFilename, loadSceneFromData, progressCallBack, useArrayBuffer);
-            }
+            }, progressHandler, errorHandler);
         };
         return SceneLoader;
     }());

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


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


+ 158 - 158
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.d.ts

@@ -4163,6 +4163,134 @@ declare module BABYLON {
     }
 }
 
+declare module BABYLON.Debug {
+    class AxesViewer {
+        private _xline;
+        private _yline;
+        private _zline;
+        private _xmesh;
+        private _ymesh;
+        private _zmesh;
+        scene: Scene;
+        scaleLines: number;
+        constructor(scene: Scene, scaleLines?: number);
+        update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    class BoneAxesViewer extends Debug.AxesViewer {
+        mesh: Mesh;
+        bone: Bone;
+        pos: Vector3;
+        xaxis: Vector3;
+        yaxis: Vector3;
+        zaxis: Vector3;
+        constructor(scene: Scene, bone: Bone, mesh: Mesh, scaleLines?: number);
+        update(): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class DebugLayer {
+        private _scene;
+        static InspectorURL: string;
+        private _inspector;
+        constructor(scene: Scene);
+        /** Creates the inspector window. */
+        private _createInspector(config?);
+        isVisible(): boolean;
+        hide(): void;
+        show(config?: {
+            popup?: boolean;
+            initialTab?: number;
+            parentElement?: HTMLElement;
+            newColors?: {
+                backgroundColor?: string;
+                backgroundColorLighter?: string;
+                backgroundColorLighter2?: string;
+                backgroundColorLighter3?: string;
+                color?: string;
+                colorTop?: string;
+                colorBot?: string;
+            };
+        }): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    class PhysicsViewer {
+        protected _impostors: Array<PhysicsImpostor>;
+        protected _meshes: Array<AbstractMesh>;
+        protected _scene: Scene;
+        protected _numMeshes: number;
+        protected _physicsEnginePlugin: IPhysicsEnginePlugin;
+        private _renderFunction;
+        private _debugBoxMesh;
+        private _debugSphereMesh;
+        private _debugMaterial;
+        constructor(scene: Scene);
+        protected _updateDebugMeshes(): void;
+        showImpostor(impostor: PhysicsImpostor): void;
+        hideImpostor(impostor: PhysicsImpostor): void;
+        private _getDebugMaterial(scene);
+        private _getDebugBoxMesh(scene);
+        private _getDebugSphereMesh(scene);
+        private _getDebugMesh(impostor, scene);
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class RayHelper {
+        ray: Ray;
+        private _renderPoints;
+        private _renderLine;
+        private _renderFunction;
+        private _scene;
+        private _updateToMeshFunction;
+        private _attachedToMesh;
+        private _meshSpaceDirection;
+        private _meshSpaceOrigin;
+        static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper;
+        constructor(ray: Ray);
+        show(scene: Scene, color: Color3): void;
+        hide(): void;
+        private _render();
+        attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void;
+        detachFromMesh(): void;
+        private _updateToMesh();
+        dispose(): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    /**
+    * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
+    */
+    class SkeletonViewer {
+        skeleton: Skeleton;
+        mesh: AbstractMesh;
+        autoUpdateBonesMatrices: boolean;
+        renderingGroupId: number;
+        color: Color3;
+        private _scene;
+        private _debugLines;
+        private _debugMesh;
+        private _isEnabled;
+        private _renderFunction;
+        constructor(skeleton: Skeleton, mesh: AbstractMesh, scene: Scene, autoUpdateBonesMatrices?: boolean, renderingGroupId?: number);
+        isEnabled: boolean;
+        private _getBonePosition(position, bone, meshMat, x?, y?, z?);
+        private _getLinesForBonesWithLength(bones, meshMat);
+        private _getLinesForBonesNoLength(bones, meshMat);
+        update(): void;
+        dispose(): void;
+    }
+}
+
 declare module BABYLON {
     /**
      * Highlight layer options. This helps customizing the behaviour
@@ -4464,134 +4592,6 @@ declare module BABYLON {
     }
 }
 
-declare module BABYLON.Debug {
-    class AxesViewer {
-        private _xline;
-        private _yline;
-        private _zline;
-        private _xmesh;
-        private _ymesh;
-        private _zmesh;
-        scene: Scene;
-        scaleLines: number;
-        constructor(scene: Scene, scaleLines?: number);
-        update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    class BoneAxesViewer extends Debug.AxesViewer {
-        mesh: Mesh;
-        bone: Bone;
-        pos: Vector3;
-        xaxis: Vector3;
-        yaxis: Vector3;
-        zaxis: Vector3;
-        constructor(scene: Scene, bone: Bone, mesh: Mesh, scaleLines?: number);
-        update(): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class DebugLayer {
-        private _scene;
-        static InspectorURL: string;
-        private _inspector;
-        constructor(scene: Scene);
-        /** Creates the inspector window. */
-        private _createInspector(config?);
-        isVisible(): boolean;
-        hide(): void;
-        show(config?: {
-            popup?: boolean;
-            initialTab?: number;
-            parentElement?: HTMLElement;
-            newColors?: {
-                backgroundColor?: string;
-                backgroundColorLighter?: string;
-                backgroundColorLighter2?: string;
-                backgroundColorLighter3?: string;
-                color?: string;
-                colorTop?: string;
-                colorBot?: string;
-            };
-        }): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    class PhysicsViewer {
-        protected _impostors: Array<PhysicsImpostor>;
-        protected _meshes: Array<AbstractMesh>;
-        protected _scene: Scene;
-        protected _numMeshes: number;
-        protected _physicsEnginePlugin: IPhysicsEnginePlugin;
-        private _renderFunction;
-        private _debugBoxMesh;
-        private _debugSphereMesh;
-        private _debugMaterial;
-        constructor(scene: Scene);
-        protected _updateDebugMeshes(): void;
-        showImpostor(impostor: PhysicsImpostor): void;
-        hideImpostor(impostor: PhysicsImpostor): void;
-        private _getDebugMaterial(scene);
-        private _getDebugBoxMesh(scene);
-        private _getDebugSphereMesh(scene);
-        private _getDebugMesh(impostor, scene);
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class RayHelper {
-        ray: Ray;
-        private _renderPoints;
-        private _renderLine;
-        private _renderFunction;
-        private _scene;
-        private _updateToMeshFunction;
-        private _attachedToMesh;
-        private _meshSpaceDirection;
-        private _meshSpaceOrigin;
-        static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper;
-        constructor(ray: Ray);
-        show(scene: Scene, color: Color3): void;
-        hide(): void;
-        private _render();
-        attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void;
-        detachFromMesh(): void;
-        private _updateToMesh();
-        dispose(): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    /**
-    * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
-    */
-    class SkeletonViewer {
-        skeleton: Skeleton;
-        mesh: AbstractMesh;
-        autoUpdateBonesMatrices: boolean;
-        renderingGroupId: number;
-        color: Color3;
-        private _scene;
-        private _debugLines;
-        private _debugMesh;
-        private _isEnabled;
-        private _renderFunction;
-        constructor(skeleton: Skeleton, mesh: AbstractMesh, scene: Scene, autoUpdateBonesMatrices?: boolean, renderingGroupId?: number);
-        isEnabled: boolean;
-        private _getBonePosition(position, bone, meshMat, x?, y?, z?);
-        private _getLinesForBonesWithLength(bones, meshMat);
-        private _getLinesForBonesNoLength(bones, meshMat);
-        update(): void;
-        dispose(): void;
-    }
-}
-
 declare module BABYLON {
     class DirectionalLight extends ShadowLight {
         private _shadowFrustumSize;
@@ -12979,36 +12979,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class ReflectionProbe {
-        name: string;
-        private _scene;
-        private _renderTargetTexture;
-        private _projectionMatrix;
-        private _viewMatrix;
-        private _target;
-        private _add;
-        private _attachedMesh;
-        invertYAxis: boolean;
-        position: Vector3;
-        constructor(name: string, size: number, scene: Scene, generateMipMaps?: boolean);
-        samples: number;
-        refreshRate: number;
-        getScene(): Scene;
-        readonly cubeTexture: RenderTargetTexture;
-        readonly renderList: AbstractMesh[];
-        attachToMesh(mesh: AbstractMesh): void;
-        /**
-         * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
-         *
-         * @param renderingGroupId The rendering group id corresponding to its index
-         * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
-         */
-        setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
     class AnaglyphPostProcess extends PostProcess {
         private _passedProcess;
         constructor(name: string, options: number | PostProcessOptions, rigCameras: Camera[], samplingMode?: number, engine?: Engine, reusable?: boolean);
@@ -13530,6 +13500,36 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class ReflectionProbe {
+        name: string;
+        private _scene;
+        private _renderTargetTexture;
+        private _projectionMatrix;
+        private _viewMatrix;
+        private _target;
+        private _add;
+        private _attachedMesh;
+        invertYAxis: boolean;
+        position: Vector3;
+        constructor(name: string, size: number, scene: Scene, generateMipMaps?: boolean);
+        samples: number;
+        refreshRate: number;
+        getScene(): Scene;
+        readonly cubeTexture: RenderTargetTexture;
+        readonly renderList: AbstractMesh[];
+        attachToMesh(mesh: AbstractMesh): void;
+        /**
+         * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
+         *
+         * @param renderingGroupId The rendering group id corresponding to its index
+         * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
+         */
+        setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
     class BoundingBoxRenderer {
         frontColor: Color3;
         backColor: Color3;

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


+ 181 - 150
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.max.js

@@ -48799,87 +48799,101 @@ var BABYLON;
                 ".glb": { isBinary: true }
             };
         }
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
-            var loaderData = GLTFFileLoader._parse(data);
-            var loader = this._getLoader(loaderData);
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
+            var loaderData = GLTFFileLoader._parse(data, onError);
+            if (!loaderData) {
+                return;
+            }
+            var loader = this._getLoader(loaderData, onError);
             if (!loader) {
-                onError();
                 return;
             }
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
+            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
-            var loaderData = GLTFFileLoader._parse(data);
-            var loader = this._getLoader(loaderData);
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+            var loaderData = GLTFFileLoader._parse(data, onError);
+            if (!loaderData) {
+                return;
+            }
+            var loader = this._getLoader(loaderData, onError);
             if (!loader) {
-                onError();
                 return;
             }
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onError);
+            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
         };
-        GLTFFileLoader._parse = function (data) {
+        GLTFFileLoader._parse = function (data, onError) {
             if (data instanceof ArrayBuffer) {
-                return GLTFFileLoader._parseBinary(data);
+                return GLTFFileLoader._parseBinary(data, onError);
+            }
+            try {
+                return {
+                    json: JSON.parse(data),
+                    bin: null
+                };
+            }
+            catch (e) {
+                onError(e.message);
+                return null;
             }
-            return {
-                json: JSON.parse(data),
-                bin: null
-            };
         };
-        GLTFFileLoader.prototype._getLoader = function (loaderData) {
+        GLTFFileLoader.prototype._getLoader = function (loaderData, onError) {
             var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
             var version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
-                BABYLON.Tools.Error("Invalid version");
+                onError("Invalid version: " + asset.version);
                 return null;
             }
-            var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
-            if (minVersion) {
+            if (asset.minVersion !== undefined) {
+                var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
+                if (!minVersion) {
+                    onError("Invalid minimum version: " + asset.minVersion);
+                    return null;
+                }
                 if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
-                    BABYLON.Tools.Error("Incompatible version");
+                    onError("Incompatible minimum version: " + asset.minVersion);
                     return null;
                 }
             }
-            var createLoader = {
+            var createLoaders = {
                 1: GLTFFileLoader.CreateGLTFLoaderV1,
                 2: GLTFFileLoader.CreateGLTFLoaderV2
             };
-            var loader = createLoader[version.major](this);
-            if (loader === null) {
-                BABYLON.Tools.Error("Unsupported version");
+            var createLoader = createLoaders[version.major];
+            if (!createLoader) {
+                onError("Unsupported version: " + asset.version);
                 return null;
             }
-            return loader;
+            return createLoader(this);
         };
-        GLTFFileLoader._parseBinary = function (data) {
+        GLTFFileLoader._parseBinary = function (data, onError) {
             var Binary = {
                 Magic: 0x46546C67
             };
             var binaryReader = new BinaryReader(data);
             var magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
-                BABYLON.Tools.Error("Unexpected magic: " + magic);
+                onError("Unexpected magic: " + magic);
                 return null;
             }
             var version = binaryReader.readUint32();
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader);
-                case 2: return GLTFFileLoader._parseV2(binaryReader);
+                case 1: return GLTFFileLoader._parseV1(binaryReader, onError);
+                case 2: return GLTFFileLoader._parseV2(binaryReader, onError);
             }
-            BABYLON.Tools.Error("Unsupported version: " + version);
+            onError("Unsupported version: " + version);
             return null;
         };
-        GLTFFileLoader._parseV1 = function (binaryReader) {
+        GLTFFileLoader._parseV1 = function (binaryReader, onError) {
             var ContentFormat = {
                 JSON: 0
             };
             var length = binaryReader.readUint32();
             if (length != binaryReader.getLength()) {
-                BABYLON.Tools.Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
             var contentLength = binaryReader.readUint32();
@@ -48890,7 +48904,7 @@ var BABYLON;
                     content = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(contentLength)));
                     break;
                 default:
-                    BABYLON.Tools.Error("Unexpected content format: " + contentFormat);
+                    onError("Unexpected content format: " + contentFormat);
                     return null;
             }
             var bytesRemaining = binaryReader.getLength() - binaryReader.getPosition();
@@ -48900,21 +48914,21 @@ var BABYLON;
                 bin: body
             };
         };
-        GLTFFileLoader._parseV2 = function (binaryReader) {
+        GLTFFileLoader._parseV2 = function (binaryReader, onError) {
             var ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
             };
             var length = binaryReader.readUint32();
             if (length !== binaryReader.getLength()) {
-                BABYLON.Tools.Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
             // JSON chunk
             var chunkLength = binaryReader.readUint32();
             var chunkFormat = binaryReader.readUint32();
             if (chunkFormat !== ChunkFormat.JSON) {
-                BABYLON.Tools.Error("First chunk format is not JSON");
+                onError("First chunk format is not JSON");
                 return null;
             }
             var json = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(chunkLength)));
@@ -48925,7 +48939,7 @@ var BABYLON;
                 chunkFormat = binaryReader.readUint32();
                 switch (chunkFormat) {
                     case ChunkFormat.JSON:
-                        BABYLON.Tools.Error("Unexpected JSON chunk");
+                        onError("Unexpected JSON chunk");
                         return null;
                     case ChunkFormat.BIN:
                         bin = binaryReader.readUint8Array(chunkLength);
@@ -48946,17 +48960,20 @@ var BABYLON;
                 return null;
             }
             var parts = version.split(".");
-            if (parts.length === 0) {
+            if (parts.length != 2) {
+                return null;
+            }
+            var major = +parts[0];
+            if (isNaN(major)) {
                 return null;
             }
-            var major = parseInt(parts[0]);
-            if (major > 1 && parts.length != 2) {
+            var minor = +parts[1];
+            if (isNaN(minor)) {
                 return null;
             }
-            var minor = parseInt(parts[1]);
             return {
                 major: major,
-                minor: parseInt(parts[0])
+                minor: minor
             };
         };
         GLTFFileLoader._compareVersion = function (a, b) {
@@ -50038,9 +50055,8 @@ var BABYLON;
         */
         var onShaderCompileError = function (program, shaderMaterial, onError) {
             return function (effect, error) {
-                BABYLON.Tools.Error("Cannot compile program named " + program.name + ". Error: " + error + ". Default material will be applied");
                 shaderMaterial.dispose(true);
-                onError();
+                onError("Cannot compile program named " + program.name + ". Error: " + error + ". Default material will be applied");
             };
         };
         /**
@@ -50188,13 +50204,15 @@ var BABYLON;
                     setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(buffer.uri))); });
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, null, true, onError);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, null, true, function (request) {
+                        onError(request.status + " " + request.statusText);
+                    });
                 }
             };
             GLTFLoaderBase.LoadTextureBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
                 var texture = gltfRuntime.textures[id];
                 if (!texture || !texture.source) {
-                    onError();
+                    onError(null);
                     return;
                 }
                 if (texture.babylonTexture) {
@@ -50206,7 +50224,9 @@ var BABYLON;
                     setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(source.uri))); });
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, null, null, true, onError);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, null, null, true, function (request) {
+                        onError(request.status + " " + request.statusText);
+                    });
                 }
             };
             GLTFLoaderBase.CreateTextureAsync = function (gltfRuntime, id, buffer, onSuccess, onError) {
@@ -50238,7 +50258,9 @@ var BABYLON;
                     onSuccess(shaderString);
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, null, null, false, onError);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, null, null, false, function (request) {
+                        onError(request.status + " " + request.statusText);
+                    });
                 }
             };
             GLTFLoaderBase.LoadMaterialAsync = function (gltfRuntime, id, onSuccess, onError) {
@@ -50384,7 +50406,7 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError, onProgress) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 var gltfRuntime = GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -50435,7 +50457,7 @@ var BABYLON;
                 }, onError);
                 return true;
             };
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -50489,7 +50511,7 @@ var BABYLON;
                 }
             };
             ;
-            GLTFLoader.prototype._loadBuffersAsync = function (gltfRuntime, onload, onProgress) {
+            GLTFLoader.prototype._loadBuffersAsync = function (gltfRuntime, onLoad, onProgress) {
                 var hasBuffers = false;
                 var processBuffer = function (buf, buffer) {
                     GLTF1.GLTFLoaderExtension.LoadBufferAsync(gltfRuntime, buf, function (bufferView) {
@@ -50501,7 +50523,7 @@ var BABYLON;
                             gltfRuntime.loadedBufferViews[buf] = bufferView;
                         }
                         if (gltfRuntime.loadedBufferCount === gltfRuntime.buffersCount) {
-                            onload();
+                            onLoad();
                         }
                     }, function () {
                         BABYLON.Tools.Error("Error when loading buffer named " + buf + " located at " + buffer.uri);
@@ -50518,7 +50540,7 @@ var BABYLON;
                     }
                 }
                 if (!hasBuffers) {
-                    onload();
+                    onLoad();
                 }
             };
             GLTFLoader.prototype._createNodes = function (gltfRuntime) {
@@ -51212,8 +51234,15 @@ var BABYLON;
     (function (GLTF2) {
         var GLTFLoader = (function () {
             function GLTFLoader(parent) {
+                this._renderReady = false;
+                this._disposed = false;
+                this._objectURLs = new Array();
                 // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
+                // Count of pending work that needs to complete before the asset is rendered.
+                this._renderPendingCount = 0;
+                // Count of pending work that needs to complete before the loader is cleared.
+                this._loaderPendingCount = 0;
                 this._parent = parent;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -51241,13 +51270,32 @@ var BABYLON;
             });
             GLTFLoader.prototype.executeWhenRenderReady = function (func) {
                 if (this._renderReady) {
-                    func(this._succeeded);
+                    func();
                 }
                 else {
                     this._renderReadyObservable.add(func);
                 }
             };
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
+            GLTFLoader.prototype.dispose = function () {
+                if (this._disposed) {
+                    return;
+                }
+                this._disposed = true;
+                // Revoke object urls created during load
+                this._objectURLs.forEach(function (url) { return URL.revokeObjectURL(url); });
+                this._objectURLs.length = 0;
+                this._gltf = undefined;
+                this._babylonScene = undefined;
+                this._rootUrl = undefined;
+                this._defaultMaterial = undefined;
+                this._successCallback = undefined;
+                this._errorCallback = undefined;
+                this._renderReady = false;
+                this._renderReadyObservable.clear();
+                this._renderPendingCount = 0;
+                this._loaderPendingCount = 0;
+            };
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 this._loadAsync(meshesNames, scene, data, rootUrl, function () {
                     var meshes = [];
@@ -51269,23 +51317,30 @@ var BABYLON;
                         }
                     }
                     onSuccess(meshes, null, skeletons);
-                }, onError);
+                }, onProgress, onError);
             };
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
-                this._loadAsync(null, scene, data, rootUrl, onSuccess, onError);
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+                this._loadAsync(null, scene, data, rootUrl, onSuccess, onProgress, onError);
             };
-            GLTFLoader.prototype._loadAsync = function (nodeNames, scene, data, rootUrl, onSuccess, onError) {
-                this._clear();
+            GLTFLoader.prototype._loadAsync = function (nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 this._loadData(data);
                 this._babylonScene = scene;
                 this._rootUrl = rootUrl;
-                this._onSuccess = onSuccess;
-                this._onError = onError;
+                this._successCallback = onSuccess;
+                this._progressCallback = onProgress;
+                this._errorCallback = onError;
                 this.addPendingData(this);
                 this._loadScene(nodeNames);
                 this._loadAnimations();
                 this.removePendingData(this);
             };
+            GLTFLoader.prototype._onError = function (message) {
+                this.dispose();
+                this._errorCallback(message);
+            };
+            GLTFLoader.prototype._onProgress = function (event) {
+                this._progressCallback(event);
+            };
             GLTFLoader.prototype._onRenderReady = function () {
                 switch (this._parent.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
@@ -51303,23 +51358,13 @@ var BABYLON;
                         BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
                         break;
                 }
-                this._succeeded = (this._errors.length === 0);
-                if (this._succeeded) {
-                    this._showMeshes();
-                    this._startAnimations();
-                    this._onSuccess();
-                }
-                else {
-                    this._errors.forEach(function (error) { return BABYLON.Tools.Error(error); });
-                    this._errors = [];
-                    this._onError();
-                }
-                this._renderReadyObservable.notifyObservers(this._succeeded);
+                this._showMeshes();
+                this._startAnimations();
+                this._successCallback();
+                this._renderReadyObservable.notifyObservers(this);
             };
             GLTFLoader.prototype._onLoaderComplete = function () {
-                this._errors.forEach(function (error) { return BABYLON.Tools.Error(error); });
-                this._errors = [];
-                this._clear();
+                this.dispose();
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                 }
@@ -51376,29 +51421,6 @@ var BABYLON;
                     }
                 }
             };
-            GLTFLoader.prototype._clear = function () {
-                // Revoke object urls created during load
-                if (this._gltf && this._gltf.textures) {
-                    for (var i = 0; i < this._gltf.textures.length; i++) {
-                        var texture = this._gltf.textures[i];
-                        if (texture.blobURL) {
-                            URL.revokeObjectURL(texture.blobURL);
-                        }
-                    }
-                }
-                this._gltf = undefined;
-                this._errors = [];
-                this._babylonScene = undefined;
-                this._rootUrl = undefined;
-                this._defaultMaterial = undefined;
-                this._onSuccess = undefined;
-                this._onError = undefined;
-                this._succeeded = false;
-                this._renderReady = false;
-                this._renderReadyObservable.clear();
-                this._renderPendingCount = 0;
-                this._loaderPendingCount = 0;
-            };
             GLTFLoader.prototype._loadScene = function (nodeNames) {
                 var _this = this;
                 var scene = this._gltf.scenes[this._gltf.scene || 0];
@@ -51563,7 +51585,7 @@ var BABYLON;
                 var _this = this;
                 var attributes = primitive.attributes;
                 if (!attributes) {
-                    this._errors.push("Primitive has no attributes");
+                    this._onError("Primitive has no attributes");
                     return;
                 }
                 var vertexData = new BABYLON.VertexData();
@@ -51882,9 +51904,15 @@ var BABYLON;
                         buffer.loadedData = new Uint8Array(data);
                         buffer.loadedObservable.notifyObservers(buffer);
                         buffer.loadedObservable = null;
-                    }, null, null, true, function (request) {
-                        _this._errors.push("Failed to load file '" + buffer.uri + "': " + request.statusText + "(" + request.status + ")");
-                        _this.removePendingData(buffer);
+                    }, function (event) {
+                        if (!_this._disposed) {
+                            _this._onProgress(event);
+                        }
+                    }, this._babylonScene.database, true, function (request) {
+                        if (!_this._disposed) {
+                            _this._onError("Failed to load file '" + buffer.uri + "': " + request.status + " " + request.statusText);
+                            _this.removePendingData(buffer);
+                        }
                     });
                 }
             };
@@ -51893,7 +51921,7 @@ var BABYLON;
                 byteOffset += (bufferView.byteOffset || 0);
                 this._loadBufferAsync(bufferView.buffer, function (bufferData) {
                     if (byteOffset + byteLength > bufferData.byteLength) {
-                        _this._errors.push("Buffer access is out of range");
+                        _this._onError("Buffer access is out of range");
                         return;
                     }
                     var buffer = bufferData.buffer;
@@ -51919,7 +51947,7 @@ var BABYLON;
                             bufferViewData = new Float32Array(buffer, byteOffset, byteLength);
                             break;
                         default:
-                            _this._errors.push("Invalid component type (" + componentType + ")");
+                            _this._onError("Invalid component type (" + componentType + ")");
                             return;
                     }
                     onSuccess(bufferViewData);
@@ -51928,9 +51956,23 @@ var BABYLON;
             GLTFLoader.prototype._loadAccessorAsync = function (accessor, onSuccess) {
                 var bufferView = this._gltf.bufferViews[accessor.bufferView];
                 var byteOffset = accessor.byteOffset || 0;
-                var byteLength = accessor.count * GLTF2.GLTFUtils.GetByteStrideFromType(accessor);
+                var byteLength = accessor.count * this._getByteStrideFromType(accessor);
                 this._loadBufferViewAsync(bufferView, byteOffset, byteLength, accessor.componentType, onSuccess);
             };
+            GLTFLoader.prototype._getByteStrideFromType = function (accessor) {
+                switch (accessor.type) {
+                    case "SCALAR": return 1;
+                    case "VEC2": return 2;
+                    case "VEC3": return 3;
+                    case "VEC4": return 4;
+                    case "MAT2": return 4;
+                    case "MAT3": return 9;
+                    case "MAT4": return 16;
+                    default:
+                        this._onError("Invalid accessor type (" + accessor.type + ")");
+                        return 0;
+                }
+            };
             GLTFLoader.prototype.addPendingData = function (data) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
@@ -52079,32 +52121,41 @@ var BABYLON;
                     return babylonTexture;
                 }
                 var source = this._gltf.images[texture.source];
-                var url;
+                var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
+                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
+                var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
+                this.addPendingData(texture);
+                babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
+                    if (!_this._disposed) {
+                        _this.removePendingData(texture);
+                    }
+                }, function () {
+                    if (!_this._disposed) {
+                        _this._onError("Failed to load texture '" + source.uri + "'");
+                        _this.removePendingData(texture);
+                    }
+                });
+                var setTextureData = function (data) {
+                    var url = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
+                    _this._objectURLs.push(url);
+                    babylonTexture.updateURL(url);
+                };
                 if (!source.uri) {
                     var bufferView = this._gltf.bufferViews[source.bufferView];
-                    this._loadBufferViewAsync(bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE, function (data) {
-                        texture.blobURL = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
-                        texture.babylonTextures[texCoord].updateURL(texture.blobURL);
-                    });
+                    this._loadBufferViewAsync(bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE, setTextureData);
                 }
                 else if (GLTF2.GLTFUtils.IsBase64(source.uri)) {
-                    var data = new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri));
-                    texture.blobURL = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
-                    url = texture.blobURL;
+                    setTextureData(new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri)));
                 }
                 else {
-                    url = this._rootUrl + source.uri;
+                    BABYLON.Tools.LoadFile(this._rootUrl + source.uri, setTextureData, function (event) {
+                        if (!_this._disposed) {
+                            _this._onProgress(event);
+                        }
+                    }, this._babylonScene.database, true, function (request) {
+                        _this._onError("Failed to load file '" + source.uri + "': " + request.status + " " + request.statusText);
+                    });
                 }
-                var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
-                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
-                var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
-                this.addPendingData(texture);
-                var babylonTexture = new BABYLON.Texture(url, this._babylonScene, noMipMaps, false, samplingMode, function () {
-                    _this.removePendingData(texture);
-                }, function () {
-                    _this._errors.push("Failed to load texture '" + source.uri + "'");
-                    _this.removePendingData(texture);
-                });
                 babylonTexture.coordinatesIndex = texCoord;
                 babylonTexture.wrapU = GLTF2.GLTFUtils.GetTextureWrapMode(sampler.wrapS);
                 babylonTexture.wrapV = GLTF2.GLTFUtils.GetTextureWrapMode(sampler.wrapT);
@@ -52175,23 +52226,6 @@ var BABYLON;
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
             };
-            /**
-             * Returns the byte stride giving an accessor
-             * @param accessor: the GLTF accessor objet
-             */
-            GLTFUtils.GetByteStrideFromType = function (accessor) {
-                // Needs this function since "byteStride" isn't requiered in glTF format
-                var type = accessor.type;
-                switch (type) {
-                    case "VEC2": return 2;
-                    case "VEC3": return 3;
-                    case "VEC4": return 4;
-                    case "MAT2": return 4;
-                    case "MAT3": return 9;
-                    case "MAT4": return 16;
-                    default: return 1;
-                }
-            };
             GLTFUtils.GetTextureSamplingMode = function (magFilter, minFilter) {
                 // Set defaults if undefined
                 magFilter = magFilter === undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
@@ -52330,12 +52364,9 @@ var BABYLON;
                             loader.removeLoaderPendingData(material);
                             return;
                         }
-                        // Load the next LOD once the loader has succeeded.
-                        loader.executeWhenRenderReady(function (succeeded) {
-                            if (!succeeded) {
-                                return;
-                            }
-                            // Load the next LOD when all of the textures are loaded.
+                        // Load the next LOD when the loader is ready to render and
+                        // all active material textures of the current LOD are loaded.
+                        loader.executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
                             });

+ 158 - 158
dist/preview release/customConfigurations/minimalGLTFViewer/babylon.module.d.ts

@@ -4163,6 +4163,134 @@ declare module BABYLON {
     }
 }
 
+declare module BABYLON.Debug {
+    class AxesViewer {
+        private _xline;
+        private _yline;
+        private _zline;
+        private _xmesh;
+        private _ymesh;
+        private _zmesh;
+        scene: Scene;
+        scaleLines: number;
+        constructor(scene: Scene, scaleLines?: number);
+        update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    class BoneAxesViewer extends Debug.AxesViewer {
+        mesh: Mesh;
+        bone: Bone;
+        pos: Vector3;
+        xaxis: Vector3;
+        yaxis: Vector3;
+        zaxis: Vector3;
+        constructor(scene: Scene, bone: Bone, mesh: Mesh, scaleLines?: number);
+        update(): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class DebugLayer {
+        private _scene;
+        static InspectorURL: string;
+        private _inspector;
+        constructor(scene: Scene);
+        /** Creates the inspector window. */
+        private _createInspector(config?);
+        isVisible(): boolean;
+        hide(): void;
+        show(config?: {
+            popup?: boolean;
+            initialTab?: number;
+            parentElement?: HTMLElement;
+            newColors?: {
+                backgroundColor?: string;
+                backgroundColorLighter?: string;
+                backgroundColorLighter2?: string;
+                backgroundColorLighter3?: string;
+                color?: string;
+                colorTop?: string;
+                colorBot?: string;
+            };
+        }): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    class PhysicsViewer {
+        protected _impostors: Array<PhysicsImpostor>;
+        protected _meshes: Array<AbstractMesh>;
+        protected _scene: Scene;
+        protected _numMeshes: number;
+        protected _physicsEnginePlugin: IPhysicsEnginePlugin;
+        private _renderFunction;
+        private _debugBoxMesh;
+        private _debugSphereMesh;
+        private _debugMaterial;
+        constructor(scene: Scene);
+        protected _updateDebugMeshes(): void;
+        showImpostor(impostor: PhysicsImpostor): void;
+        hideImpostor(impostor: PhysicsImpostor): void;
+        private _getDebugMaterial(scene);
+        private _getDebugBoxMesh(scene);
+        private _getDebugSphereMesh(scene);
+        private _getDebugMesh(impostor, scene);
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
+    class RayHelper {
+        ray: Ray;
+        private _renderPoints;
+        private _renderLine;
+        private _renderFunction;
+        private _scene;
+        private _updateToMeshFunction;
+        private _attachedToMesh;
+        private _meshSpaceDirection;
+        private _meshSpaceOrigin;
+        static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper;
+        constructor(ray: Ray);
+        show(scene: Scene, color: Color3): void;
+        hide(): void;
+        private _render();
+        attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void;
+        detachFromMesh(): void;
+        private _updateToMesh();
+        dispose(): void;
+    }
+}
+
+declare module BABYLON.Debug {
+    /**
+    * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
+    */
+    class SkeletonViewer {
+        skeleton: Skeleton;
+        mesh: AbstractMesh;
+        autoUpdateBonesMatrices: boolean;
+        renderingGroupId: number;
+        color: Color3;
+        private _scene;
+        private _debugLines;
+        private _debugMesh;
+        private _isEnabled;
+        private _renderFunction;
+        constructor(skeleton: Skeleton, mesh: AbstractMesh, scene: Scene, autoUpdateBonesMatrices?: boolean, renderingGroupId?: number);
+        isEnabled: boolean;
+        private _getBonePosition(position, bone, meshMat, x?, y?, z?);
+        private _getLinesForBonesWithLength(bones, meshMat);
+        private _getLinesForBonesNoLength(bones, meshMat);
+        update(): void;
+        dispose(): void;
+    }
+}
+
 declare module BABYLON {
     /**
      * Highlight layer options. This helps customizing the behaviour
@@ -4464,134 +4592,6 @@ declare module BABYLON {
     }
 }
 
-declare module BABYLON.Debug {
-    class AxesViewer {
-        private _xline;
-        private _yline;
-        private _zline;
-        private _xmesh;
-        private _ymesh;
-        private _zmesh;
-        scene: Scene;
-        scaleLines: number;
-        constructor(scene: Scene, scaleLines?: number);
-        update(position: Vector3, xaxis: Vector3, yaxis: Vector3, zaxis: Vector3): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    class BoneAxesViewer extends Debug.AxesViewer {
-        mesh: Mesh;
-        bone: Bone;
-        pos: Vector3;
-        xaxis: Vector3;
-        yaxis: Vector3;
-        zaxis: Vector3;
-        constructor(scene: Scene, bone: Bone, mesh: Mesh, scaleLines?: number);
-        update(): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class DebugLayer {
-        private _scene;
-        static InspectorURL: string;
-        private _inspector;
-        constructor(scene: Scene);
-        /** Creates the inspector window. */
-        private _createInspector(config?);
-        isVisible(): boolean;
-        hide(): void;
-        show(config?: {
-            popup?: boolean;
-            initialTab?: number;
-            parentElement?: HTMLElement;
-            newColors?: {
-                backgroundColor?: string;
-                backgroundColorLighter?: string;
-                backgroundColorLighter2?: string;
-                backgroundColorLighter3?: string;
-                color?: string;
-                colorTop?: string;
-                colorBot?: string;
-            };
-        }): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    class PhysicsViewer {
-        protected _impostors: Array<PhysicsImpostor>;
-        protected _meshes: Array<AbstractMesh>;
-        protected _scene: Scene;
-        protected _numMeshes: number;
-        protected _physicsEnginePlugin: IPhysicsEnginePlugin;
-        private _renderFunction;
-        private _debugBoxMesh;
-        private _debugSphereMesh;
-        private _debugMaterial;
-        constructor(scene: Scene);
-        protected _updateDebugMeshes(): void;
-        showImpostor(impostor: PhysicsImpostor): void;
-        hideImpostor(impostor: PhysicsImpostor): void;
-        private _getDebugMaterial(scene);
-        private _getDebugBoxMesh(scene);
-        private _getDebugSphereMesh(scene);
-        private _getDebugMesh(impostor, scene);
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
-    class RayHelper {
-        ray: Ray;
-        private _renderPoints;
-        private _renderLine;
-        private _renderFunction;
-        private _scene;
-        private _updateToMeshFunction;
-        private _attachedToMesh;
-        private _meshSpaceDirection;
-        private _meshSpaceOrigin;
-        static CreateAndShow(ray: Ray, scene: Scene, color: Color3): RayHelper;
-        constructor(ray: Ray);
-        show(scene: Scene, color: Color3): void;
-        hide(): void;
-        private _render();
-        attachToMesh(mesh: AbstractMesh, meshSpaceDirection?: Vector3, meshSpaceOrigin?: Vector3, length?: number): void;
-        detachFromMesh(): void;
-        private _updateToMesh();
-        dispose(): void;
-    }
-}
-
-declare module BABYLON.Debug {
-    /**
-    * Demo available here: http://www.babylonjs-playground.com/#1BZJVJ#8
-    */
-    class SkeletonViewer {
-        skeleton: Skeleton;
-        mesh: AbstractMesh;
-        autoUpdateBonesMatrices: boolean;
-        renderingGroupId: number;
-        color: Color3;
-        private _scene;
-        private _debugLines;
-        private _debugMesh;
-        private _isEnabled;
-        private _renderFunction;
-        constructor(skeleton: Skeleton, mesh: AbstractMesh, scene: Scene, autoUpdateBonesMatrices?: boolean, renderingGroupId?: number);
-        isEnabled: boolean;
-        private _getBonePosition(position, bone, meshMat, x?, y?, z?);
-        private _getLinesForBonesWithLength(bones, meshMat);
-        private _getLinesForBonesNoLength(bones, meshMat);
-        update(): void;
-        dispose(): void;
-    }
-}
-
 declare module BABYLON {
     class DirectionalLight extends ShadowLight {
         private _shadowFrustumSize;
@@ -12979,36 +12979,6 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
-    class ReflectionProbe {
-        name: string;
-        private _scene;
-        private _renderTargetTexture;
-        private _projectionMatrix;
-        private _viewMatrix;
-        private _target;
-        private _add;
-        private _attachedMesh;
-        invertYAxis: boolean;
-        position: Vector3;
-        constructor(name: string, size: number, scene: Scene, generateMipMaps?: boolean);
-        samples: number;
-        refreshRate: number;
-        getScene(): Scene;
-        readonly cubeTexture: RenderTargetTexture;
-        readonly renderList: AbstractMesh[];
-        attachToMesh(mesh: AbstractMesh): void;
-        /**
-         * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
-         *
-         * @param renderingGroupId The rendering group id corresponding to its index
-         * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
-         */
-        setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void;
-        dispose(): void;
-    }
-}
-
-declare module BABYLON {
     class AnaglyphPostProcess extends PostProcess {
         private _passedProcess;
         constructor(name: string, options: number | PostProcessOptions, rigCameras: Camera[], samplingMode?: number, engine?: Engine, reusable?: boolean);
@@ -13530,6 +13500,36 @@ declare module BABYLON {
 }
 
 declare module BABYLON {
+    class ReflectionProbe {
+        name: string;
+        private _scene;
+        private _renderTargetTexture;
+        private _projectionMatrix;
+        private _viewMatrix;
+        private _target;
+        private _add;
+        private _attachedMesh;
+        invertYAxis: boolean;
+        position: Vector3;
+        constructor(name: string, size: number, scene: Scene, generateMipMaps?: boolean);
+        samples: number;
+        refreshRate: number;
+        getScene(): Scene;
+        readonly cubeTexture: RenderTargetTexture;
+        readonly renderList: AbstractMesh[];
+        attachToMesh(mesh: AbstractMesh): void;
+        /**
+         * Specifies whether or not the stencil and depth buffer are cleared between two rendering groups.
+         *
+         * @param renderingGroupId The rendering group id corresponding to its index
+         * @param autoClearDepthStencil Automatically clears depth and stencil between groups if true.
+         */
+        setRenderingAutoClearDepthStencil(renderingGroupId: number, autoClearDepthStencil: boolean): void;
+        dispose(): void;
+    }
+}
+
+declare module BABYLON {
     class BoundingBoxRenderer {
         frontColor: Color3;
         backColor: Color3;

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

@@ -3153,6 +3153,9 @@ var BABYLON;
                 if (!this.isHitTestVisible || !this.isVisible) {
                     return false;
                 }
+                if (!_super.prototype.contains.call(this, x, y)) {
+                    return false;
+                }
                 this._processObservables(type, x, y);
                 return true;
             };

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


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

@@ -10,8 +10,8 @@ declare module BABYLON {
         bin: ArrayBufferView;
     }
     interface IGLTFLoader {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
     class GLTFFileLoader implements ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
@@ -23,14 +23,14 @@ declare module BABYLON {
         onMaterialLoaded: (material: Material) => void;
         onComplete: () => void;
         extensions: ISceneLoaderPluginExtensions;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => 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;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
-        private static _parse(data);
-        private _getLoader(loaderData);
-        private static _parseBinary(data);
-        private static _parseV1(binaryReader);
-        private static _parseV2(binaryReader);
+        private static _parse(data, onError);
+        private _getLoader(loaderData, onError);
+        private static _parseBinary(data, onError);
+        private static _parseV1(binaryReader, onError);
+        private static _parseV2(binaryReader, onError);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(view);
@@ -365,11 +365,11 @@ declare module BABYLON.GLTF1 {
     */
     class GLTFLoaderBase {
         static CreateRuntime(parsedData: any, scene: Scene, rootUrl: string): IGLTFRuntime;
-        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void, onProgress?: () => void): void;
-        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): void;
-        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: () => void): void;
-        static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: () => void): void;
-        static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): void;
+        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): void;
+        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): void;
+        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
+        static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): void;
+        static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): void;
     }
     /**
     * glTF V1 Loader
@@ -379,10 +379,10 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void, onProgress?: () => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadShadersAsync(gltfRuntime, onload);
-        private _loadBuffersAsync(gltfRuntime, onload, onProgress?);
+        private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
     }
 }
@@ -467,43 +467,43 @@ declare module BABYLON.GLTF1 {
         * Defines an override for loading the runtime
         * Return true to stop further extensions from loading the runtime
         */
-        loadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): boolean;
+        loadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: (message: string) => void): boolean;
         /**
          * Defines an onverride for creating gltf runtime
          * Return true to stop further extensions from creating the runtime
          */
-        loadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: () => void): boolean;
+        loadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: (message: string) => void): boolean;
         /**
         * Defines an override for loading buffers
         * Return true to stop further extensions from loading this buffer
         */
-        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void, onProgress?: () => void): boolean;
+        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): boolean;
         /**
         * Defines an override for loading texture buffers
         * Return true to stop further extensions from loading this texture data
         */
-        loadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): boolean;
+        loadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): boolean;
         /**
         * Defines an override for creating textures
         * Return true to stop further extensions from loading this texture
         */
-        createTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: () => void): boolean;
+        createTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: (message: string) => void): boolean;
         /**
         * Defines an override for loading shader strings
         * Return true to stop further extensions from loading this shader data
         */
-        loadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: () => void): boolean;
+        loadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): boolean;
         /**
         * Defines an override for loading materials
         * Return true to stop further extensions from loading this material
         */
-        loadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): boolean;
-        static LoadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): void;
-        static LoadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void;
-        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (bufferView: ArrayBufferView) => void, onError: () => void, onProgress?: () => void): void;
-        static LoadTextureAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (texture: Texture) => void, onError: () => void): void;
-        static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderData: string) => void, onError: () => void): void;
-        static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): void;
+        loadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): boolean;
+        static LoadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: (message: string) => void): void;
+        static LoadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: (message: string) => void): void;
+        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (bufferView: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): void;
+        static LoadTextureAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
+        static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderData: string) => void, onError: (message: string) => void): void;
+        static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): void;
         private static LoadTextureBufferAsync(gltfRuntime, id, onSuccess, onError);
         private static CreateTextureAsync(gltfRuntime, id, buffer, onSuccess, onError);
         private static ApplyExtensions(func, defaultFunc);
@@ -515,10 +515,10 @@ declare module BABYLON.GLTF1 {
     class GLTFBinaryExtension extends GLTFLoaderExtension {
         private _bin;
         constructor();
-        loadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): boolean;
-        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): boolean;
-        loadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): boolean;
-        loadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: () => void): boolean;
+        loadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: (message: string) => void): boolean;
+        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): boolean;
+        loadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): boolean;
+        loadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): boolean;
     }
 }
 
@@ -526,8 +526,8 @@ declare module BABYLON.GLTF1 {
 declare module BABYLON.GLTF1 {
     class GLTFMaterialsCommonExtension extends GLTFLoaderExtension {
         constructor();
-        loadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: () => void): boolean;
-        loadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): boolean;
+        loadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: (message: string) => void): boolean;
+        loadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): boolean;
         private _loadTexture(gltfRuntime, id, material, propertyPath, onError);
     }
 }

+ 76 - 54
dist/preview release/loaders/babylon.glTF1FileLoader.js

@@ -20,87 +20,101 @@ var BABYLON;
                 ".glb": { isBinary: true }
             };
         }
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
-            var loaderData = GLTFFileLoader._parse(data);
-            var loader = this._getLoader(loaderData);
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
+            var loaderData = GLTFFileLoader._parse(data, onError);
+            if (!loaderData) {
+                return;
+            }
+            var loader = this._getLoader(loaderData, onError);
             if (!loader) {
-                onError();
                 return;
             }
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
+            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
-            var loaderData = GLTFFileLoader._parse(data);
-            var loader = this._getLoader(loaderData);
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+            var loaderData = GLTFFileLoader._parse(data, onError);
+            if (!loaderData) {
+                return;
+            }
+            var loader = this._getLoader(loaderData, onError);
             if (!loader) {
-                onError();
                 return;
             }
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onError);
+            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
         };
-        GLTFFileLoader._parse = function (data) {
+        GLTFFileLoader._parse = function (data, onError) {
             if (data instanceof ArrayBuffer) {
-                return GLTFFileLoader._parseBinary(data);
+                return GLTFFileLoader._parseBinary(data, onError);
+            }
+            try {
+                return {
+                    json: JSON.parse(data),
+                    bin: null
+                };
+            }
+            catch (e) {
+                onError(e.message);
+                return null;
             }
-            return {
-                json: JSON.parse(data),
-                bin: null
-            };
         };
-        GLTFFileLoader.prototype._getLoader = function (loaderData) {
+        GLTFFileLoader.prototype._getLoader = function (loaderData, onError) {
             var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
             var version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
-                BABYLON.Tools.Error("Invalid version");
+                onError("Invalid version: " + asset.version);
                 return null;
             }
-            var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
-            if (minVersion) {
+            if (asset.minVersion !== undefined) {
+                var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
+                if (!minVersion) {
+                    onError("Invalid minimum version: " + asset.minVersion);
+                    return null;
+                }
                 if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
-                    BABYLON.Tools.Error("Incompatible version");
+                    onError("Incompatible minimum version: " + asset.minVersion);
                     return null;
                 }
             }
-            var createLoader = {
+            var createLoaders = {
                 1: GLTFFileLoader.CreateGLTFLoaderV1,
                 2: GLTFFileLoader.CreateGLTFLoaderV2
             };
-            var loader = createLoader[version.major](this);
-            if (loader === null) {
-                BABYLON.Tools.Error("Unsupported version");
+            var createLoader = createLoaders[version.major];
+            if (!createLoader) {
+                onError("Unsupported version: " + asset.version);
                 return null;
             }
-            return loader;
+            return createLoader(this);
         };
-        GLTFFileLoader._parseBinary = function (data) {
+        GLTFFileLoader._parseBinary = function (data, onError) {
             var Binary = {
                 Magic: 0x46546C67
             };
             var binaryReader = new BinaryReader(data);
             var magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
-                BABYLON.Tools.Error("Unexpected magic: " + magic);
+                onError("Unexpected magic: " + magic);
                 return null;
             }
             var version = binaryReader.readUint32();
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader);
-                case 2: return GLTFFileLoader._parseV2(binaryReader);
+                case 1: return GLTFFileLoader._parseV1(binaryReader, onError);
+                case 2: return GLTFFileLoader._parseV2(binaryReader, onError);
             }
-            BABYLON.Tools.Error("Unsupported version: " + version);
+            onError("Unsupported version: " + version);
             return null;
         };
-        GLTFFileLoader._parseV1 = function (binaryReader) {
+        GLTFFileLoader._parseV1 = function (binaryReader, onError) {
             var ContentFormat = {
                 JSON: 0
             };
             var length = binaryReader.readUint32();
             if (length != binaryReader.getLength()) {
-                BABYLON.Tools.Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
             var contentLength = binaryReader.readUint32();
@@ -111,7 +125,7 @@ var BABYLON;
                     content = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(contentLength)));
                     break;
                 default:
-                    BABYLON.Tools.Error("Unexpected content format: " + contentFormat);
+                    onError("Unexpected content format: " + contentFormat);
                     return null;
             }
             var bytesRemaining = binaryReader.getLength() - binaryReader.getPosition();
@@ -121,21 +135,21 @@ var BABYLON;
                 bin: body
             };
         };
-        GLTFFileLoader._parseV2 = function (binaryReader) {
+        GLTFFileLoader._parseV2 = function (binaryReader, onError) {
             var ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
             };
             var length = binaryReader.readUint32();
             if (length !== binaryReader.getLength()) {
-                BABYLON.Tools.Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
             // JSON chunk
             var chunkLength = binaryReader.readUint32();
             var chunkFormat = binaryReader.readUint32();
             if (chunkFormat !== ChunkFormat.JSON) {
-                BABYLON.Tools.Error("First chunk format is not JSON");
+                onError("First chunk format is not JSON");
                 return null;
             }
             var json = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(chunkLength)));
@@ -146,7 +160,7 @@ var BABYLON;
                 chunkFormat = binaryReader.readUint32();
                 switch (chunkFormat) {
                     case ChunkFormat.JSON:
-                        BABYLON.Tools.Error("Unexpected JSON chunk");
+                        onError("Unexpected JSON chunk");
                         return null;
                     case ChunkFormat.BIN:
                         bin = binaryReader.readUint8Array(chunkLength);
@@ -167,17 +181,20 @@ var BABYLON;
                 return null;
             }
             var parts = version.split(".");
-            if (parts.length === 0) {
+            if (parts.length != 2) {
+                return null;
+            }
+            var major = +parts[0];
+            if (isNaN(major)) {
                 return null;
             }
-            var major = parseInt(parts[0]);
-            if (major > 1 && parts.length != 2) {
+            var minor = +parts[1];
+            if (isNaN(minor)) {
                 return null;
             }
-            var minor = parseInt(parts[1]);
             return {
                 major: major,
-                minor: parseInt(parts[0])
+                minor: minor
             };
         };
         GLTFFileLoader._compareVersion = function (a, b) {
@@ -1259,9 +1276,8 @@ var BABYLON;
         */
         var onShaderCompileError = function (program, shaderMaterial, onError) {
             return function (effect, error) {
-                BABYLON.Tools.Error("Cannot compile program named " + program.name + ". Error: " + error + ". Default material will be applied");
                 shaderMaterial.dispose(true);
-                onError();
+                onError("Cannot compile program named " + program.name + ". Error: " + error + ". Default material will be applied");
             };
         };
         /**
@@ -1409,13 +1425,15 @@ var BABYLON;
                     setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(buffer.uri))); });
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, null, true, onError);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, null, true, function (request) {
+                        onError(request.status + " " + request.statusText);
+                    });
                 }
             };
             GLTFLoaderBase.LoadTextureBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
                 var texture = gltfRuntime.textures[id];
                 if (!texture || !texture.source) {
-                    onError();
+                    onError(null);
                     return;
                 }
                 if (texture.babylonTexture) {
@@ -1427,7 +1445,9 @@ var BABYLON;
                     setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(source.uri))); });
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, null, null, true, onError);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, null, null, true, function (request) {
+                        onError(request.status + " " + request.statusText);
+                    });
                 }
             };
             GLTFLoaderBase.CreateTextureAsync = function (gltfRuntime, id, buffer, onSuccess, onError) {
@@ -1459,7 +1479,9 @@ var BABYLON;
                     onSuccess(shaderString);
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, null, null, false, onError);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, null, null, false, function (request) {
+                        onError(request.status + " " + request.statusText);
+                    });
                 }
             };
             GLTFLoaderBase.LoadMaterialAsync = function (gltfRuntime, id, onSuccess, onError) {
@@ -1605,7 +1627,7 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError, onProgress) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 var gltfRuntime = GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1656,7 +1678,7 @@ var BABYLON;
                 }, onError);
                 return true;
             };
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1710,7 +1732,7 @@ var BABYLON;
                 }
             };
             ;
-            GLTFLoader.prototype._loadBuffersAsync = function (gltfRuntime, onload, onProgress) {
+            GLTFLoader.prototype._loadBuffersAsync = function (gltfRuntime, onLoad, onProgress) {
                 var hasBuffers = false;
                 var processBuffer = function (buf, buffer) {
                     GLTF1.GLTFLoaderExtension.LoadBufferAsync(gltfRuntime, buf, function (bufferView) {
@@ -1722,7 +1744,7 @@ var BABYLON;
                             gltfRuntime.loadedBufferViews[buf] = bufferView;
                         }
                         if (gltfRuntime.loadedBufferCount === gltfRuntime.buffersCount) {
-                            onload();
+                            onLoad();
                         }
                     }, function () {
                         BABYLON.Tools.Error("Error when loading buffer named " + buf + " located at " + buffer.uri);
@@ -1739,7 +1761,7 @@ var BABYLON;
                     }
                 }
                 if (!hasBuffers) {
-                    onload();
+                    onLoad();
                 }
             };
             GLTFLoader.prototype._createNodes = function (gltfRuntime) {

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


+ 23 - 25
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -10,8 +10,8 @@ declare module BABYLON {
         bin: ArrayBufferView;
     }
     interface IGLTFLoader {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
     class GLTFFileLoader implements ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
@@ -23,14 +23,14 @@ declare module BABYLON {
         onMaterialLoaded: (material: Material) => void;
         onComplete: () => void;
         extensions: ISceneLoaderPluginExtensions;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => 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;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
-        private static _parse(data);
-        private _getLoader(loaderData);
-        private static _parseBinary(data);
-        private static _parseV1(binaryReader);
-        private static _parseV2(binaryReader);
+        private static _parse(data, onError);
+        private _getLoader(loaderData, onError);
+        private static _parseBinary(data, onError);
+        private static _parseV1(binaryReader, onError);
+        private static _parseV2(binaryReader, onError);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(view);
@@ -247,7 +247,6 @@ declare module BABYLON.GLTF2 {
         sampler?: number;
         source: number;
         babylonTextures?: Texture[];
-        blobURL?: string;
     }
     interface IGLTFTextureInfo {
         index: number;
@@ -277,17 +276,18 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    class GLTFLoader implements IGLTFLoader {
+    class GLTFLoader implements IGLTFLoader, IDisposable {
         private _parent;
         private _gltf;
-        private _errors;
         private _babylonScene;
         private _rootUrl;
         private _defaultMaterial;
-        private _onSuccess;
-        private _onError;
-        private _succeeded;
+        private _successCallback;
+        private _progressCallback;
+        private _errorCallback;
         private _renderReady;
+        private _disposed;
+        private _objectURLs;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
@@ -297,18 +297,20 @@ declare module BABYLON.GLTF2 {
         static RegisterExtension(extension: GLTFLoaderExtension): void;
         readonly gltf: IGLTF;
         readonly babylonScene: Scene;
-        executeWhenRenderReady(func: (succeeded: boolean) => void): void;
+        executeWhenRenderReady(func: () => void): void;
         constructor(parent: GLTFFileLoader);
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onError);
+        dispose(): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
+        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        private _onError(message);
+        private _onProgress(event);
         private _onRenderReady();
         private _onLoaderComplete();
         private _loadData(data);
         private _addRightHandToLeftHandRootTransform();
         private _showMeshes();
         private _startAnimations();
-        private _clear();
         private _loadScene(nodeNames);
         private _loadSkin(node);
         private _updateBone(node, parentNode, skin, inverseBindMatrixData);
@@ -327,6 +329,7 @@ declare module BABYLON.GLTF2 {
         private _loadBufferAsync(index, onSuccess);
         private _loadBufferViewAsync(bufferView, byteOffset, byteLength, componentType, onSuccess);
         private _loadAccessorAsync(accessor, onSuccess);
+        private _getByteStrideFromType(accessor);
         addPendingData(data: any): void;
         removePendingData(data: any): void;
         addLoaderPendingData(data: any): void;
@@ -359,11 +362,6 @@ declare module BABYLON.GLTF2 {
         static DecodeBase64(uri: string): ArrayBuffer;
         static ForEach(view: Uint16Array | Uint32Array | Float32Array, func: (nvalue: number, index: number) => void): void;
         static GetTextureWrapMode(mode: ETextureWrapMode): number;
-        /**
-         * Returns the byte stride giving an accessor
-         * @param accessor: the GLTF accessor objet
-         */
-        static GetByteStrideFromType(accessor: IGLTFAccessor): number;
         static GetTextureSamplingMode(magFilter: ETextureMagFilter, minFilter: ETextureMinFilter): number;
         /**
          * Decodes a buffer view into a string

+ 165 - 139
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -20,87 +20,101 @@ var BABYLON;
                 ".glb": { isBinary: true }
             };
         }
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
-            var loaderData = GLTFFileLoader._parse(data);
-            var loader = this._getLoader(loaderData);
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
+            var loaderData = GLTFFileLoader._parse(data, onError);
+            if (!loaderData) {
+                return;
+            }
+            var loader = this._getLoader(loaderData, onError);
             if (!loader) {
-                onError();
                 return;
             }
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
+            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
-            var loaderData = GLTFFileLoader._parse(data);
-            var loader = this._getLoader(loaderData);
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+            var loaderData = GLTFFileLoader._parse(data, onError);
+            if (!loaderData) {
+                return;
+            }
+            var loader = this._getLoader(loaderData, onError);
             if (!loader) {
-                onError();
                 return;
             }
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onError);
+            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
         };
-        GLTFFileLoader._parse = function (data) {
+        GLTFFileLoader._parse = function (data, onError) {
             if (data instanceof ArrayBuffer) {
-                return GLTFFileLoader._parseBinary(data);
+                return GLTFFileLoader._parseBinary(data, onError);
+            }
+            try {
+                return {
+                    json: JSON.parse(data),
+                    bin: null
+                };
+            }
+            catch (e) {
+                onError(e.message);
+                return null;
             }
-            return {
-                json: JSON.parse(data),
-                bin: null
-            };
         };
-        GLTFFileLoader.prototype._getLoader = function (loaderData) {
+        GLTFFileLoader.prototype._getLoader = function (loaderData, onError) {
             var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
             var version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
-                BABYLON.Tools.Error("Invalid version");
+                onError("Invalid version: " + asset.version);
                 return null;
             }
-            var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
-            if (minVersion) {
+            if (asset.minVersion !== undefined) {
+                var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
+                if (!minVersion) {
+                    onError("Invalid minimum version: " + asset.minVersion);
+                    return null;
+                }
                 if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
-                    BABYLON.Tools.Error("Incompatible version");
+                    onError("Incompatible minimum version: " + asset.minVersion);
                     return null;
                 }
             }
-            var createLoader = {
+            var createLoaders = {
                 1: GLTFFileLoader.CreateGLTFLoaderV1,
                 2: GLTFFileLoader.CreateGLTFLoaderV2
             };
-            var loader = createLoader[version.major](this);
-            if (loader === null) {
-                BABYLON.Tools.Error("Unsupported version");
+            var createLoader = createLoaders[version.major];
+            if (!createLoader) {
+                onError("Unsupported version: " + asset.version);
                 return null;
             }
-            return loader;
+            return createLoader(this);
         };
-        GLTFFileLoader._parseBinary = function (data) {
+        GLTFFileLoader._parseBinary = function (data, onError) {
             var Binary = {
                 Magic: 0x46546C67
             };
             var binaryReader = new BinaryReader(data);
             var magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
-                BABYLON.Tools.Error("Unexpected magic: " + magic);
+                onError("Unexpected magic: " + magic);
                 return null;
             }
             var version = binaryReader.readUint32();
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader);
-                case 2: return GLTFFileLoader._parseV2(binaryReader);
+                case 1: return GLTFFileLoader._parseV1(binaryReader, onError);
+                case 2: return GLTFFileLoader._parseV2(binaryReader, onError);
             }
-            BABYLON.Tools.Error("Unsupported version: " + version);
+            onError("Unsupported version: " + version);
             return null;
         };
-        GLTFFileLoader._parseV1 = function (binaryReader) {
+        GLTFFileLoader._parseV1 = function (binaryReader, onError) {
             var ContentFormat = {
                 JSON: 0
             };
             var length = binaryReader.readUint32();
             if (length != binaryReader.getLength()) {
-                BABYLON.Tools.Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
             var contentLength = binaryReader.readUint32();
@@ -111,7 +125,7 @@ var BABYLON;
                     content = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(contentLength)));
                     break;
                 default:
-                    BABYLON.Tools.Error("Unexpected content format: " + contentFormat);
+                    onError("Unexpected content format: " + contentFormat);
                     return null;
             }
             var bytesRemaining = binaryReader.getLength() - binaryReader.getPosition();
@@ -121,21 +135,21 @@ var BABYLON;
                 bin: body
             };
         };
-        GLTFFileLoader._parseV2 = function (binaryReader) {
+        GLTFFileLoader._parseV2 = function (binaryReader, onError) {
             var ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
             };
             var length = binaryReader.readUint32();
             if (length !== binaryReader.getLength()) {
-                BABYLON.Tools.Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
             // JSON chunk
             var chunkLength = binaryReader.readUint32();
             var chunkFormat = binaryReader.readUint32();
             if (chunkFormat !== ChunkFormat.JSON) {
-                BABYLON.Tools.Error("First chunk format is not JSON");
+                onError("First chunk format is not JSON");
                 return null;
             }
             var json = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(chunkLength)));
@@ -146,7 +160,7 @@ var BABYLON;
                 chunkFormat = binaryReader.readUint32();
                 switch (chunkFormat) {
                     case ChunkFormat.JSON:
-                        BABYLON.Tools.Error("Unexpected JSON chunk");
+                        onError("Unexpected JSON chunk");
                         return null;
                     case ChunkFormat.BIN:
                         bin = binaryReader.readUint8Array(chunkLength);
@@ -167,17 +181,20 @@ var BABYLON;
                 return null;
             }
             var parts = version.split(".");
-            if (parts.length === 0) {
+            if (parts.length != 2) {
+                return null;
+            }
+            var major = +parts[0];
+            if (isNaN(major)) {
                 return null;
             }
-            var major = parseInt(parts[0]);
-            if (major > 1 && parts.length != 2) {
+            var minor = +parts[1];
+            if (isNaN(minor)) {
                 return null;
             }
-            var minor = parseInt(parts[1]);
             return {
                 major: major,
-                minor: parseInt(parts[0])
+                minor: minor
             };
         };
         GLTFFileLoader._compareVersion = function (a, b) {
@@ -298,8 +315,15 @@ var BABYLON;
     (function (GLTF2) {
         var GLTFLoader = (function () {
             function GLTFLoader(parent) {
+                this._renderReady = false;
+                this._disposed = false;
+                this._objectURLs = new Array();
                 // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
+                // Count of pending work that needs to complete before the asset is rendered.
+                this._renderPendingCount = 0;
+                // Count of pending work that needs to complete before the loader is cleared.
+                this._loaderPendingCount = 0;
                 this._parent = parent;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -327,13 +351,32 @@ var BABYLON;
             });
             GLTFLoader.prototype.executeWhenRenderReady = function (func) {
                 if (this._renderReady) {
-                    func(this._succeeded);
+                    func();
                 }
                 else {
                     this._renderReadyObservable.add(func);
                 }
             };
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
+            GLTFLoader.prototype.dispose = function () {
+                if (this._disposed) {
+                    return;
+                }
+                this._disposed = true;
+                // Revoke object urls created during load
+                this._objectURLs.forEach(function (url) { return URL.revokeObjectURL(url); });
+                this._objectURLs.length = 0;
+                this._gltf = undefined;
+                this._babylonScene = undefined;
+                this._rootUrl = undefined;
+                this._defaultMaterial = undefined;
+                this._successCallback = undefined;
+                this._errorCallback = undefined;
+                this._renderReady = false;
+                this._renderReadyObservable.clear();
+                this._renderPendingCount = 0;
+                this._loaderPendingCount = 0;
+            };
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 this._loadAsync(meshesNames, scene, data, rootUrl, function () {
                     var meshes = [];
@@ -355,23 +398,30 @@ var BABYLON;
                         }
                     }
                     onSuccess(meshes, null, skeletons);
-                }, onError);
+                }, onProgress, onError);
             };
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
-                this._loadAsync(null, scene, data, rootUrl, onSuccess, onError);
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+                this._loadAsync(null, scene, data, rootUrl, onSuccess, onProgress, onError);
             };
-            GLTFLoader.prototype._loadAsync = function (nodeNames, scene, data, rootUrl, onSuccess, onError) {
-                this._clear();
+            GLTFLoader.prototype._loadAsync = function (nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 this._loadData(data);
                 this._babylonScene = scene;
                 this._rootUrl = rootUrl;
-                this._onSuccess = onSuccess;
-                this._onError = onError;
+                this._successCallback = onSuccess;
+                this._progressCallback = onProgress;
+                this._errorCallback = onError;
                 this.addPendingData(this);
                 this._loadScene(nodeNames);
                 this._loadAnimations();
                 this.removePendingData(this);
             };
+            GLTFLoader.prototype._onError = function (message) {
+                this.dispose();
+                this._errorCallback(message);
+            };
+            GLTFLoader.prototype._onProgress = function (event) {
+                this._progressCallback(event);
+            };
             GLTFLoader.prototype._onRenderReady = function () {
                 switch (this._parent.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
@@ -389,23 +439,13 @@ var BABYLON;
                         BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
                         break;
                 }
-                this._succeeded = (this._errors.length === 0);
-                if (this._succeeded) {
-                    this._showMeshes();
-                    this._startAnimations();
-                    this._onSuccess();
-                }
-                else {
-                    this._errors.forEach(function (error) { return BABYLON.Tools.Error(error); });
-                    this._errors = [];
-                    this._onError();
-                }
-                this._renderReadyObservable.notifyObservers(this._succeeded);
+                this._showMeshes();
+                this._startAnimations();
+                this._successCallback();
+                this._renderReadyObservable.notifyObservers(this);
             };
             GLTFLoader.prototype._onLoaderComplete = function () {
-                this._errors.forEach(function (error) { return BABYLON.Tools.Error(error); });
-                this._errors = [];
-                this._clear();
+                this.dispose();
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                 }
@@ -462,29 +502,6 @@ var BABYLON;
                     }
                 }
             };
-            GLTFLoader.prototype._clear = function () {
-                // Revoke object urls created during load
-                if (this._gltf && this._gltf.textures) {
-                    for (var i = 0; i < this._gltf.textures.length; i++) {
-                        var texture = this._gltf.textures[i];
-                        if (texture.blobURL) {
-                            URL.revokeObjectURL(texture.blobURL);
-                        }
-                    }
-                }
-                this._gltf = undefined;
-                this._errors = [];
-                this._babylonScene = undefined;
-                this._rootUrl = undefined;
-                this._defaultMaterial = undefined;
-                this._onSuccess = undefined;
-                this._onError = undefined;
-                this._succeeded = false;
-                this._renderReady = false;
-                this._renderReadyObservable.clear();
-                this._renderPendingCount = 0;
-                this._loaderPendingCount = 0;
-            };
             GLTFLoader.prototype._loadScene = function (nodeNames) {
                 var _this = this;
                 var scene = this._gltf.scenes[this._gltf.scene || 0];
@@ -649,7 +666,7 @@ var BABYLON;
                 var _this = this;
                 var attributes = primitive.attributes;
                 if (!attributes) {
-                    this._errors.push("Primitive has no attributes");
+                    this._onError("Primitive has no attributes");
                     return;
                 }
                 var vertexData = new BABYLON.VertexData();
@@ -968,9 +985,15 @@ var BABYLON;
                         buffer.loadedData = new Uint8Array(data);
                         buffer.loadedObservable.notifyObservers(buffer);
                         buffer.loadedObservable = null;
-                    }, null, null, true, function (request) {
-                        _this._errors.push("Failed to load file '" + buffer.uri + "': " + request.statusText + "(" + request.status + ")");
-                        _this.removePendingData(buffer);
+                    }, function (event) {
+                        if (!_this._disposed) {
+                            _this._onProgress(event);
+                        }
+                    }, this._babylonScene.database, true, function (request) {
+                        if (!_this._disposed) {
+                            _this._onError("Failed to load file '" + buffer.uri + "': " + request.status + " " + request.statusText);
+                            _this.removePendingData(buffer);
+                        }
                     });
                 }
             };
@@ -979,7 +1002,7 @@ var BABYLON;
                 byteOffset += (bufferView.byteOffset || 0);
                 this._loadBufferAsync(bufferView.buffer, function (bufferData) {
                     if (byteOffset + byteLength > bufferData.byteLength) {
-                        _this._errors.push("Buffer access is out of range");
+                        _this._onError("Buffer access is out of range");
                         return;
                     }
                     var buffer = bufferData.buffer;
@@ -1005,7 +1028,7 @@ var BABYLON;
                             bufferViewData = new Float32Array(buffer, byteOffset, byteLength);
                             break;
                         default:
-                            _this._errors.push("Invalid component type (" + componentType + ")");
+                            _this._onError("Invalid component type (" + componentType + ")");
                             return;
                     }
                     onSuccess(bufferViewData);
@@ -1014,9 +1037,23 @@ var BABYLON;
             GLTFLoader.prototype._loadAccessorAsync = function (accessor, onSuccess) {
                 var bufferView = this._gltf.bufferViews[accessor.bufferView];
                 var byteOffset = accessor.byteOffset || 0;
-                var byteLength = accessor.count * GLTF2.GLTFUtils.GetByteStrideFromType(accessor);
+                var byteLength = accessor.count * this._getByteStrideFromType(accessor);
                 this._loadBufferViewAsync(bufferView, byteOffset, byteLength, accessor.componentType, onSuccess);
             };
+            GLTFLoader.prototype._getByteStrideFromType = function (accessor) {
+                switch (accessor.type) {
+                    case "SCALAR": return 1;
+                    case "VEC2": return 2;
+                    case "VEC3": return 3;
+                    case "VEC4": return 4;
+                    case "MAT2": return 4;
+                    case "MAT3": return 9;
+                    case "MAT4": return 16;
+                    default:
+                        this._onError("Invalid accessor type (" + accessor.type + ")");
+                        return 0;
+                }
+            };
             GLTFLoader.prototype.addPendingData = function (data) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
@@ -1165,32 +1202,41 @@ var BABYLON;
                     return babylonTexture;
                 }
                 var source = this._gltf.images[texture.source];
-                var url;
+                var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
+                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
+                var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
+                this.addPendingData(texture);
+                babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
+                    if (!_this._disposed) {
+                        _this.removePendingData(texture);
+                    }
+                }, function () {
+                    if (!_this._disposed) {
+                        _this._onError("Failed to load texture '" + source.uri + "'");
+                        _this.removePendingData(texture);
+                    }
+                });
+                var setTextureData = function (data) {
+                    var url = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
+                    _this._objectURLs.push(url);
+                    babylonTexture.updateURL(url);
+                };
                 if (!source.uri) {
                     var bufferView = this._gltf.bufferViews[source.bufferView];
-                    this._loadBufferViewAsync(bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE, function (data) {
-                        texture.blobURL = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
-                        texture.babylonTextures[texCoord].updateURL(texture.blobURL);
-                    });
+                    this._loadBufferViewAsync(bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE, setTextureData);
                 }
                 else if (GLTF2.GLTFUtils.IsBase64(source.uri)) {
-                    var data = new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri));
-                    texture.blobURL = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
-                    url = texture.blobURL;
+                    setTextureData(new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri)));
                 }
                 else {
-                    url = this._rootUrl + source.uri;
+                    BABYLON.Tools.LoadFile(this._rootUrl + source.uri, setTextureData, function (event) {
+                        if (!_this._disposed) {
+                            _this._onProgress(event);
+                        }
+                    }, this._babylonScene.database, true, function (request) {
+                        _this._onError("Failed to load file '" + source.uri + "': " + request.status + " " + request.statusText);
+                    });
                 }
-                var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
-                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
-                var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
-                this.addPendingData(texture);
-                var babylonTexture = new BABYLON.Texture(url, this._babylonScene, noMipMaps, false, samplingMode, function () {
-                    _this.removePendingData(texture);
-                }, function () {
-                    _this._errors.push("Failed to load texture '" + source.uri + "'");
-                    _this.removePendingData(texture);
-                });
                 babylonTexture.coordinatesIndex = texCoord;
                 babylonTexture.wrapU = GLTF2.GLTFUtils.GetTextureWrapMode(sampler.wrapS);
                 babylonTexture.wrapV = GLTF2.GLTFUtils.GetTextureWrapMode(sampler.wrapT);
@@ -1261,23 +1307,6 @@ var BABYLON;
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
             };
-            /**
-             * Returns the byte stride giving an accessor
-             * @param accessor: the GLTF accessor objet
-             */
-            GLTFUtils.GetByteStrideFromType = function (accessor) {
-                // Needs this function since "byteStride" isn't requiered in glTF format
-                var type = accessor.type;
-                switch (type) {
-                    case "VEC2": return 2;
-                    case "VEC3": return 3;
-                    case "VEC4": return 4;
-                    case "MAT2": return 4;
-                    case "MAT3": return 9;
-                    case "MAT4": return 16;
-                    default: return 1;
-                }
-            };
             GLTFUtils.GetTextureSamplingMode = function (magFilter, minFilter) {
                 // Set defaults if undefined
                 magFilter = magFilter === undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
@@ -1425,12 +1454,9 @@ var BABYLON;
                             loader.removeLoaderPendingData(material);
                             return;
                         }
-                        // Load the next LOD once the loader has succeeded.
-                        loader.executeWhenRenderReady(function (succeeded) {
-                            if (!succeeded) {
-                                return;
-                            }
-                            // Load the next LOD when all of the textures are loaded.
+                        // Load the next LOD when the loader is ready to render and
+                        // all active material textures of the current LOD are loaded.
+                        loader.executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
                             });

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


+ 50 - 52
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -10,8 +10,8 @@ declare module BABYLON {
         bin: ArrayBufferView;
     }
     interface IGLTFLoader {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
     class GLTFFileLoader implements ISceneLoaderPluginAsync {
         static CreateGLTFLoaderV1: (parent: GLTFFileLoader) => IGLTFLoader;
@@ -23,14 +23,14 @@ declare module BABYLON {
         onMaterialLoaded: (material: Material) => void;
         onComplete: () => void;
         extensions: ISceneLoaderPluginExtensions;
-        importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void): void;
-        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onError: () => 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;
+        loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         canDirectLoad(data: string): boolean;
-        private static _parse(data);
-        private _getLoader(loaderData);
-        private static _parseBinary(data);
-        private static _parseV1(binaryReader);
-        private static _parseV2(binaryReader);
+        private static _parse(data, onError);
+        private _getLoader(loaderData, onError);
+        private static _parseBinary(data, onError);
+        private static _parseV1(binaryReader, onError);
+        private static _parseV2(binaryReader, onError);
         private static _parseVersion(version);
         private static _compareVersion(a, b);
         private static _decodeBufferToText(view);
@@ -365,11 +365,11 @@ declare module BABYLON.GLTF1 {
     */
     class GLTFLoaderBase {
         static CreateRuntime(parsedData: any, scene: Scene, rootUrl: string): IGLTFRuntime;
-        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void, onProgress?: () => void): void;
-        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): void;
-        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: () => void): void;
-        static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: () => void): void;
-        static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): void;
+        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): void;
+        static LoadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): void;
+        static CreateTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
+        static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): void;
+        static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): void;
     }
     /**
     * glTF V1 Loader
@@ -379,10 +379,10 @@ declare module BABYLON.GLTF1 {
             [name: string]: GLTFLoaderExtension;
         };
         static RegisterExtension(extension: GLTFLoaderExtension): void;
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError?: () => void, onProgress?: () => void): boolean;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
         private _loadShadersAsync(gltfRuntime, onload);
-        private _loadBuffersAsync(gltfRuntime, onload, onProgress?);
+        private _loadBuffersAsync(gltfRuntime, onLoad, onProgress?);
         private _createNodes(gltfRuntime);
     }
 }
@@ -467,43 +467,43 @@ declare module BABYLON.GLTF1 {
         * Defines an override for loading the runtime
         * Return true to stop further extensions from loading the runtime
         */
-        loadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): boolean;
+        loadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: (message: string) => void): boolean;
         /**
          * Defines an onverride for creating gltf runtime
          * Return true to stop further extensions from creating the runtime
          */
-        loadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: () => void): boolean;
+        loadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: (message: string) => void): boolean;
         /**
         * Defines an override for loading buffers
         * Return true to stop further extensions from loading this buffer
         */
-        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void, onProgress?: () => void): boolean;
+        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): boolean;
         /**
         * Defines an override for loading texture buffers
         * Return true to stop further extensions from loading this texture data
         */
-        loadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): boolean;
+        loadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): boolean;
         /**
         * Defines an override for creating textures
         * Return true to stop further extensions from loading this texture
         */
-        createTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: () => void): boolean;
+        createTextureAsync(gltfRuntime: IGLTFRuntime, id: string, buffer: ArrayBufferView, onSuccess: (texture: Texture) => void, onError: (message: string) => void): boolean;
         /**
         * Defines an override for loading shader strings
         * Return true to stop further extensions from loading this shader data
         */
-        loadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: () => void): boolean;
+        loadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): boolean;
         /**
         * Defines an override for loading materials
         * Return true to stop further extensions from loading this material
         */
-        loadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): boolean;
-        static LoadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): void;
-        static LoadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void;
-        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (bufferView: ArrayBufferView) => void, onError: () => void, onProgress?: () => void): void;
-        static LoadTextureAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (texture: Texture) => void, onError: () => void): void;
-        static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderData: string) => void, onError: () => void): void;
-        static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): void;
+        loadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): boolean;
+        static LoadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: (message: string) => void): void;
+        static LoadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: (message: string) => void): void;
+        static LoadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (bufferView: ArrayBufferView) => void, onError: (message: string) => void, onProgress?: () => void): void;
+        static LoadTextureAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (texture: Texture) => void, onError: (message: string) => void): void;
+        static LoadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderData: string) => void, onError: (message: string) => void): void;
+        static LoadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): void;
         private static LoadTextureBufferAsync(gltfRuntime, id, onSuccess, onError);
         private static CreateTextureAsync(gltfRuntime, id, buffer, onSuccess, onError);
         private static ApplyExtensions(func, defaultFunc);
@@ -515,10 +515,10 @@ declare module BABYLON.GLTF1 {
     class GLTFBinaryExtension extends GLTFLoaderExtension {
         private _bin;
         constructor();
-        loadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: () => void): boolean;
-        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): boolean;
-        loadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: () => void): boolean;
-        loadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: () => void): boolean;
+        loadRuntimeAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (gltfRuntime: IGLTFRuntime) => void, onError: (message: string) => void): boolean;
+        loadBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): boolean;
+        loadTextureBufferAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (buffer: ArrayBufferView) => void, onError: (message: string) => void): boolean;
+        loadShaderStringAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (shaderString: string) => void, onError: (message: string) => void): boolean;
     }
 }
 
@@ -526,8 +526,8 @@ declare module BABYLON.GLTF1 {
 declare module BABYLON.GLTF1 {
     class GLTFMaterialsCommonExtension extends GLTFLoaderExtension {
         constructor();
-        loadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: () => void): boolean;
-        loadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: () => void): boolean;
+        loadRuntimeExtensionsAsync(gltfRuntime: IGLTFRuntime, onSuccess: () => void, onError: (message: string) => void): boolean;
+        loadMaterialAsync(gltfRuntime: IGLTFRuntime, id: string, onSuccess: (material: Material) => void, onError: (message: string) => void): boolean;
         private _loadTexture(gltfRuntime, id, material, propertyPath, onError);
     }
 }
@@ -742,7 +742,6 @@ declare module BABYLON.GLTF2 {
         sampler?: number;
         source: number;
         babylonTextures?: Texture[];
-        blobURL?: string;
     }
     interface IGLTFTextureInfo {
         index: number;
@@ -772,17 +771,18 @@ declare module BABYLON.GLTF2 {
 
 
 declare module BABYLON.GLTF2 {
-    class GLTFLoader implements IGLTFLoader {
+    class GLTFLoader implements IGLTFLoader, IDisposable {
         private _parent;
         private _gltf;
-        private _errors;
         private _babylonScene;
         private _rootUrl;
         private _defaultMaterial;
-        private _onSuccess;
-        private _onError;
-        private _succeeded;
+        private _successCallback;
+        private _progressCallback;
+        private _errorCallback;
         private _renderReady;
+        private _disposed;
+        private _objectURLs;
         private _renderReadyObservable;
         private _renderPendingCount;
         private _loaderPendingCount;
@@ -792,18 +792,20 @@ declare module BABYLON.GLTF2 {
         static RegisterExtension(extension: GLTFLoaderExtension): void;
         readonly gltf: IGLTF;
         readonly babylonScene: Scene;
-        executeWhenRenderReady(func: (succeeded: boolean) => void): void;
+        executeWhenRenderReady(func: () => void): void;
         constructor(parent: GLTFFileLoader);
-        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onError: () => void): void;
-        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onError: () => void): void;
-        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onError);
+        dispose(): void;
+        importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
+        loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void;
+        private _loadAsync(nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError);
+        private _onError(message);
+        private _onProgress(event);
         private _onRenderReady();
         private _onLoaderComplete();
         private _loadData(data);
         private _addRightHandToLeftHandRootTransform();
         private _showMeshes();
         private _startAnimations();
-        private _clear();
         private _loadScene(nodeNames);
         private _loadSkin(node);
         private _updateBone(node, parentNode, skin, inverseBindMatrixData);
@@ -822,6 +824,7 @@ declare module BABYLON.GLTF2 {
         private _loadBufferAsync(index, onSuccess);
         private _loadBufferViewAsync(bufferView, byteOffset, byteLength, componentType, onSuccess);
         private _loadAccessorAsync(accessor, onSuccess);
+        private _getByteStrideFromType(accessor);
         addPendingData(data: any): void;
         removePendingData(data: any): void;
         addLoaderPendingData(data: any): void;
@@ -854,11 +857,6 @@ declare module BABYLON.GLTF2 {
         static DecodeBase64(uri: string): ArrayBuffer;
         static ForEach(view: Uint16Array | Uint32Array | Float32Array, func: (nvalue: number, index: number) => void): void;
         static GetTextureWrapMode(mode: ETextureWrapMode): number;
-        /**
-         * Returns the byte stride giving an accessor
-         * @param accessor: the GLTF accessor objet
-         */
-        static GetByteStrideFromType(accessor: IGLTFAccessor): number;
         static GetTextureSamplingMode(magFilter: ETextureMagFilter, minFilter: ETextureMinFilter): number;
         /**
          * Decodes a buffer view into a string

+ 181 - 150
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -20,87 +20,101 @@ var BABYLON;
                 ".glb": { isBinary: true }
             };
         }
-        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
-            var loaderData = GLTFFileLoader._parse(data);
-            var loader = this._getLoader(loaderData);
+        GLTFFileLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
+            var loaderData = GLTFFileLoader._parse(data, onError);
+            if (!loaderData) {
+                return;
+            }
+            var loader = this._getLoader(loaderData, onError);
             if (!loader) {
-                onError();
                 return;
             }
-            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onError);
+            loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
-        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
-            var loaderData = GLTFFileLoader._parse(data);
-            var loader = this._getLoader(loaderData);
+        GLTFFileLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+            var loaderData = GLTFFileLoader._parse(data, onError);
+            if (!loaderData) {
+                return;
+            }
+            var loader = this._getLoader(loaderData, onError);
             if (!loader) {
-                onError();
                 return;
             }
-            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onError);
+            return loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         };
         GLTFFileLoader.prototype.canDirectLoad = function (data) {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
         };
-        GLTFFileLoader._parse = function (data) {
+        GLTFFileLoader._parse = function (data, onError) {
             if (data instanceof ArrayBuffer) {
-                return GLTFFileLoader._parseBinary(data);
+                return GLTFFileLoader._parseBinary(data, onError);
+            }
+            try {
+                return {
+                    json: JSON.parse(data),
+                    bin: null
+                };
+            }
+            catch (e) {
+                onError(e.message);
+                return null;
             }
-            return {
-                json: JSON.parse(data),
-                bin: null
-            };
         };
-        GLTFFileLoader.prototype._getLoader = function (loaderData) {
+        GLTFFileLoader.prototype._getLoader = function (loaderData, onError) {
             var loaderVersion = { major: 2, minor: 0 };
             var asset = loaderData.json.asset || {};
             var version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
-                BABYLON.Tools.Error("Invalid version");
+                onError("Invalid version: " + asset.version);
                 return null;
             }
-            var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
-            if (minVersion) {
+            if (asset.minVersion !== undefined) {
+                var minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
+                if (!minVersion) {
+                    onError("Invalid minimum version: " + asset.minVersion);
+                    return null;
+                }
                 if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
-                    BABYLON.Tools.Error("Incompatible version");
+                    onError("Incompatible minimum version: " + asset.minVersion);
                     return null;
                 }
             }
-            var createLoader = {
+            var createLoaders = {
                 1: GLTFFileLoader.CreateGLTFLoaderV1,
                 2: GLTFFileLoader.CreateGLTFLoaderV2
             };
-            var loader = createLoader[version.major](this);
-            if (loader === null) {
-                BABYLON.Tools.Error("Unsupported version");
+            var createLoader = createLoaders[version.major];
+            if (!createLoader) {
+                onError("Unsupported version: " + asset.version);
                 return null;
             }
-            return loader;
+            return createLoader(this);
         };
-        GLTFFileLoader._parseBinary = function (data) {
+        GLTFFileLoader._parseBinary = function (data, onError) {
             var Binary = {
                 Magic: 0x46546C67
             };
             var binaryReader = new BinaryReader(data);
             var magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
-                BABYLON.Tools.Error("Unexpected magic: " + magic);
+                onError("Unexpected magic: " + magic);
                 return null;
             }
             var version = binaryReader.readUint32();
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader);
-                case 2: return GLTFFileLoader._parseV2(binaryReader);
+                case 1: return GLTFFileLoader._parseV1(binaryReader, onError);
+                case 2: return GLTFFileLoader._parseV2(binaryReader, onError);
             }
-            BABYLON.Tools.Error("Unsupported version: " + version);
+            onError("Unsupported version: " + version);
             return null;
         };
-        GLTFFileLoader._parseV1 = function (binaryReader) {
+        GLTFFileLoader._parseV1 = function (binaryReader, onError) {
             var ContentFormat = {
                 JSON: 0
             };
             var length = binaryReader.readUint32();
             if (length != binaryReader.getLength()) {
-                BABYLON.Tools.Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
             var contentLength = binaryReader.readUint32();
@@ -111,7 +125,7 @@ var BABYLON;
                     content = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(contentLength)));
                     break;
                 default:
-                    BABYLON.Tools.Error("Unexpected content format: " + contentFormat);
+                    onError("Unexpected content format: " + contentFormat);
                     return null;
             }
             var bytesRemaining = binaryReader.getLength() - binaryReader.getPosition();
@@ -121,21 +135,21 @@ var BABYLON;
                 bin: body
             };
         };
-        GLTFFileLoader._parseV2 = function (binaryReader) {
+        GLTFFileLoader._parseV2 = function (binaryReader, onError) {
             var ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
             };
             var length = binaryReader.readUint32();
             if (length !== binaryReader.getLength()) {
-                BABYLON.Tools.Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
+                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
                 return null;
             }
             // JSON chunk
             var chunkLength = binaryReader.readUint32();
             var chunkFormat = binaryReader.readUint32();
             if (chunkFormat !== ChunkFormat.JSON) {
-                BABYLON.Tools.Error("First chunk format is not JSON");
+                onError("First chunk format is not JSON");
                 return null;
             }
             var json = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(chunkLength)));
@@ -146,7 +160,7 @@ var BABYLON;
                 chunkFormat = binaryReader.readUint32();
                 switch (chunkFormat) {
                     case ChunkFormat.JSON:
-                        BABYLON.Tools.Error("Unexpected JSON chunk");
+                        onError("Unexpected JSON chunk");
                         return null;
                     case ChunkFormat.BIN:
                         bin = binaryReader.readUint8Array(chunkLength);
@@ -167,17 +181,20 @@ var BABYLON;
                 return null;
             }
             var parts = version.split(".");
-            if (parts.length === 0) {
+            if (parts.length != 2) {
                 return null;
             }
-            var major = parseInt(parts[0]);
-            if (major > 1 && parts.length != 2) {
+            var major = +parts[0];
+            if (isNaN(major)) {
+                return null;
+            }
+            var minor = +parts[1];
+            if (isNaN(minor)) {
                 return null;
             }
-            var minor = parseInt(parts[1]);
             return {
                 major: major,
-                minor: parseInt(parts[0])
+                minor: minor
             };
         };
         GLTFFileLoader._compareVersion = function (a, b) {
@@ -1259,9 +1276,8 @@ var BABYLON;
         */
         var onShaderCompileError = function (program, shaderMaterial, onError) {
             return function (effect, error) {
-                BABYLON.Tools.Error("Cannot compile program named " + program.name + ". Error: " + error + ". Default material will be applied");
                 shaderMaterial.dispose(true);
-                onError();
+                onError("Cannot compile program named " + program.name + ". Error: " + error + ". Default material will be applied");
             };
         };
         /**
@@ -1409,13 +1425,15 @@ var BABYLON;
                     setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(buffer.uri))); });
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, null, true, onError);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + buffer.uri, function (data) { return onSuccess(new Uint8Array(data)); }, onProgress, null, true, function (request) {
+                        onError(request.status + " " + request.statusText);
+                    });
                 }
             };
             GLTFLoaderBase.LoadTextureBufferAsync = function (gltfRuntime, id, onSuccess, onError) {
                 var texture = gltfRuntime.textures[id];
                 if (!texture || !texture.source) {
-                    onError();
+                    onError(null);
                     return;
                 }
                 if (texture.babylonTexture) {
@@ -1427,7 +1445,9 @@ var BABYLON;
                     setTimeout(function () { return onSuccess(new Uint8Array(GLTF1.GLTFUtils.DecodeBase64(source.uri))); });
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, null, null, true, onError);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + source.uri, function (data) { return onSuccess(new Uint8Array(data)); }, null, null, true, function (request) {
+                        onError(request.status + " " + request.statusText);
+                    });
                 }
             };
             GLTFLoaderBase.CreateTextureAsync = function (gltfRuntime, id, buffer, onSuccess, onError) {
@@ -1459,7 +1479,9 @@ var BABYLON;
                     onSuccess(shaderString);
                 }
                 else {
-                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, null, null, false, onError);
+                    BABYLON.Tools.LoadFile(gltfRuntime.rootUrl + shader.uri, onSuccess, null, null, false, function (request) {
+                        onError(request.status + " " + request.statusText);
+                    });
                 }
             };
             GLTFLoaderBase.LoadMaterialAsync = function (gltfRuntime, id, onSuccess, onError) {
@@ -1605,7 +1627,7 @@ var BABYLON;
                 }
                 GLTFLoader.Extensions[extension.name] = extension;
             };
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError, onProgress) {
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 var gltfRuntime = GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1656,7 +1678,7 @@ var BABYLON;
                 }, onError);
                 return true;
             };
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 scene.useRightHandedSystem = true;
                 GLTF1.GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, function (gltfRuntime) {
@@ -1710,7 +1732,7 @@ var BABYLON;
                 }
             };
             ;
-            GLTFLoader.prototype._loadBuffersAsync = function (gltfRuntime, onload, onProgress) {
+            GLTFLoader.prototype._loadBuffersAsync = function (gltfRuntime, onLoad, onProgress) {
                 var hasBuffers = false;
                 var processBuffer = function (buf, buffer) {
                     GLTF1.GLTFLoaderExtension.LoadBufferAsync(gltfRuntime, buf, function (bufferView) {
@@ -1722,7 +1744,7 @@ var BABYLON;
                             gltfRuntime.loadedBufferViews[buf] = bufferView;
                         }
                         if (gltfRuntime.loadedBufferCount === gltfRuntime.buffersCount) {
-                            onload();
+                            onLoad();
                         }
                     }, function () {
                         BABYLON.Tools.Error("Error when loading buffer named " + buf + " located at " + buffer.uri);
@@ -1739,7 +1761,7 @@ var BABYLON;
                     }
                 }
                 if (!hasBuffers) {
-                    onload();
+                    onLoad();
                 }
             };
             GLTFLoader.prototype._createNodes = function (gltfRuntime) {
@@ -2451,8 +2473,15 @@ var BABYLON;
     (function (GLTF2) {
         var GLTFLoader = (function () {
             function GLTFLoader(parent) {
+                this._renderReady = false;
+                this._disposed = false;
+                this._objectURLs = new Array();
                 // Observable with boolean indicating success or error.
                 this._renderReadyObservable = new BABYLON.Observable();
+                // Count of pending work that needs to complete before the asset is rendered.
+                this._renderPendingCount = 0;
+                // Count of pending work that needs to complete before the loader is cleared.
+                this._loaderPendingCount = 0;
                 this._parent = parent;
             }
             GLTFLoader.RegisterExtension = function (extension) {
@@ -2480,13 +2509,32 @@ var BABYLON;
             });
             GLTFLoader.prototype.executeWhenRenderReady = function (func) {
                 if (this._renderReady) {
-                    func(this._succeeded);
+                    func();
                 }
                 else {
                     this._renderReadyObservable.add(func);
                 }
             };
-            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onError) {
+            GLTFLoader.prototype.dispose = function () {
+                if (this._disposed) {
+                    return;
+                }
+                this._disposed = true;
+                // Revoke object urls created during load
+                this._objectURLs.forEach(function (url) { return URL.revokeObjectURL(url); });
+                this._objectURLs.length = 0;
+                this._gltf = undefined;
+                this._babylonScene = undefined;
+                this._rootUrl = undefined;
+                this._defaultMaterial = undefined;
+                this._successCallback = undefined;
+                this._errorCallback = undefined;
+                this._renderReady = false;
+                this._renderReadyObservable.clear();
+                this._renderPendingCount = 0;
+                this._loaderPendingCount = 0;
+            };
+            GLTFLoader.prototype.importMeshAsync = function (meshesNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 var _this = this;
                 this._loadAsync(meshesNames, scene, data, rootUrl, function () {
                     var meshes = [];
@@ -2508,23 +2556,30 @@ var BABYLON;
                         }
                     }
                     onSuccess(meshes, null, skeletons);
-                }, onError);
+                }, onProgress, onError);
             };
-            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onError) {
-                this._loadAsync(null, scene, data, rootUrl, onSuccess, onError);
+            GLTFLoader.prototype.loadAsync = function (scene, data, rootUrl, onSuccess, onProgress, onError) {
+                this._loadAsync(null, scene, data, rootUrl, onSuccess, onProgress, onError);
             };
-            GLTFLoader.prototype._loadAsync = function (nodeNames, scene, data, rootUrl, onSuccess, onError) {
-                this._clear();
+            GLTFLoader.prototype._loadAsync = function (nodeNames, scene, data, rootUrl, onSuccess, onProgress, onError) {
                 this._loadData(data);
                 this._babylonScene = scene;
                 this._rootUrl = rootUrl;
-                this._onSuccess = onSuccess;
-                this._onError = onError;
+                this._successCallback = onSuccess;
+                this._progressCallback = onProgress;
+                this._errorCallback = onError;
                 this.addPendingData(this);
                 this._loadScene(nodeNames);
                 this._loadAnimations();
                 this.removePendingData(this);
             };
+            GLTFLoader.prototype._onError = function (message) {
+                this.dispose();
+                this._errorCallback(message);
+            };
+            GLTFLoader.prototype._onProgress = function (event) {
+                this._progressCallback(event);
+            };
             GLTFLoader.prototype._onRenderReady = function () {
                 switch (this._parent.coordinateSystemMode) {
                     case BABYLON.GLTFLoaderCoordinateSystemMode.AUTO:
@@ -2542,23 +2597,13 @@ var BABYLON;
                         BABYLON.Tools.Error("Invalid coordinate system mode (" + this._parent.coordinateSystemMode + ")");
                         break;
                 }
-                this._succeeded = (this._errors.length === 0);
-                if (this._succeeded) {
-                    this._showMeshes();
-                    this._startAnimations();
-                    this._onSuccess();
-                }
-                else {
-                    this._errors.forEach(function (error) { return BABYLON.Tools.Error(error); });
-                    this._errors = [];
-                    this._onError();
-                }
-                this._renderReadyObservable.notifyObservers(this._succeeded);
+                this._showMeshes();
+                this._startAnimations();
+                this._successCallback();
+                this._renderReadyObservable.notifyObservers(this);
             };
             GLTFLoader.prototype._onLoaderComplete = function () {
-                this._errors.forEach(function (error) { return BABYLON.Tools.Error(error); });
-                this._errors = [];
-                this._clear();
+                this.dispose();
                 if (this._parent.onComplete) {
                     this._parent.onComplete();
                 }
@@ -2615,29 +2660,6 @@ var BABYLON;
                     }
                 }
             };
-            GLTFLoader.prototype._clear = function () {
-                // Revoke object urls created during load
-                if (this._gltf && this._gltf.textures) {
-                    for (var i = 0; i < this._gltf.textures.length; i++) {
-                        var texture = this._gltf.textures[i];
-                        if (texture.blobURL) {
-                            URL.revokeObjectURL(texture.blobURL);
-                        }
-                    }
-                }
-                this._gltf = undefined;
-                this._errors = [];
-                this._babylonScene = undefined;
-                this._rootUrl = undefined;
-                this._defaultMaterial = undefined;
-                this._onSuccess = undefined;
-                this._onError = undefined;
-                this._succeeded = false;
-                this._renderReady = false;
-                this._renderReadyObservable.clear();
-                this._renderPendingCount = 0;
-                this._loaderPendingCount = 0;
-            };
             GLTFLoader.prototype._loadScene = function (nodeNames) {
                 var _this = this;
                 var scene = this._gltf.scenes[this._gltf.scene || 0];
@@ -2802,7 +2824,7 @@ var BABYLON;
                 var _this = this;
                 var attributes = primitive.attributes;
                 if (!attributes) {
-                    this._errors.push("Primitive has no attributes");
+                    this._onError("Primitive has no attributes");
                     return;
                 }
                 var vertexData = new BABYLON.VertexData();
@@ -3121,9 +3143,15 @@ var BABYLON;
                         buffer.loadedData = new Uint8Array(data);
                         buffer.loadedObservable.notifyObservers(buffer);
                         buffer.loadedObservable = null;
-                    }, null, null, true, function (request) {
-                        _this._errors.push("Failed to load file '" + buffer.uri + "': " + request.statusText + "(" + request.status + ")");
-                        _this.removePendingData(buffer);
+                    }, function (event) {
+                        if (!_this._disposed) {
+                            _this._onProgress(event);
+                        }
+                    }, this._babylonScene.database, true, function (request) {
+                        if (!_this._disposed) {
+                            _this._onError("Failed to load file '" + buffer.uri + "': " + request.status + " " + request.statusText);
+                            _this.removePendingData(buffer);
+                        }
                     });
                 }
             };
@@ -3132,7 +3160,7 @@ var BABYLON;
                 byteOffset += (bufferView.byteOffset || 0);
                 this._loadBufferAsync(bufferView.buffer, function (bufferData) {
                     if (byteOffset + byteLength > bufferData.byteLength) {
-                        _this._errors.push("Buffer access is out of range");
+                        _this._onError("Buffer access is out of range");
                         return;
                     }
                     var buffer = bufferData.buffer;
@@ -3158,7 +3186,7 @@ var BABYLON;
                             bufferViewData = new Float32Array(buffer, byteOffset, byteLength);
                             break;
                         default:
-                            _this._errors.push("Invalid component type (" + componentType + ")");
+                            _this._onError("Invalid component type (" + componentType + ")");
                             return;
                     }
                     onSuccess(bufferViewData);
@@ -3167,9 +3195,23 @@ var BABYLON;
             GLTFLoader.prototype._loadAccessorAsync = function (accessor, onSuccess) {
                 var bufferView = this._gltf.bufferViews[accessor.bufferView];
                 var byteOffset = accessor.byteOffset || 0;
-                var byteLength = accessor.count * GLTF2.GLTFUtils.GetByteStrideFromType(accessor);
+                var byteLength = accessor.count * this._getByteStrideFromType(accessor);
                 this._loadBufferViewAsync(bufferView, byteOffset, byteLength, accessor.componentType, onSuccess);
             };
+            GLTFLoader.prototype._getByteStrideFromType = function (accessor) {
+                switch (accessor.type) {
+                    case "SCALAR": return 1;
+                    case "VEC2": return 2;
+                    case "VEC3": return 3;
+                    case "VEC4": return 4;
+                    case "MAT2": return 4;
+                    case "MAT3": return 9;
+                    case "MAT4": return 16;
+                    default:
+                        this._onError("Invalid accessor type (" + accessor.type + ")");
+                        return 0;
+                }
+            };
             GLTFLoader.prototype.addPendingData = function (data) {
                 if (!this._renderReady) {
                     this._renderPendingCount++;
@@ -3318,32 +3360,41 @@ var BABYLON;
                     return babylonTexture;
                 }
                 var source = this._gltf.images[texture.source];
-                var url;
+                var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
+                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
+                var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
+                this.addPendingData(texture);
+                babylonTexture = new BABYLON.Texture(null, this._babylonScene, noMipMaps, false, samplingMode, function () {
+                    if (!_this._disposed) {
+                        _this.removePendingData(texture);
+                    }
+                }, function () {
+                    if (!_this._disposed) {
+                        _this._onError("Failed to load texture '" + source.uri + "'");
+                        _this.removePendingData(texture);
+                    }
+                });
+                var setTextureData = function (data) {
+                    var url = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
+                    _this._objectURLs.push(url);
+                    babylonTexture.updateURL(url);
+                };
                 if (!source.uri) {
                     var bufferView = this._gltf.bufferViews[source.bufferView];
-                    this._loadBufferViewAsync(bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE, function (data) {
-                        texture.blobURL = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
-                        texture.babylonTextures[texCoord].updateURL(texture.blobURL);
-                    });
+                    this._loadBufferViewAsync(bufferView, 0, bufferView.byteLength, GLTF2.EComponentType.UNSIGNED_BYTE, setTextureData);
                 }
                 else if (GLTF2.GLTFUtils.IsBase64(source.uri)) {
-                    var data = new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri));
-                    texture.blobURL = URL.createObjectURL(new Blob([data], { type: source.mimeType }));
-                    url = texture.blobURL;
+                    setTextureData(new Uint8Array(GLTF2.GLTFUtils.DecodeBase64(source.uri)));
                 }
                 else {
-                    url = this._rootUrl + source.uri;
+                    BABYLON.Tools.LoadFile(this._rootUrl + source.uri, setTextureData, function (event) {
+                        if (!_this._disposed) {
+                            _this._onProgress(event);
+                        }
+                    }, this._babylonScene.database, true, function (request) {
+                        _this._onError("Failed to load file '" + source.uri + "': " + request.status + " " + request.statusText);
+                    });
                 }
-                var sampler = (texture.sampler === undefined ? {} : this._gltf.samplers[texture.sampler]);
-                var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
-                var samplingMode = GLTF2.GLTFUtils.GetTextureSamplingMode(sampler.magFilter, sampler.minFilter);
-                this.addPendingData(texture);
-                var babylonTexture = new BABYLON.Texture(url, this._babylonScene, noMipMaps, false, samplingMode, function () {
-                    _this.removePendingData(texture);
-                }, function () {
-                    _this._errors.push("Failed to load texture '" + source.uri + "'");
-                    _this.removePendingData(texture);
-                });
                 babylonTexture.coordinatesIndex = texCoord;
                 babylonTexture.wrapU = GLTF2.GLTFUtils.GetTextureWrapMode(sampler.wrapS);
                 babylonTexture.wrapV = GLTF2.GLTFUtils.GetTextureWrapMode(sampler.wrapT);
@@ -3414,23 +3465,6 @@ var BABYLON;
                         return BABYLON.Texture.WRAP_ADDRESSMODE;
                 }
             };
-            /**
-             * Returns the byte stride giving an accessor
-             * @param accessor: the GLTF accessor objet
-             */
-            GLTFUtils.GetByteStrideFromType = function (accessor) {
-                // Needs this function since "byteStride" isn't requiered in glTF format
-                var type = accessor.type;
-                switch (type) {
-                    case "VEC2": return 2;
-                    case "VEC3": return 3;
-                    case "VEC4": return 4;
-                    case "MAT2": return 4;
-                    case "MAT3": return 9;
-                    case "MAT4": return 16;
-                    default: return 1;
-                }
-            };
             GLTFUtils.GetTextureSamplingMode = function (magFilter, minFilter) {
                 // Set defaults if undefined
                 magFilter = magFilter === undefined ? GLTF2.ETextureMagFilter.LINEAR : magFilter;
@@ -3578,12 +3612,9 @@ var BABYLON;
                             loader.removeLoaderPendingData(material);
                             return;
                         }
-                        // Load the next LOD once the loader has succeeded.
-                        loader.executeWhenRenderReady(function (succeeded) {
-                            if (!succeeded) {
-                                return;
-                            }
-                            // Load the next LOD when all of the textures are loaded.
+                        // Load the next LOD when the loader is ready to render and
+                        // all active material textures of the current LOD are loaded.
+                        loader.executeWhenRenderReady(function () {
                             BABYLON.BaseTexture.WhenAllReady(babylonMaterial.getActiveTextures(), function () {
                                 _this.loadMaterialLOD(loader, material, materialLODs, lod - 1, assign);
                             });

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


+ 4 - 0
gui/src/controls/button.ts

@@ -42,6 +42,10 @@ module BABYLON.GUI {
                 return false;
             }
 
+            if (!super.contains(x, y)) {
+                return false;
+            }
+
             this._processObservables(type, x, y);
 
             return true;