Explorar o código

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

David Catuhe %!s(int64=8) %!d(string=hai) anos
pai
achega
bb1cb26990

+ 53 - 45
src/Loading/Plugins/babylon.babylonFileLoader.ts

@@ -38,7 +38,7 @@
 
             return false;
         },
-        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]): boolean => {
+        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[], onError?: (message: string, exception?: any) => void): boolean => {
             // Entire method running in try block, so ALWAYS logs as far as it got, only actually writes details
             // when SceneLoader.debugLogging = true (default), or exception encountered.
             // Everything stored in var log instead of writing separate lines to support only writing in exception,
@@ -53,7 +53,7 @@
                 } else if (!Array.isArray(meshesNames)) {
                     meshesNames = [meshesNames];
                 }
-                
+
                 if (parsedData.meshes !== undefined && parsedData.meshes !== null) {
                     var loadedSkeletonsIds = [];
                     var loadedMaterialsIds = [];
@@ -68,7 +68,7 @@
                                 // Remove found mesh name from list.
                                 delete meshesNames[meshesNames.indexOf(parsedMesh.name)];
                             }
-        
+
                             //Geometry?
                             if (parsedMesh.geometryId !== undefined && parsedMesh.geometryId !== null) {
                                 //does the file contain geometries?
@@ -118,7 +118,7 @@
                                     }
                                 }
                             }
-        
+
                             // Material ?
                             if (parsedMesh.materialId) {
                                 var materialFound = (loadedMaterialsIds.indexOf(parsedMesh.materialId) !== -1);
@@ -151,7 +151,7 @@
                                     }
                                 }
                             }
-        
+
                             // Skeleton ?
                             if (parsedMesh.skeletonId > -1 && parsedData.skeletons !== undefined && parsedData.skeletons !== null) {
                                 var skeletonAlreadyLoaded = (loadedSkeletonsIds.indexOf(parsedMesh.skeletonId) > -1);
@@ -173,7 +173,7 @@
                             log += "\n\tMesh " + mesh.toString(fullDetails);
                         }
                     }
-        
+
                     // Connecting parents
                     var currentMesh: AbstractMesh;
                     for (index = 0, cache = scene.meshes.length; index < cache; index++) {
@@ -183,7 +183,7 @@
                             currentMesh._waitingParentId = undefined;
                         }
                     }
-        
+
                     // freeze and compute world matrix application
                     for (index = 0, cache = scene.meshes.length; index < cache; index++) {
                         currentMesh = scene.meshes[index];
@@ -195,7 +195,7 @@
                         }
                     }
                 }
-    
+
                 // Particles
                 if (parsedData.particleSystems !== undefined && parsedData.particleSystems !== null) {
                     for (index = 0, cache = parsedData.particleSystems.length; index < cache; index++) {
@@ -209,17 +209,21 @@
                 return true;
 
             } catch (err) {
-                Tools.Log(logOperation("importMesh", parsedData ? parsedData.producer : "Unknown") + log);
-                log = null;
-                throw err;
-
+                let msg = logOperation("importMesh", parsedData ? parsedData.producer : "Unknown") + log;
+                if (onError) {
+                    onError(msg, err);
+                } else {
+                    Tools.Log(msg);
+                    log = null;
+                    throw err;
+                }
             } finally {
                 if (log !== null && SceneLoader.loggingLevel !== SceneLoader.NO_LOGGING) {
                     Tools.Log(logOperation("importMesh", parsedData ? parsedData.producer : "Unknown") + (SceneLoader.loggingLevel !== SceneLoader.MINIMAL_LOGGING ? log : ""));
                 }
             }
         },
