Browse Source

onError handling of textures

the onError callbacks of Texture/CubeTexture and HDRTexture now deliver
)optional) string message and the exception thrown (if thrown).
AssetsManager was also updated to be conform with the rest of the tasks'
error handling.
Raanan Weber 8 years ago
parent
commit
ab850aa98d

+ 1 - 1
src/Materials/Textures/babylon.cubeTexture.ts

@@ -18,7 +18,7 @@
             return new CubeTexture(url, scene, null, false, null, null, null, undefined, true, forcedExtension);
             return new CubeTexture(url, scene, null, false, null, null, null, undefined, true, forcedExtension);
         }
         }
 
 
-        constructor(rootUrl: string, scene: Scene, extensions?: string[], noMipmap?: boolean, files?: string[], onLoad: () => void = null, onError: () => void = null, format: number = Engine.TEXTUREFORMAT_RGBA, prefiltered = false, forcedExtension = null) {
+        constructor(rootUrl: string, scene: Scene, extensions?: string[], noMipmap?: boolean, files?: string[], onLoad: () => void = null, onError: (message?: string, exception?: any) => void = null, format: number = Engine.TEXTUREFORMAT_RGBA, prefiltered = false, forcedExtension = null) {
             super(scene);
             super(scene);
 
 
             this.name = rootUrl;
             this.name = rootUrl;

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

@@ -69,7 +69,7 @@ module BABYLON {
          * @param useInGammaSpace Specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space)
          * @param useInGammaSpace Specifies if the texture will be use in gamma or linear space (the PBR material requires those texture in linear space, but the standard material would require them in Gamma space)
          * @param usePMREMGenerator Specifies wether or not to generate the CubeMap through CubeMapGen to avoid seams issue at run time.
          * @param usePMREMGenerator Specifies wether or not to generate the CubeMap through CubeMapGen to avoid seams issue at run time.
          */
          */
-        constructor(url: string, scene: Scene, size?: number, noMipmap = false, generateHarmonics = true, useInGammaSpace = false, usePMREMGenerator = false, onLoad: () => void = null, onError: () => void = null) {
+        constructor(url: string, scene: Scene, size?: number, noMipmap = false, generateHarmonics = true, useInGammaSpace = false, usePMREMGenerator = false, onLoad: () => void = null, onError: (message?: string, exception?: any) => void = null) {
             super(scene);
             super(scene);
 
 
             if (!url) {
             if (!url) {
@@ -436,7 +436,7 @@ module BABYLON {
             serializationObject.customType = "BABYLON.HDRCubeTexture";
             serializationObject.customType = "BABYLON.HDRCubeTexture";
             serializationObject.noMipmap = this._noMipmap;
             serializationObject.noMipmap = this._noMipmap;
             serializationObject.isBlocking = this._isBlocking;
             serializationObject.isBlocking = this._isBlocking;
-            
+
             return serializationObject;
             return serializationObject;
         }
         }
 
 

+ 15 - 15
src/Materials/Textures/babylon.texture.ts

@@ -1,12 +1,12 @@
 module BABYLON {
 module BABYLON {
     export class Texture extends BaseTexture {
     export class Texture extends BaseTexture {
         // Constants
         // Constants
-        public static NEAREST_SAMPLINGMODE = 1;        
+        public static NEAREST_SAMPLINGMODE = 1;
         public static NEAREST_NEAREST_MIPLINEAR = 1; // nearest is mag = nearest and min = nearest and mip = linear
         public static NEAREST_NEAREST_MIPLINEAR = 1; // nearest is mag = nearest and min = nearest and mip = linear
-        
+
         public static BILINEAR_SAMPLINGMODE = 2;
         public static BILINEAR_SAMPLINGMODE = 2;
         public static LINEAR_LINEAR_MIPNEAREST = 2; // Bilinear is mag = linear and min = linear and mip = nearest
         public static LINEAR_LINEAR_MIPNEAREST = 2; // Bilinear is mag = linear and min = linear and mip = nearest
-        
+
         public static TRILINEAR_SAMPLINGMODE = 3;
         public static TRILINEAR_SAMPLINGMODE = 3;
         public static LINEAR_LINEAR_MIPLINEAR = 3; // Trilinear is mag = linear and min = linear and mip = linear
         public static LINEAR_LINEAR_MIPLINEAR = 3; // Trilinear is mag = linear and min = linear and mip = linear
 
 
@@ -103,7 +103,7 @@
             return this._samplingMode;
             return this._samplingMode;
         }
         }
 
 
-        constructor(url: string, scene: Scene, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: () => void = null, buffer: any = null, deleteBuffer: boolean = false, format?: number) {
+        constructor(url: string, scene: Scene, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: (message?: string, esception?: any) => void = null, buffer: any = null, deleteBuffer: boolean = false, format?: number) {
             super(scene);
             super(scene);
 
 
             this.name = url;
             this.name = url;
@@ -270,13 +270,13 @@
                 this.uScale === this._cachedUScale &&
                 this.uScale === this._cachedUScale &&
                 this.vScale === this._cachedVScale &&
                 this.vScale === this._cachedVScale &&
                 this.coordinatesMode === this._cachedCoordinatesMode) {
                 this.coordinatesMode === this._cachedCoordinatesMode) {
-                    if (this.coordinatesMode === Texture.PROJECTION_MODE) {
-                        if (this._cachedProjectionMatrixId === scene.getProjectionMatrix().updateFlag) {
-                            return this._cachedTextureMatrix;
-                        }
-                    } else {
+                if (this.coordinatesMode === Texture.PROJECTION_MODE) {
+                    if (this._cachedProjectionMatrixId === scene.getProjectionMatrix().updateFlag) {
                         return this._cachedTextureMatrix;
                         return this._cachedTextureMatrix;
                     }
                     }
+                } else {
+                    return this._cachedTextureMatrix;
+                }
             }
             }
 
 
             if (!this._cachedTextureMatrix) {
             if (!this._cachedTextureMatrix) {
@@ -317,7 +317,7 @@
                     Matrix.IdentityToRef(this._cachedTextureMatrix);
                     Matrix.IdentityToRef(this._cachedTextureMatrix);
                     break;
                     break;
             }
             }
-            
+
             scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag, (mat) => {
             scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag, (mat) => {
                 return (mat.getActiveTextures().indexOf(this) !== -1);
                 return (mat.getActiveTextures().indexOf(this) !== -1);
             });
             });
@@ -340,7 +340,7 @@
 
 
         public serialize(): any {
         public serialize(): any {
             var serializationObject = super.serialize();
             var serializationObject = super.serialize();
-            
+
             if (typeof this._buffer === "string" && this._buffer.substr(0, 5) === "data:") {
             if (typeof this._buffer === "string" && this._buffer.substr(0, 5) === "data:") {
                 serializationObject.base64String = this._buffer;
                 serializationObject.base64String = this._buffer;
                 serializationObject.name = serializationObject.name.replace("data:", "");
                 serializationObject.name = serializationObject.name.replace("data:", "");
@@ -371,10 +371,10 @@
         }
         }
 
 
         public static Parse(parsedTexture: any, scene: Scene, rootUrl: string): BaseTexture {
         public static Parse(parsedTexture: any, scene: Scene, rootUrl: string): BaseTexture {
-            if (parsedTexture.customType) { 
+            if (parsedTexture.customType) {
                 var customTexture = Tools.Instantiate(parsedTexture.customType);
                 var customTexture = Tools.Instantiate(parsedTexture.customType);
                 // Update Sampling Mode
                 // Update Sampling Mode
-                var parsedCustomTexture:any = customTexture.Parse(parsedTexture, scene, rootUrl);
+                var parsedCustomTexture: any = customTexture.Parse(parsedTexture, scene, rootUrl);
                 if (parsedTexture.samplingMode && parsedCustomTexture.updateSamplingMode && parsedCustomTexture._samplingMode) {
                 if (parsedTexture.samplingMode && parsedCustomTexture.updateSamplingMode && parsedCustomTexture._samplingMode) {
                     if (parsedCustomTexture._samplingMode !== parsedTexture.samplingMode) {
                     if (parsedCustomTexture._samplingMode !== parsedTexture.samplingMode) {
                         parsedCustomTexture.updateSamplingMode(parsedTexture.samplingMode);
                         parsedCustomTexture.updateSamplingMode(parsedTexture.samplingMode);
@@ -417,7 +417,7 @@
 
 
             // Update Sampling Mode
             // Update Sampling Mode
             if (parsedTexture.samplingMode) {
             if (parsedTexture.samplingMode) {
-                var sampling:number = parsedTexture.samplingMode;
+                var sampling: number = parsedTexture.samplingMode;
                 if (texture._samplingMode !== sampling) {
                 if (texture._samplingMode !== sampling) {
                     texture.updateSamplingMode(sampling);
                     texture.updateSamplingMode(sampling);
                 }
                 }
@@ -435,7 +435,7 @@
             return texture;
             return texture;
         }
         }
 
 
-        public static LoadFromDataString(name: string, buffer: any, scene: Scene, deleteBuffer: boolean = false, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: () => void = null, format: number = Engine.TEXTUREFORMAT_RGBA): Texture {
+        public static LoadFromDataString(name: string, buffer: any, scene: Scene, deleteBuffer: boolean = false, noMipmap: boolean = false, invertY: boolean = true, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE, onLoad: () => void = null, onError: (message?: string, exception?: any) => void = null, format: number = Engine.TEXTUREFORMAT_RGBA): Texture {
             if (name.substr(0, 5) !== "data:") {
             if (name.substr(0, 5) !== "data:") {
                 name = "data:" + name;
                 name = "data:" + name;
             }
             }

+ 15 - 15
src/Tools/babylon.assetsManager.ts

@@ -153,7 +153,7 @@
 
 
     export class TextureAssetTask implements ITextureAssetTask {
     export class TextureAssetTask implements ITextureAssetTask {
         public onSuccess: (task: ITextureAssetTask) => void;
         public onSuccess: (task: ITextureAssetTask) => void;
-        public onError: (task: ITextureAssetTask) => void;
+        public onError: (task: ITextureAssetTask, message?: string, exception?: any) => void;
 
 
         public isCompleted = false;
         public isCompleted = false;
         public texture: Texture;
         public texture: Texture;
@@ -161,7 +161,7 @@
         constructor(public name: string, public url: string, public noMipmap?: boolean, public invertY?: boolean, public samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
         constructor(public name: string, public url: string, public noMipmap?: boolean, public invertY?: boolean, public samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) {
         }
         }
 
 
-        public run(scene: Scene, onSuccess: () => void, onError: () => void) {
+        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
 
 
             var onload = () => {
             var onload = () => {
                 this.isCompleted = true;
                 this.isCompleted = true;
@@ -173,12 +173,12 @@
                 onSuccess();
                 onSuccess();
             };
             };
 
 
-            var onerror = () => {
+            var onerror = (msg, exception) => {
                 if (this.onError) {
                 if (this.onError) {
-                    this.onError(this);
+                    this.onError(this, msg, exception);
                 }
                 }
 
 
-                onError();
+                onError(msg, exception);
             };
             };
 
 
             this.texture = new Texture(this.url, scene, this.noMipmap, this.invertY, this.samplingMode, onload, onerror);
             this.texture = new Texture(this.url, scene, this.noMipmap, this.invertY, this.samplingMode, onload, onerror);
@@ -187,7 +187,7 @@
 
 
     export class CubeTextureAssetTask implements IAssetTask {
     export class CubeTextureAssetTask implements IAssetTask {
         public onSuccess: (task: IAssetTask) => void;
         public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask) => void;
+        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
 
 
         public isCompleted = false;
         public isCompleted = false;
         public texture: CubeTexture;
         public texture: CubeTexture;
@@ -195,7 +195,7 @@
         constructor(public name: string, public url: string, public extensions?: string[], public noMipmap?: boolean, public files?: string[]) {
         constructor(public name: string, public url: string, public extensions?: string[], public noMipmap?: boolean, public files?: string[]) {
         }
         }
 
 
-        public run(scene: Scene, onSuccess: () => void, onError: () => void) {
+        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
 
 
             var onload = () => {
             var onload = () => {
                 this.isCompleted = true;
                 this.isCompleted = true;
@@ -207,12 +207,12 @@
                 onSuccess();
                 onSuccess();
             };
             };
 
 
-            var onerror = () => {
+            var onerror = (msg, exception) => {
                 if (this.onError) {
                 if (this.onError) {
-                    this.onError(this);
+                    this.onError(this, msg, exception);
                 }
                 }
 
 
-                onError();
+                onError(msg, exception);
             };
             };
 
 
             this.texture = new CubeTexture(this.url, scene, this.extensions, this.noMipmap, this.files, onload, onerror);
             this.texture = new CubeTexture(this.url, scene, this.extensions, this.noMipmap, this.files, onload, onerror);
@@ -221,7 +221,7 @@
 
 
     export class HDRCubeTextureAssetTask implements IAssetTask {
     export class HDRCubeTextureAssetTask implements IAssetTask {
         public onSuccess: (task: IAssetTask) => void;
         public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask) => void;
+        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
 
 
         public isCompleted = false;
         public isCompleted = false;
         public texture: HDRCubeTexture;
         public texture: HDRCubeTexture;
@@ -229,7 +229,7 @@
         constructor(public name: string, public url: string, public size?: number, public noMipmap = false, public generateHarmonics = true, public useInGammaSpace = false, public usePMREMGenerator = false) {
         constructor(public name: string, public url: string, public size?: number, public noMipmap = false, public generateHarmonics = true, public useInGammaSpace = false, public usePMREMGenerator = false) {
         }
         }
 
 
-        public run(scene: Scene, onSuccess: () => void, onError: () => void) {
+        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
 
 
             var onload = () => {
             var onload = () => {
                 this.isCompleted = true;
                 this.isCompleted = true;
@@ -241,12 +241,12 @@
                 onSuccess();
                 onSuccess();
             };
             };
 
 
-            var onerror = () => {
+            var onerror = (message?: string, exception?: any) => {
                 if (this.onError) {
                 if (this.onError) {
-                    this.onError(this);
+                    this.onError(this, message, exception);
                 }
                 }
 
 
-                onError();
+                onError(message, exception);
             };
             };
 
 
             this.texture = new HDRCubeTexture(this.url, scene, this.size, this.noMipmap, this.generateHarmonics, this.useInGammaSpace, this.usePMREMGenerator, onload, onerror);
             this.texture = new HDRCubeTexture(this.url, scene, this.size, this.noMipmap, this.generateHarmonics, this.useInGammaSpace, this.usePMREMGenerator, onload, onerror);

+ 7 - 7
src/Tools/babylon.tools.ts

@@ -394,7 +394,7 @@
             return url;
             return url;
         }
         }
 
 
-        public static LoadImage(url: any, onload, onerror, database): HTMLImageElement {
+        public static LoadImage(url: any, onLoad, onError: (message?: string, eception?: any) => void, database): HTMLImageElement {
             if (url instanceof ArrayBuffer) {
             if (url instanceof ArrayBuffer) {
                 url = Tools.EncodeArrayBufferTobase64(url);
                 url = Tools.EncodeArrayBufferTobase64(url);
             }
             }
@@ -410,7 +410,7 @@
             }
             }
 
 
             img.onload = () => {
             img.onload = () => {
-                onload(img);
+                onLoad(img);
             };
             };
 
 
             img.onerror = err => {
             img.onerror = err => {
@@ -418,9 +418,9 @@
 
 
                 if (Tools.UseFallbackTexture) {
                 if (Tools.UseFallbackTexture) {
                     img.src = Tools.fallbackTexture;
                     img.src = Tools.fallbackTexture;
-                    onload(img);
+                    onLoad(img);
                 } else {
                 } else {
-                    onerror();
+                    onError("Error while trying to load image: " + url, err);
                 }
                 }
             };
             };
 
 
@@ -541,7 +541,7 @@
          * Load a script (identified by an url). When the url returns, the 
          * Load a script (identified by an url). When the url returns, the 
          * content of this file is added into a new script element, attached to the DOM (body element)
          * content of this file is added into a new script element, attached to the DOM (body element)
          */
          */
-        public static LoadScript(scriptUrl: string, onSuccess: () => void, onError?: () => void) {
+        public static LoadScript(scriptUrl: string, onSuccess: () => void, onError?: (message?: string, exception?: any) => void) {
             var head = document.getElementsByTagName('head')[0];
             var head = document.getElementsByTagName('head')[0];
             var script = document.createElement('script');
             var script = document.createElement('script');
             script.type = 'text/javascript';
             script.type = 'text/javascript';
@@ -554,9 +554,9 @@
                 }
                 }
             };
             };
 
 
-            script.onerror = () => {
+            script.onerror = (e) => {
                 if (onError) {
                 if (onError) {
-                    onError();
+                    onError("Unable to load script", e);
                 }
                 }
             };
             };
 
 

+ 43 - 37
src/babylon.engine.ts

@@ -105,7 +105,7 @@
     }
     }
 
 
     var partialLoad = (url: string, index: number, loadedImages: any, scene,
     var partialLoad = (url: string, index: number, loadedImages: any, scene,
-        onfinish: (images: HTMLImageElement[]) => void, onErrorCallBack: () => void = null) => {
+        onfinish: (images: HTMLImageElement[]) => void, onErrorCallBack: (message?: string, exception?: any) => void = null) => {
 
 
         var img: HTMLImageElement;
         var img: HTMLImageElement;
 
 
@@ -122,13 +122,13 @@
             }
             }
         };
         };
 
 
-        var onerror = () => {
+        var onerror = (message?: string, exception?: any) => {
             if (scene) {
             if (scene) {
                 scene._removePendingData(img);
                 scene._removePendingData(img);
             }
             }
 
 
             if (onErrorCallBack) {
             if (onErrorCallBack) {
-                onErrorCallBack();
+                onErrorCallBack(message, exception);
             }
             }
         };
         };
 
 
@@ -139,7 +139,7 @@
     }
     }
 
 
     var cascadeLoad = (rootUrl: string, scene,
     var cascadeLoad = (rootUrl: string, scene,
-        onfinish: (images: HTMLImageElement[]) => void, files: string[], onError: () => void = null) => {
+        onfinish: (images: HTMLImageElement[]) => void, files: string[], onError: (message?: string, exception?: any) => void = null) => {
 
 
         var loadedImages: any = [];
         var loadedImages: any = [];
         loadedImages._internalCount = 0;
         loadedImages._internalCount = 0;
@@ -552,7 +552,7 @@
         /**
         /**
          * Observable event triggered each time the canvas gains focus
          * Observable event triggered each time the canvas gains focus
          */
          */
-        public onCanvasFocusObservable = new Observable<Engine>();        
+        public onCanvasFocusObservable = new Observable<Engine>();
 
 
         /**
         /**
          * Observable event triggered each time the canvas receives pointerout event
          * Observable event triggered each time the canvas receives pointerout event
@@ -605,14 +605,14 @@
 
 
         public static audioEngine: AudioEngine;
         public static audioEngine: AudioEngine;
 
 
-        
+
         // Focus
         // Focus
         private _onFocus: () => void;
         private _onFocus: () => void;
-        private _onBlur: () => void;       
+        private _onBlur: () => void;
         private _onCanvasPointerOut: () => void;
         private _onCanvasPointerOut: () => void;
         private _onCanvasBlur: () => void;
         private _onCanvasBlur: () => void;
         private _onCanvasFocus: () => void;
         private _onCanvasFocus: () => void;
-        
+
         private _onFullscreenChange: () => void;
         private _onFullscreenChange: () => void;
         private _onPointerLockChange: () => void;
         private _onPointerLockChange: () => void;
 
 
@@ -821,18 +821,18 @@
                 if (!this._gl) {
                 if (!this._gl) {
                     throw new Error("WebGL not supported");
                     throw new Error("WebGL not supported");
                 }
                 }
-    
+
                 this._onCanvasFocus = () => {
                 this._onCanvasFocus = () => {
                     this.onCanvasFocusObservable.notifyObservers(this);
                     this.onCanvasFocusObservable.notifyObservers(this);
                 }
                 }
-    
+
                 this._onCanvasBlur = () => {
                 this._onCanvasBlur = () => {
                     this.onCanvasBlurObservable.notifyObservers(this);
                     this.onCanvasBlurObservable.notifyObservers(this);
                 }
                 }
-    
+
                 canvas.addEventListener("focus", this._onCanvasFocus);
                 canvas.addEventListener("focus", this._onCanvasFocus);
                 canvas.addEventListener("blur", this._onCanvasBlur);
                 canvas.addEventListener("blur", this._onCanvasBlur);
-    
+
                 this._onBlur = () => {
                 this._onBlur = () => {
                     if (this.disablePerformanceMonitorInBackground) {
                     if (this.disablePerformanceMonitorInBackground) {
                         this._performanceMonitor.disable();
                         this._performanceMonitor.disable();
@@ -868,7 +868,7 @@
 
 
                     this._onContextRestored = (evt: Event) => {
                     this._onContextRestored = (evt: Event) => {
                         // Adding a timeout to avoid race condition at browser level
                         // Adding a timeout to avoid race condition at browser level
-                        setTimeout(()=> {
+                        setTimeout(() => {
                             // Rebuild gl context
                             // Rebuild gl context
                             this._initGLContext();
                             this._initGLContext();
 
 
@@ -894,7 +894,7 @@
 
 
                     canvas.addEventListener("webglcontextlost", this._onContextLost, false);
                     canvas.addEventListener("webglcontextlost", this._onContextLost, false);
                     canvas.addEventListener("webglcontextrestored", this._onContextRestored, false);
                     canvas.addEventListener("webglcontextrestored", this._onContextRestored, false);
-                }                
+                }
             } else {
             } else {
                 this._gl = <WebGLRenderingContext>canvasOrContext;
                 this._gl = <WebGLRenderingContext>canvasOrContext;
                 this._renderingCanvas = this._gl.canvas
                 this._renderingCanvas = this._gl.canvas
@@ -1106,7 +1106,7 @@
                     this._caps.drawBuffersExtension = true;
                     this._caps.drawBuffersExtension = true;
                     this._gl.drawBuffers = drawBuffersExtension.drawBuffersWEBGL.bind(drawBuffersExtension);
                     this._gl.drawBuffers = drawBuffersExtension.drawBuffersWEBGL.bind(drawBuffersExtension);
                     this._gl.DRAW_FRAMEBUFFER = this._gl.FRAMEBUFFER;
                     this._gl.DRAW_FRAMEBUFFER = this._gl.FRAMEBUFFER;
-                    
+
                     for (var i = 0; i < 16; i++) {
                     for (var i = 0; i < 16; i++) {
                         this._gl["COLOR_ATTACHMENT" + i + "_WEBGL"] = drawBuffersExtension["COLOR_ATTACHMENT" + i + "_WEBGL"];
                         this._gl["COLOR_ATTACHMENT" + i + "_WEBGL"] = drawBuffersExtension["COLOR_ATTACHMENT" + i + "_WEBGL"];
                     }
                     }
@@ -1408,7 +1408,7 @@
 
 
                     // Present
                     // Present
                     this.endFrame();
                     this.endFrame();
-                }  
+                }
             }
             }
 
 
             if (this._activeRenderLoops.length > 0) {
             if (this._activeRenderLoops.length > 0) {
@@ -1595,15 +1595,15 @@
         }
         }
 
 
         // WebVR functions
         // WebVR functions
-        public isVRDevicePresent() : boolean {
+        public isVRDevicePresent(): boolean {
             return !!this._vrDisplay;
             return !!this._vrDisplay;
         }
         }
 
 
-        public getVRDevice() : any {
+        public getVRDevice(): any {
             return this._vrDisplay;
             return this._vrDisplay;
         }
         }
 
 
-        public initWebVR(): Observable<{vrDisplay: any, vrSupported: any}> {
+        public initWebVR(): Observable<{ vrDisplay: any, vrSupported: any }> {
             var notifyObservers = () => {
             var notifyObservers = () => {
                 var eventArgs = {
                 var eventArgs = {
                     vrDisplay: this._vrDisplay,
                     vrDisplay: this._vrDisplay,
@@ -1623,14 +1623,14 @@
                     this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
                     this._frameHandler = Tools.QueueNewFrame(this._bindedRenderFunction);
                     notifyObservers();
                     notifyObservers();
                 };
                 };
-                this._onVrDisplayPresentChange = () => {                    
+                this._onVrDisplayPresentChange = () => {
                     this._vrExclusivePointerMode = this._vrDisplay && this._vrDisplay.isPresenting;
                     this._vrExclusivePointerMode = this._vrDisplay && this._vrDisplay.isPresenting;
                 }
                 }
                 window.addEventListener('vrdisplayconnect', this._onVrDisplayConnect);
                 window.addEventListener('vrdisplayconnect', this._onVrDisplayConnect);
                 window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
                 window.addEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
                 window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
                 window.addEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
             }
             }
-            
+
             this._getVRDisplays(notifyObservers);
             this._getVRDisplays(notifyObservers);
 
 
             return this.onVRDisplayChangedObservable;
             return this.onVRDisplayChangedObservable;
@@ -1645,7 +1645,7 @@
                 var onRejected = () => {
                 var onRejected = () => {
                     this.onVRRequestPresentComplete.notifyObservers(false);
                     this.onVRRequestPresentComplete.notifyObservers(false);
                 };
                 };
-                
+
                 this.onVRRequestPresentStart.notifyObservers(this);
                 this.onVRRequestPresentStart.notifyObservers(this);
                 this._vrDisplay.requestPresent([{ source: this.getRenderingCanvas() }]).then(onResolved).catch(onRejected);
                 this._vrDisplay.requestPresent([{ source: this.getRenderingCanvas() }]).then(onResolved).catch(onRejected);
             }
             }
@@ -3268,7 +3268,7 @@
 
 
             var width = size.width || size;
             var width = size.width || size;
             var height = size.height || size;
             var height = size.height || size;
-            
+
             var textures = [];
             var textures = [];
             var attachments = []
             var attachments = []
 
 
@@ -3295,7 +3295,7 @@
 
 
                 var texture = new InternalTexture(this, InternalTexture.DATASOURCE_MULTIRENDERTARGET);
                 var texture = new InternalTexture(this, InternalTexture.DATASOURCE_MULTIRENDERTARGET);
                 var attachment = gl[this.webGLVersion > 1 ? "COLOR_ATTACHMENT" + i : "COLOR_ATTACHMENT" + i + "_WEBGL"];
                 var attachment = gl[this.webGLVersion > 1 ? "COLOR_ATTACHMENT" + i : "COLOR_ATTACHMENT" + i + "_WEBGL"];
-                
+
                 textures.push(texture);
                 textures.push(texture);
                 attachments.push(attachment);
                 attachments.push(attachment);
 
 
@@ -3548,7 +3548,7 @@
             return texture;
             return texture;
         }
         }
 
 
-        public createPrefilteredCubeTexture(rootUrl: string, scene: Scene, scale: number, offset: number, onLoad: (internalTexture: InternalTexture) => void, onError: () => void = null, format?: number, forcedExtension = null): InternalTexture {
+        public createPrefilteredCubeTexture(rootUrl: string, scene: Scene, scale: number, offset: number, onLoad: (internalTexture: InternalTexture) => void, onError: (message?: string, exception?: any) => void = null, format?: number, forcedExtension = null): InternalTexture {
             var callback = (loadData) => {
             var callback = (loadData) => {
                 if (!loadData) {
                 if (!loadData) {
                     if (onLoad) {
                     if (onLoad) {
@@ -3633,7 +3633,7 @@
             return this.createCubeTexture(rootUrl, scene, null, false, callback, onError, format, forcedExtension);
             return this.createCubeTexture(rootUrl, scene, null, false, callback, onError, format, forcedExtension);
         }
         }
 
 
-        public createCubeTexture(rootUrl: string, scene: Scene, files: string[], noMipmap?: boolean, onLoad: (data?: any) => void = null, onError: () => void = null, format?: number, forcedExtension = null): InternalTexture {
+        public createCubeTexture(rootUrl: string, scene: Scene, files: string[], noMipmap?: boolean, onLoad: (data?: any) => void = null, onError: (message?: string, exception?: any) => void = null, format?: number, forcedExtension = null): InternalTexture {
             var gl = this._gl;
             var gl = this._gl;
 
 
             var texture = new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
             var texture = new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
@@ -3658,6 +3658,12 @@
                 isDDS = (extension === ".dds");
                 isDDS = (extension === ".dds");
             }
             }
 
 
+            let onerror = (request, exception) => {
+                if (onError) {
+                    onError(request.status + " " + request.statusText, exception)
+                }
+            }
+
             if (isKTX) {
             if (isKTX) {
                 Tools.LoadFile(rootUrl, data => {
                 Tools.LoadFile(rootUrl, data => {
                     var ktx = new Internals.KhronosTextureContainer(data, 6);
                     var ktx = new Internals.KhronosTextureContainer(data, 6);
@@ -3681,7 +3687,7 @@
                     texture.width = ktx.pixelWidth;
                     texture.width = ktx.pixelWidth;
                     texture.height = ktx.pixelHeight;
                     texture.height = ktx.pixelHeight;
                     texture.isReady = true;
                     texture.isReady = true;
-                }, null, null, true, onError);
+                }, null, null, true, onerror);
             } else if (isDDS) {
             } else if (isDDS) {
                 Tools.LoadFile(rootUrl, data => {
                 Tools.LoadFile(rootUrl, data => {
                     var info = Internals.DDSTools.GetDDSInfo(data);
                     var info = Internals.DDSTools.GetDDSInfo(data);
@@ -3714,7 +3720,7 @@
                     if (onLoad) {
                     if (onLoad) {
                         onLoad({ isDDS: true, width: info.width, info, data, texture });
                         onLoad({ isDDS: true, width: info.width, info, data, texture });
                     }
                     }
-                }, null, null, true, onError);
+                }, null, null, true, onerror);
             } else {
             } else {
                 cascadeLoad(rootUrl, scene, imgs => {
                 cascadeLoad(rootUrl, scene, imgs => {
                     var width = this.needPOTTextures ? Tools.GetExponentOfTwo(imgs[0].width, this._caps.maxCubemapTextureSize) : imgs[0].width;
                     var width = this.needPOTTextures ? Tools.GetExponentOfTwo(imgs[0].width, this._caps.maxCubemapTextureSize) : imgs[0].width;
@@ -3889,7 +3895,7 @@
             callback: (ArrayBuffer: ArrayBuffer) => ArrayBufferView[],
             callback: (ArrayBuffer: ArrayBuffer) => ArrayBufferView[],
             mipmmapGenerator: ((faces: ArrayBufferView[]) => ArrayBufferView[][]),
             mipmmapGenerator: ((faces: ArrayBufferView[]) => ArrayBufferView[][]),
             onLoad: () => void = null,
             onLoad: () => void = null,
-            onError: () => void = null,
+            onError: (message?: string, exception?: any) => void = null,
             samplingMode = Texture.TRILINEAR_SAMPLINGMODE,
             samplingMode = Texture.TRILINEAR_SAMPLINGMODE,
             invertY = false): InternalTexture {
             invertY = false): InternalTexture {
 
 
@@ -3899,10 +3905,10 @@
             texture.url = url;
             texture.url = url;
             this._internalTexturesCache.push(texture);
             this._internalTexturesCache.push(texture);
 
 
-            var onerror = () => {
+            var onerror = (request, exception) => {
                 scene._removePendingData(texture);
                 scene._removePendingData(texture);
                 if (onError) {
                 if (onError) {
-                    onError();
+                    onError(request.status + " " + request.statusText, exception);
                 }
                 }
             };
             };
 
 
@@ -3956,7 +3962,7 @@
 
 
             Tools.LoadFile(url, data => {
             Tools.LoadFile(url, data => {
                 internalCallback(data);
                 internalCallback(data);
-            }, onerror, scene.database, true);
+            }, undefined, scene.database, true, onerror);
 
 
             return texture;
             return texture;
         };
         };
@@ -4208,7 +4214,7 @@
 
 
                 if (internalTexture._cachedWrapU !== texture.wrapU) {
                 if (internalTexture._cachedWrapU !== texture.wrapU) {
                     internalTexture._cachedWrapU = texture.wrapU;
                     internalTexture._cachedWrapU = texture.wrapU;
-                    
+
                     switch (texture.wrapU) {
                     switch (texture.wrapU) {
                         case Texture.WRAP_ADDRESSMODE:
                         case Texture.WRAP_ADDRESSMODE:
                             this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.REPEAT);
                             this._gl.texParameteri(this._gl.TEXTURE_2D, this._gl.TEXTURE_WRAP_S, this._gl.REPEAT);
@@ -4270,7 +4276,7 @@
             var value = texture.anisotropicFilteringLevel;
             var value = texture.anisotropicFilteringLevel;
 
 
 
 
-            if (internalTexture.samplingMode !== Texture.LINEAR_LINEAR_MIPNEAREST 
+            if (internalTexture.samplingMode !== Texture.LINEAR_LINEAR_MIPNEAREST
                 && internalTexture.samplingMode !== Texture.LINEAR_LINEAR_MIPLINEAR
                 && internalTexture.samplingMode !== Texture.LINEAR_LINEAR_MIPLINEAR
                 && internalTexture.samplingMode !== Texture.LINEAR_LINEAR) {
                 && internalTexture.samplingMode !== Texture.LINEAR_LINEAR) {
                 value = 1; // Forcing the anisotropic to 1 because else webgl will force filters to linear
                 value = 1; // Forcing the anisotropic to 1 because else webgl will force filters to linear
@@ -4429,7 +4435,7 @@
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
             window.removeEventListener('vrdisplaypointerrestricted', this._onVRDisplayPointerRestricted);
             window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
             window.removeEventListener('vrdisplaypointerunrestricted', this._onVRDisplayPointerUnrestricted);
             this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
             this._renderingCanvas.removeEventListener("focus", this._onCanvasFocus);
-            this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);            
+            this._renderingCanvas.removeEventListener("blur", this._onCanvasBlur);
             this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
             this._renderingCanvas.removeEventListener("pointerout", this._onCanvasBlur);
 
 
             if (!this._doNotHandleContextLost) {
             if (!this._doNotHandleContextLost) {
@@ -4444,13 +4450,13 @@
             document.removeEventListener("mspointerlockchange", this._onPointerLockChange);
             document.removeEventListener("mspointerlockchange", this._onPointerLockChange);
             document.removeEventListener("mozpointerlockchange", this._onPointerLockChange);
             document.removeEventListener("mozpointerlockchange", this._onPointerLockChange);
             document.removeEventListener("webkitpointerlockchange", this._onPointerLockChange);
             document.removeEventListener("webkitpointerlockchange", this._onPointerLockChange);
-            
+
             if (this._onVrDisplayConnect) {
             if (this._onVrDisplayConnect) {
                 window.removeEventListener('vrdisplayconnect', this._onVrDisplayConnect);
                 window.removeEventListener('vrdisplayconnect', this._onVrDisplayConnect);
                 window.removeEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
                 window.removeEventListener('vrdisplaydisconnect', this._onVrDisplayDisconnect);
                 window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
                 window.removeEventListener('vrdisplaypresentchange', this._onVrDisplayPresentChange);
                 this._onVrDisplayConnect = undefined;
                 this._onVrDisplayConnect = undefined;
-                this._onVrDisplayDisconnect = undefined;                
+                this._onVrDisplayDisconnect = undefined;
             }
             }
 
 
             // Remove from Instances
             // Remove from Instances