-        load: (scene: Scene, data: string, rootUrl: string): boolean => {
+        load: (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void): boolean => {
             // Entire method running in try block, so ALWAYS logs as far as it got, only actually writes details
             // when SceneLoader.debugLogging = true (default), or exception encountered.
             // Everything stored in var log instead of writing separate lines to support only writing in exception,
@@ -229,7 +233,7 @@
                 var parsedData = JSON.parse(data);
                 log = "";
                 var fullDetails = SceneLoader.loggingLevel === SceneLoader.DETAILED_LOGGING;
-                
+
                 // Scene
                 if (parsedData.useDelayedTextureLoading !== undefined && parsedData.useDelayedTextureLoading !== null) {
                     scene.useDelayedTextureLoading = parsedData.useDelayedTextureLoading && !BABYLON.SceneLoader.ForceFullSceneLoadingForIncremental;
@@ -246,7 +250,7 @@
                 if (parsedData.gravity !== undefined && parsedData.gravity !== null) {
                     scene.gravity = BABYLON.Vector3.FromArray(parsedData.gravity);
                 }
-                
+
                 // Fog
                 if (parsedData.fogMode && parsedData.fogMode !== 0) {
                     scene.fogMode = parsedData.fogMode;
@@ -262,7 +266,7 @@
                         case 3: log += "linear\n"; break;
                     }
                 }
-                
+
                 //Physics
                 if (parsedData.physicsEnabled) {
                     var physicsPlugin;
@@ -276,12 +280,12 @@
                     var physicsGravity = parsedData.physicsGravity ? BABYLON.Vector3.FromArray(parsedData.physicsGravity) : null;
                     scene.enablePhysics(physicsGravity, physicsPlugin);
                 }
-                
+
                 // Metadata
                 if (parsedData.metadata !== undefined && parsedData.metadata !== null) {
                     scene.metadata = parsedData.metadata;
                 }
-                
+
                 //collisions, if defined. otherwise, default is true
                 if (parsedData.collisionsEnabled !== undefined && parsedData.collisionsEnabled !== null) {
                     scene.collisionsEnabled = parsedData.collisionsEnabled;
@@ -299,7 +303,7 @@
                         log += "\n\t\t" + light.toString(fullDetails);
                     }
                 }
-    
+
                 // Animations
                 if (parsedData.animations !== undefined && parsedData.animations !== null) {
                     for (index = 0, cache = parsedData.animations.length; index < cache; index++) {
@@ -314,7 +318,7 @@
                 if (parsedData.autoAnimate) {
                     scene.beginAnimation(scene, parsedData.autoAnimateFrom, parsedData.autoAnimateTo, parsedData.autoAnimateLoop, parsedData.autoAnimateSpeed || 1.0);
                 }
-    
+
                 // Materials
                 if (parsedData.materials !== undefined && parsedData.materials !== null) {
                     for (index = 0, cache = parsedData.materials.length; index < cache; index++) {
@@ -340,7 +344,7 @@
                         var parsedManager = MorphTargetManager.Parse(managerData, scene);
                     }
                 }
-    
+
                 // Skeletons
                 if (parsedData.skeletons !== undefined && parsedData.skeletons !== null) {
                     for (index = 0, cache = parsedData.skeletons.length; index < cache; index++) {
@@ -350,7 +354,7 @@
                         log += "\n\t\t" + skeleton.toString(fullDetails);
                     }
                 }
-    
+
                 // Geometries
                 var geometries = parsedData.geometries;
                 if (geometries !== undefined && geometries !== null) {
@@ -362,7 +366,7 @@
                             Geometry.Primitives.Box.Parse(parsedBox, scene);
                         }
                     }
-    
+
                     // Spheres
                     var spheres = geometries.spheres;
                     if (spheres !== undefined && spheres !== null) {
@@ -371,7 +375,7 @@
                             Geometry.Primitives.Sphere.Parse(parsedSphere, scene);
                         }
                     }
-    
+
                     // Cylinders
                     var cylinders = geometries.cylinders;
                     if (cylinders !== undefined && cylinders !== null) {
@@ -380,7 +384,7 @@
                             Geometry.Primitives.Cylinder.Parse(parsedCylinder, scene);
                         }
                     }
-    
+
                     // Toruses
                     var toruses = geometries.toruses;
                     if (toruses !== undefined && toruses !== null) {
@@ -389,7 +393,7 @@
                             Geometry.Primitives.Torus.Parse(parsedTorus, scene);
                         }
                     }
-    
+
                     // Grounds
                     var grounds = geometries.grounds;
                     if (grounds !== undefined && grounds !== null) {
@@ -398,7 +402,7 @@
                             Geometry.Primitives.Ground.Parse(parsedGround, scene);
                         }
                     }
-    
+
                     // Planes
                     var planes = geometries.planes;
                     if (planes !== undefined && planes !== null) {
@@ -407,7 +411,7 @@
                             Geometry.Primitives.Plane.Parse(parsedPlane, scene);
                         }
                     }
-    
+
                     // TorusKnots
                     var torusKnots = geometries.torusKnots;
                     if (torusKnots !== undefined && torusKnots !== null) {
@@ -416,7 +420,7 @@
                             Geometry.Primitives.TorusKnot.Parse(parsedTorusKnot, scene);
                         }
                     }
-    
+
                     // VertexData
                     var vertexData = geometries.vertexData;
                     if (vertexData !== undefined && vertexData !== null) {
@@ -426,7 +430,7 @@
                         }
                     }
                 }
-    
+
                 // Meshes
                 if (parsedData.meshes !== undefined && parsedData.meshes !== null) {
                     for (index = 0, cache = parsedData.meshes.length; index < cache; index++) {
@@ -436,7 +440,7 @@
                         log += "\n\t\t" + mesh.toString(fullDetails);
                     }
                 }
-    
+
                 // Cameras
                 if (parsedData.cameras !== undefined && parsedData.cameras !== null) {
                     for (index = 0, cache = parsedData.cameras.length; index < cache; index++) {
@@ -449,7 +453,7 @@
                 if (parsedData.activeCameraID !== undefined && parsedData.activeCameraID !== null) {
                     scene.setActiveCameraByID(parsedData.activeCameraID);
                 }
-    
+
                 // Browsing all the graph to connect the dots
                 for (index = 0, cache = scene.cameras.length; index < cache; index++) {
                     var camera = scene.cameras[index];
@@ -466,7 +470,7 @@
                         light._waitingParentId = undefined;
                     }
                 }
-    
+
                 // Sounds
                 var loadedSounds: Sound[] = [];
                 var loadedSound: Sound;
@@ -489,7 +493,7 @@
                 }
 
                 loadedSounds = [];
-    
+
                 // Connect parents & children and parse actions
                 for (index = 0, cache = scene.meshes.length; index < cache; index++) {
                     var mesh = scene.meshes[index];
@@ -502,7 +506,7 @@
                         mesh._waitingActions = undefined;
                     }
                 }
-    
+
                 // freeze world matrix application
                 for (index = 0, cache = scene.meshes.length; index < cache; index++) {
                     var currentMesh = scene.meshes[index];
@@ -513,7 +517,7 @@
                         currentMesh.computeWorldMatrix(true);
                     }
                 }
-    
+
                 // Particles Systems
                 if (parsedData.particleSystems !== undefined && parsedData.particleSystems !== null) {
                     for (index = 0, cache = parsedData.particleSystems.length; index < cache; index++) {
@@ -521,7 +525,7 @@
                         ParticleSystem.Parse(parsedParticleSystem, scene, rootUrl);
                     }
                 }
-    
+
                 // Lens flares
                 if (parsedData.lensFlareSystems !== undefined && parsedData.lensFlareSystems !== null) {
                     for (index = 0, cache = parsedData.lensFlareSystems.length; index < cache; index++) {
@@ -529,7 +533,7 @@
                         LensFlareSystem.Parse(parsedLensFlareSystem, scene, rootUrl);
                     }
                 }
-    
+
                 // Shadows
                 if (parsedData.shadowGenerators !== undefined && parsedData.shadowGenerators !== null) {
                     for (index = 0, cache = parsedData.shadowGenerators.length; index < cache; index++) {
@@ -537,7 +541,7 @@
                         ShadowGenerator.Parse(parsedShadowGenerator, scene);
                     }
                 }
-                
+
                 // Lights exclusions / inclusions
                 for (index = 0, cache = scene.lights.length; index < cache; index++) {
                     var light = scene.lights[index];
@@ -567,20 +571,24 @@
                         light._includedOnlyMeshesIds = [];
                     }
                 }
-    
+
                 // Actions (scene)
                 if (parsedData.actions !== undefined && parsedData.actions !== null) {
                     ActionManager.Parse(parsedData.actions, null, scene);
                 }
-    
+
                 // Finish
                 return true;
 
             } catch (err) {
-                Tools.Log(logOperation("importScene", parsedData ? parsedData.producer : "Unknown") + log);
-                log = null;
-                throw err;
-
+                let msg = logOperation("importScene", parsedData ? parsedData.producer : "Unknown") + log;
+                if (onError) {
+                    onError(msg, err);
+                } else {
+                    Tools.Log(msg);
+                    log = null;
+                    throw err;
+                }
             } finally {
                 if (log !== null && SceneLoader.loggingLevel !== SceneLoader.NO_LOGGING) {
                     Tools.Log(logOperation("importScene", parsedData ? parsedData.producer : "Unknown") + (SceneLoader.loggingLevel !== SceneLoader.MINIMAL_LOGGING ? log : ""));

+ 37 - 14
src/Loading/babylon.sceneLoader.ts

@@ -8,8 +8,8 @@
     export interface ISceneLoaderPlugin {
         name: string;
         extensions: string | ISceneLoaderPluginExtensions;
-        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[], onError: (message: string) => void) => boolean;
-        load: (scene: Scene, data: string, rootUrl: string, onError: (message: string) => void) => boolean;
+        importMesh: (meshesNames: any, scene: Scene, data: any, rootUrl: string, meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[], onError?: (message: string, exception?: any) => void) => boolean;
+        load: (scene: Scene, data: string, rootUrl: string, onError?: (message: string, exception?: any) => void) => boolean;
         canDirectLoad?: (data: string) => boolean;
     }
 
@@ -17,7 +17,7 @@
         name: string;
         extensions: string | ISceneLoaderPluginExtensions;
         importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
-        loadAsync: (scene: Scene, data: string, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        loadAsync: (scene: Scene, data: string, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string, exception?: any) => void) => void;
         canDirectLoad?: (data: string) => boolean;
     }
 
@@ -80,7 +80,7 @@
 
         public static set CleanBoneMatrixWeights(value: boolean) {
             SceneLoader._CleanBoneMatrixWeights = value;
-        }        
+        }
 
         // Members
         public static OnPluginActivatedObservable = new Observable<ISceneLoaderPlugin | ISceneLoaderPluginAsync>();
@@ -233,8 +233,12 @@
             scene._addPendingData(loadingToken);
 
             var errorHandler = (message?: string, exception?: any) => {
+                let errorMessage = "Unable to import meshes from " + rootUrl + sceneFilename + (message ? ": " + message : "");
                 if (onError) {
-                    onError(scene, "Unable to import meshes from " + rootUrl + sceneFilename + (message ? ": " + message : ""));
+                    onError(scene, errorMessage, exception);
+                } else {
+                    Tools.Error(errorMessage);
+                    // should the exception be thrown?
                 }
                 scene._removePendingData(loadingToken);
             };
@@ -256,18 +260,29 @@
                     }
 
                     if (onSuccess) {
-                        scene.importedMeshesFiles.push(rootUrl + sceneFilename);
-                        onSuccess(meshes, particleSystems, skeletons);
-                        scene._removePendingData(loadingToken);
+                        // wrap onSuccess with try-catch to know if something went wrong.
+                        try {
+                            scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                            onSuccess(meshes, particleSystems, skeletons);
+                            scene._removePendingData(loadingToken);
+                        } catch (e) {
+                            let message = 'Error in onSuccess callback.';
+                            errorHandler(message, e);
+                        }
                     }
                 }
                 else {
                     var asyncedPlugin = <ISceneLoaderPluginAsync>plugin;
                     asyncedPlugin.importMeshAsync(meshNames, scene, data, rootUrl, (meshes, particleSystems, skeletons) => {
                         if (onSuccess) {
-                            scene.importedMeshesFiles.push(rootUrl + sceneFilename);
-                            onSuccess(meshes, particleSystems, skeletons);
-                            scene._removePendingData(loadingToken);
+                            try {
+                                scene.importedMeshesFiles.push(rootUrl + sceneFilename);
+                                onSuccess(meshes, particleSystems, skeletons);
+                                scene._removePendingData(loadingToken);
+                            } catch (e) {
+                                let message = 'Error in onSuccess callback.';
+                                errorHandler(message, e);
+                            }
                         }
                     }, progressHandler, errorHandler);
                 }
@@ -310,8 +325,12 @@
             scene._addPendingData(loadingToken);
 
             var errorHandler = (message?: string, exception?: any) => {
+                let errorMessage = "Unable to load from " + rootUrl + sceneFilename + (message ? ": " + message : "");
                 if (onError) {
-                    onError(scene, "Unable to load from " + rootUrl + sceneFilename + (message ? ": " + message : ""));
+                    onError(scene, errorMessage, exception);
+                } else {
+                    Tools.Error(errorMessage);
+                    // should the exception be thrown?
                 }
                 scene._removePendingData(loadingToken);
                 scene.getEngine().hideLoadingUI();
@@ -331,7 +350,11 @@
                     }
 
                     if (onSuccess) {
-                        onSuccess(scene);
+                        try {
+                            onSuccess(scene);
+                        } catch (e) {
+                            errorHandler("Error in onSuccess callback", e);
+                        }
                     }
 
                     scene.loadingPluginName = plugin.name;
@@ -342,7 +365,7 @@
                         if (onSuccess) {
                             onSuccess(scene);
                         }
-                        
+
                         scene.loadingPluginName = plugin.name;
                         scene._removePendingData(loadingToken);
                     }, progressHandler, errorHandler);

+ 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);
         }
 
-        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);
 
             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 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);
 
             if (!url) {
@@ -436,7 +436,7 @@ module BABYLON {
             serializationObject.customType = "BABYLON.HDRCubeTexture";
             serializationObject.noMipmap = this._noMipmap;
             serializationObject.isBlocking = this._isBlocking;
-            
+
             return serializationObject;
         }
 

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

@@ -1,12 +1,12 @@
 module BABYLON {
     export class Texture extends BaseTexture {
         // 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 BILINEAR_SAMPLINGMODE = 2;
         public static LINEAR_LINEAR_MIPNEAREST = 2; // Bilinear is mag = linear and min = linear and mip = nearest
-        
+
         public static TRILINEAR_SAMPLINGMODE = 3;
         public static LINEAR_LINEAR_MIPLINEAR = 3; // Trilinear is mag = linear and min = linear and mip = linear
 
@@ -103,7 +103,7 @@
             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);
 
             this.name = url;
@@ -270,13 +270,13 @@
                 this.uScale === this._cachedUScale &&
                 this.vScale === this._cachedVScale &&
                 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;
                     }
+                } else {
+                    return this._cachedTextureMatrix;
+                }
             }
 
             if (!this._cachedTextureMatrix) {
@@ -317,7 +317,7 @@
                     Matrix.IdentityToRef(this._cachedTextureMatrix);
                     break;
             }
-            
+
             scene.markAllMaterialsAsDirty(Material.TextureDirtyFlag, (mat) => {
                 return (mat.getActiveTextures().indexOf(this) !== -1);
             });
@@ -340,7 +340,7 @@
 
         public serialize(): any {
             var serializationObject = super.serialize();
-            
+
             if (typeof this._buffer === "string" && this._buffer.substr(0, 5) === "data:") {
                 serializationObject.base64String = this._buffer;
                 serializationObject.name = serializationObject.name.replace("data:", "");
@@ -371,10 +371,10 @@
         }
 
         public static Parse(parsedTexture: any, scene: Scene, rootUrl: string): BaseTexture {
-            if (parsedTexture.customType) { 
+            if (parsedTexture.customType) {
                 var customTexture = Tools.Instantiate(parsedTexture.customType);
                 // 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 (parsedCustomTexture._samplingMode !== parsedTexture.samplingMode) {
                         parsedCustomTexture.updateSamplingMode(parsedTexture.samplingMode);
@@ -417,7 +417,7 @@
 
             // Update Sampling Mode
             if (parsedTexture.samplingMode) {
-                var sampling:number = parsedTexture.samplingMode;
+                var sampling: number = parsedTexture.samplingMode;
                 if (texture._samplingMode !== sampling) {
                     texture.updateSamplingMode(sampling);
                 }
@@ -435,7 +435,7 @@
             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:") {
                 name = "data:" + name;
             }

+ 62 - 53
src/Tools/babylon.assetsManager.ts

@@ -1,10 +1,10 @@
 module BABYLON {
     export interface IAssetTask {
         onSuccess: (task: IAssetTask) => void;
-        onError: (task: IAssetTask) => void;
+        onError: (task: IAssetTask, message?: string, exception?: any) => void;
         isCompleted: boolean;
 
-        run(scene: Scene, onSuccess: () => void, onError: () => void);
+        run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void);
     }
 
     export class MeshAssetTask implements IAssetTask {
@@ -13,14 +13,14 @@
         public loadedSkeletons: Array<Skeleton>;
 
         public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask) => void;
+        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
 
         public isCompleted = false;
 
         constructor(public name: string, public meshesNames: any, public rootUrl: string, public sceneFilename: string) {
         }
 
-        public run(scene: Scene, onSuccess: () => void, onError: () => void) {
+        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
             SceneLoader.ImportMesh(this.meshesNames, this.rootUrl, this.sceneFilename, scene,
                 (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => {
                     this.loadedMeshes = meshes;
@@ -34,20 +34,20 @@
                     }
 
                     onSuccess();
-                }, null, () => {
+                }, null, (scene, message, exception) => {
                     if (this.onError) {
-                        this.onError(this);
+                        this.onError(this, message, exception);
                     }
 
-                    onError();
+                    onError(message, exception);
                 }
-                );
+            );
         }
     }
 
     export class TextFileAssetTask implements IAssetTask {
         public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask) => void;
+        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
 
         public isCompleted = false;
         public text: string;
@@ -55,7 +55,7 @@
         constructor(public name: string, public url: string) {
         }
 
-        public run(scene: Scene, onSuccess: () => void, onError: () => void) {
+        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
             Tools.LoadFile(this.url, (data) => {
 
                 this.text = data;
@@ -66,19 +66,19 @@
                 }
 
                 onSuccess();
-            }, null, scene.database, false, () => {
-                    if (this.onError) {
-                        this.onError(this);
-                    }
+            }, null, scene.database, false, (request, exception) => {
+                if (this.onError) {
+                    this.onError(this, request.status + " " + request.statusText, exception);
+                }
 
-                    onError();
-                });
+                onError(request.status + " " + request.statusText, exception);
+            });
         }
     }
 
     export class BinaryFileAssetTask implements IAssetTask {
         public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask) => void;
+        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
 
         public isCompleted = false;
         public data: ArrayBuffer;
@@ -86,7 +86,7 @@
         constructor(public name: string, public url: string) {
         }
 
-        public run(scene: Scene, onSuccess: () => void, onError: () => void) {
+        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
             Tools.LoadFile(this.url, (data) => {
 
                 this.data = data;
@@ -97,19 +97,19 @@
                 }
 
                 onSuccess();
-            }, null, scene.database, true, () => {
-                    if (this.onError) {
-                        this.onError(this);
-                    }
+            }, null, scene.database, true, (request, exception) => {
+                if (this.onError) {
+                    this.onError(this, request.status + " " + request.statusText, exception);
+                }
 
-                    onError();
-                });
+                onError(request.status + " " + request.statusText, exception);
+            });
         }
     }
 
     export class ImageAssetTask implements IAssetTask {
         public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask) => void;
+        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
 
         public isCompleted = false;
         public image: HTMLImageElement;
@@ -117,7 +117,7 @@
         constructor(public name: string, public url: string) {
         }
 
-        public run(scene: Scene, onSuccess: () => void, onError: () => void) {
+        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
             var img = new Image();
 
             Tools.SetCorsBehavior(this.url, img);
@@ -133,12 +133,12 @@
                 onSuccess();
             };
 
-            img.onerror = () => {
+            img.onerror = (err: ErrorEvent): any => {
                 if (this.onError) {
-                    this.onError(this);
+                    this.onError(this, "Error loading image", err);
                 }
 
-                onError();
+                onError("Error loading image", err);
             };
 
             img.src = this.url;
@@ -147,13 +147,13 @@
 
     export interface ITextureAssetTask extends IAssetTask {
         onSuccess: (task: ITextureAssetTask) => void;
-        onError: (task: ITextureAssetTask) => void;
+        onError: (task: ITextureAssetTask, ) => void;
         texture: Texture;
     }
 
     export class TextureAssetTask implements ITextureAssetTask {
         public onSuccess: (task: ITextureAssetTask) => void;
-        public onError: (task: ITextureAssetTask) => void;
+        public onError: (task: ITextureAssetTask, message?: string, exception?: any) => void;
 
         public isCompleted = false;
         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) {
         }
 
-        public run(scene: Scene, onSuccess: () => void, onError: () => void) {
+        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
 
             var onload = () => {
                 this.isCompleted = true;
@@ -173,12 +173,12 @@
                 onSuccess();
             };
 
-            var onerror = () => {
+            var onerror = (msg, exception) => {
                 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);
@@ -187,7 +187,7 @@
 
     export class CubeTextureAssetTask implements IAssetTask {
         public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask) => void;
+        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
 
         public isCompleted = false;
         public texture: CubeTexture;
@@ -195,7 +195,7 @@
         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 = () => {
                 this.isCompleted = true;
@@ -207,21 +207,21 @@
                 onSuccess();
             };
 
-            var onerror = () => {
+            var onerror = (msg, exception) => {
                 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);
         }
     }
 
-      export class HDRCubeTextureAssetTask implements IAssetTask {
+    export class HDRCubeTextureAssetTask implements IAssetTask {
         public onSuccess: (task: IAssetTask) => void;
-        public onError: (task: IAssetTask) => void;
+        public onError: (task: IAssetTask, message?: string, exception?: any) => void;
 
         public isCompleted = false;
         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) {
         }
 
-        public run(scene: Scene, onSuccess: () => void, onError: () => void) {
+        public run(scene: Scene, onSuccess: () => void, onError: (message?: string, exception?: any) => void) {
 
             var onload = () => {
                 this.isCompleted = true;
@@ -241,12 +241,12 @@
                 onSuccess();
             };
 
-            var onerror = () => {
+            var onerror = (message?: string, exception?: any) => {
                 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);
@@ -263,6 +263,12 @@
         public onTaskSuccess: (task: IAssetTask) => void;
         public onTaskError: (task: IAssetTask) => void;
 
+        //Observables
+
+        public onTaskSuccessObservable = new Observable<IAssetTask>();
+        public onTaskErrorObservable = new Observable<IAssetTask>();
+        public onTasksDoneObservable = new Observable<IAssetTask[]>();
+
         public useDefaultLoadingScreen = true;
 
         constructor(scene: Scene) {
@@ -318,7 +324,7 @@
 
             return task;
         }
-        
+
         private _decreaseWaitingTasksCount(): void {
             this.waitingTasksCount--;
 
@@ -336,13 +342,15 @@
                 if (this.onTaskSuccess) {
                     this.onTaskSuccess(task);
                 }
+                this.onTaskSuccessObservable.notifyObservers(task);
                 this._decreaseWaitingTasksCount();
             }, () => {
-                    if (this.onTaskError) {
-                        this.onTaskError(task);
-                    }
-                    this._decreaseWaitingTasksCount();
-                });
+                if (this.onTaskError) {
+                    this.onTaskError(task);
+                }
+                this.onTaskErrorObservable.notifyObservers(task);
+                this._decreaseWaitingTasksCount();
+            });
         }
 
         public reset(): AssetsManager {
@@ -357,6 +365,7 @@
                 if (this.onFinish) {
                     this.onFinish(this.tasks);
                 }
+                this.onTasksDoneObservable.notifyObservers(this.tasks);
                 return this;
             }
 
@@ -370,6 +379,6 @@
             }
 
             return this;
-        }     
+        }
     }
 } 

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 51 - 45
src/Tools/babylon.tools.ts


+ 43 - 37
src/babylon.engine.ts

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