瀏覽代碼

Merge pull request #3424 from bghgary/loader-progress-fix

Fix progress event in loader, Tools.LoadFile abort request, and bounding box
David Catuhe 7 年之前
父節點
當前提交
ab2c7c3805

+ 3 - 3
loaders/src/glTF/1.0/babylon.glTFLoader.ts

@@ -1561,7 +1561,7 @@ module BABYLON.GLTF1 {
             // do nothing
         }
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): boolean {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): boolean {
             scene.useRightHandedSystem = true;
 
             GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, gltfRuntime => {
@@ -1624,7 +1624,7 @@ module BABYLON.GLTF1 {
             return true;
         }
 
-        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
+        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: SceneLoaderProgressEvent) => void, onError: (message: string) => void): void {
             scene.useRightHandedSystem = true;
 
             GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, gltfRuntime => {
@@ -1688,7 +1688,7 @@ module BABYLON.GLTF1 {
             }
         };
 
-        private _loadBuffersAsync(gltfRuntime: IGLTFRuntime, onLoad: () => void, onProgress?: (event: ProgressEvent) => void): void {
+        private _loadBuffersAsync(gltfRuntime: IGLTFRuntime, onLoad: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void): void {
             var hasBuffers = false;
 
             var processBuffer = (buf: string, buffer: IGLTFBuffer) => {

+ 5 - 21
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -50,7 +50,7 @@ module BABYLON.GLTF2 {
         private _defaultSampler = {} as IGLTFSampler;
         private _rootNode: IGLTFNode;
         private _successCallback?: () => void;
-        private _progressCallback?: (event: ProgressEvent) => void;
+        private _progressCallback?: (event: SceneLoaderProgressEvent) => void;
         private _errorCallback?: (message: string, exception?: any) => void;
         private _renderReady = false;
         private _requests = new Array<GLTFLoaderRequest>();
@@ -79,22 +79,6 @@ module BABYLON.GLTF2 {
             GLTFLoaderExtension._Extensions.push(extension);
         }
 
-        // IE 11 Compatibility.
-        private static _createProgressEvent: (lengthComputable: boolean, loaded: number, total: number) => ProgressEvent =
-            (typeof (<any>window)["ProgressEvent"] === "function")
-                ? (lengthComputable, loaded, total) => {
-                    return new ProgressEvent("GLTFLoaderProgress", {
-                        lengthComputable: lengthComputable,
-                        loaded: loaded,
-                        total: total
-                    });
-                }
-                : (lengthComputable, loaded, total) => {
-                    const event = document.createEvent("ProgressEvent");
-                    event.initProgressEvent("GLTFLoaderProgress", false, false, lengthComputable, loaded, total);
-                    return event;
-                };
-
         public constructor(parent: GLTFFileLoader) {
             this._parent = parent;
         }
@@ -123,7 +107,7 @@ module BABYLON.GLTF2 {
             }
         }
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
             this._loadAsync(meshesNames, scene, data, rootUrl, () => {
                 if (onSuccess) {
                     onSuccess(this._getMeshes(), [], this._getSkeletons());
@@ -131,11 +115,11 @@ module BABYLON.GLTF2 {
             }, onProgress, onError);
         }
 
-        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
+        public loadAsync(scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
             this._loadAsync(null, scene, data, rootUrl, onSuccess, onProgress, onError);
         }
 
-        private _loadAsync(nodeNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
+        private _loadAsync(nodeNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
             this._babylonScene = scene;
             this._rootUrl = rootUrl;
             this._successCallback = onSuccess;
@@ -170,7 +154,7 @@ module BABYLON.GLTF2 {
                 total += request._total;
             }
 
-            this._progressCallback(GLTFLoader._createProgressEvent(lengthComputable, loaded, lengthComputable ? total : 0));
+            this._progressCallback(new SceneLoaderProgressEvent(lengthComputable, loaded, lengthComputable ? total : 0));
         }
 
         public _executeWhenRenderReady(func: () => void): void {

+ 4 - 4
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -36,8 +36,8 @@ module BABYLON {
     }
 
     export interface IGLTFLoader extends IDisposable {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
     }
 
     export class GLTFFileLoader implements IDisposable, ISceneLoaderPluginAsync, ISceneLoaderPluginFactory {
@@ -132,7 +132,7 @@ module BABYLON {
             }
         }
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
+        public importMeshAsync(meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
             try {
                 const loaderData = GLTFFileLoader._parse(data);
 
@@ -153,7 +153,7 @@ module BABYLON {
             }
         }
 
-        public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
+        public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void): void {
             try {
                 const loaderData = GLTFFileLoader._parse(data);
 

+ 20 - 9
src/Loading/babylon.sceneLoader.ts

@@ -1,4 +1,13 @@
 module BABYLON {
+    export class SceneLoaderProgressEvent {
+        constructor(public readonly lengthComputable: boolean, public readonly loaded: number, public readonly total: number) {
+        }
+
+        public static FromProgressEvent(event: ProgressEvent): SceneLoaderProgressEvent {
+            return new SceneLoaderProgressEvent(event.lengthComputable, event.loaded, event.total);
+        }
+    }
+
     export interface ISceneLoaderPluginExtensions {
         [extension: string]: {
             isBinary: boolean;
@@ -23,8 +32,8 @@
     export interface ISceneLoaderPluginAsync {
         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, exception?: any) => void) => void;
-        loadAsync: (scene: Scene, data: string, rootUrl: string, onSuccess?: () => void, onProgress?: (event: ProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: any, rootUrl: string, onSuccess?: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
+        loadAsync: (scene: Scene, data: string, rootUrl: string, onSuccess?: () => void, onProgress?: (event: SceneLoaderProgressEvent) => void, onError?: (message: string, exception?: any) => void) => void;
         canDirectLoad?: (data: string) => boolean;
         rewriteRootURL?: (rootUrl: string, responseURL?: string) => string;
     }
@@ -146,7 +155,7 @@
             return null;
         }
 
-        private static _loadData(rootUrl: string, sceneFilename: string, scene: Scene, onSuccess: (plugin: ISceneLoaderPlugin | ISceneLoaderPluginAsync, data: any, responseURL?: string) => void, onProgress: ((event: ProgressEvent) => void) | undefined, onError: (message: string, exception?: any) => void, pluginExtension: Nullable<string>): ISceneLoaderPlugin | ISceneLoaderPluginAsync {
+        private static _loadData(rootUrl: string, sceneFilename: string, scene: Scene, onSuccess: (plugin: ISceneLoaderPlugin | ISceneLoaderPluginAsync, data: any, responseURL?: string) => void, onProgress: ((event: SceneLoaderProgressEvent) => void) | undefined, onError: (message: string, exception?: any) => void, pluginExtension: Nullable<string>): ISceneLoaderPlugin | ISceneLoaderPluginAsync {
             var directLoad = SceneLoader._getDirectLoad(sceneFilename);
             var registeredPlugin = pluginExtension ? SceneLoader._getPluginForExtension(pluginExtension) : (directLoad ? SceneLoader._getPluginForDirectLoad(sceneFilename) : SceneLoader._getPluginForFilename(sceneFilename));
 
@@ -175,7 +184,9 @@
             };
 
             var manifestChecked = (success: any) => {
-                Tools.LoadFile(rootUrl + sceneFilename, dataCallback, onProgress, database, useArrayBuffer, (request, exception) => {
+                Tools.LoadFile(rootUrl + sceneFilename, dataCallback, onProgress ? event => {
+                    onProgress(SceneLoaderProgressEvent.FromProgressEvent(event));
+                }: undefined, database, useArrayBuffer, (request, exception) => {
                     if (request) {
                         onError(request.status + " " + request.statusText, exception);
                     }
@@ -249,7 +260,7 @@
         * @param onProgress a callback with a progress event for each file being loaded
         * @param onError a callback with the scene, a message, and possibly an exception when import fails
         */
-        public static ImportMesh(meshNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onSuccess: Nullable<(meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void> = null, onProgress: Nullable<(event: ProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
+        public static ImportMesh(meshNames: any, rootUrl: string, sceneFilename: string, scene: Scene, onSuccess: Nullable<(meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void> = null, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
             if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
                 Tools.Error("Wrong sceneFilename parameter");
                 return null;
@@ -271,7 +282,7 @@
                 scene._removePendingData(loadingToken);
             };
 
-            var progressHandler = onProgress ? (event: ProgressEvent) => {
+            var progressHandler = onProgress ? (event: SceneLoaderProgressEvent) => {
                 try {
                     onProgress(event);
                 }
@@ -332,7 +343,7 @@
         * @param onProgress a callback with a progress event for each file being loaded
         * @param onError a callback with the scene, a message, and possibly an exception when import fails
         */
-        public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onSuccess: Nullable<(scene: Scene) => void> = null, onProgress: Nullable<(event: ProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
+        public static Load(rootUrl: string, sceneFilename: any, engine: Engine, onSuccess: Nullable<(scene: Scene) => void> = null, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
             return SceneLoader.Append(rootUrl, sceneFilename, new Scene(engine), onSuccess, onProgress, onError, pluginExtension);
         }
 
@@ -345,7 +356,7 @@
         * @param onProgress a callback with a progress event for each file being loaded
         * @param onError a callback with the scene, a message, and possibly an exception when import fails
         */
-        public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onSuccess: Nullable<(scene: Scene) => void> = null, onProgress: Nullable<(event: ProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
+        public static Append(rootUrl: string, sceneFilename: any, scene: Scene, onSuccess: Nullable<(scene: Scene) => void> = null, onProgress: Nullable<(event: SceneLoaderProgressEvent) => void> = null, onError: Nullable<(scene: Scene, message: string, exception?: any) => void> = null, pluginExtension: Nullable<string> = null): Nullable<ISceneLoaderPlugin | ISceneLoaderPluginAsync> {
             if (sceneFilename.substr && sceneFilename.substr(0, 1) === "/") {
                 Tools.Error("Wrong sceneFilename parameter");
                 return null;
@@ -370,7 +381,7 @@
                 scene.getEngine().hideLoadingUI();
             };
 
-            var progressHandler = onProgress ? (event: ProgressEvent) => {
+            var progressHandler = onProgress ? (event: SceneLoaderProgressEvent) => {
                 try {
                     onProgress(event);
                 }

+ 2 - 2
src/Mesh/babylon.abstractMesh.ts

@@ -904,14 +904,14 @@
                 for (var descendant of descendants) {
                     let childMesh = <AbstractMesh>descendant;
 
+                    childMesh.computeWorldMatrix(true);
+
                     //make sure we have the needed params to get mix and max
                     if (!childMesh.getBoundingInfo || childMesh.getTotalVertices() === 0) {
                         continue;
                     }
 
-                    childMesh.computeWorldMatrix(true);
                     let childBoundingInfo = childMesh.getBoundingInfo();
-
                     let boundingBox = childBoundingInfo.boundingBox;
 
                     var minBox = boundingBox.minimumWorld;

+ 2 - 2
src/Tools/babylon.filesInput.ts

@@ -7,7 +7,7 @@
         private _engine: Engine;
         private _currentScene: Scene;
         private _sceneLoadedCallback: (sceneFile: File, scene: Scene) => void;
-        private _progressCallback: (progress: ProgressEvent) => void;
+        private _progressCallback: (progress: SceneLoaderProgressEvent) => void;
         private _additionalRenderLoopLogicCallback: () => void;
         private _textureLoadingCallback: (remaining: number) => void;
         private _startingProcessingFilesCallback: () => void;
@@ -18,7 +18,7 @@
         private _sceneFileToLoad: File;
         private _filesToLoad: File[];
 
-        constructor(engine: Engine, scene: Scene, sceneLoadedCallback: (sceneFile: File, scene: Scene) => void, progressCallback: (progress: ProgressEvent) => void, additionalRenderLoopLogicCallback: () => void,
+        constructor(engine: Engine, scene: Scene, sceneLoadedCallback: (sceneFile: File, scene: Scene) => void, progressCallback: (progress: SceneLoaderProgressEvent) => void, additionalRenderLoopLogicCallback: () => void, 
             textureLoadingCallback: (remaining: number) => void, startingProcessingFilesCallback: () => void, onReloadCallback: (sceneFile: File) => void, errorCallback: (sceneFile: File, scene: Scene, message: string) => void) {
             this._engine = engine;
             this._currentScene = scene;

+ 15 - 3
src/Tools/babylon.tools.ts

@@ -520,8 +520,13 @@
             url = Tools.PreprocessUrl(url);
 
             let request: Nullable<XMLHttpRequest> = null;
+            let aborted = false;
 
             let noIndexedDB = (retryIndex?: number) => {
+                if (aborted) {
+                    return;
+                }
+
                 let oldRequest = request;
                 request = new XMLHttpRequest();
 
@@ -536,11 +541,16 @@
                     request.onprogress = progressCallBack;
                 }
 
-                request.onreadystatechange = () => {
+                request.addEventListener("abort", () => {
+                    aborted = true;
+                });
+
+                let onreadystatechange = () => {
                     let req = <XMLHttpRequest>request;
                     // In case of undefined state in some browsers.
                     if (req.readyState === (XMLHttpRequest.DONE || 4)) {
-                        req.onreadystatechange = () => { };//some browsers have issues where onreadystatechange can be called multiple times with the same value
+                        // Some browsers have issues where onreadystatechange can be called multiple times with the same value.
+                        req.removeEventListener("readystatechange", onreadystatechange);
 
                         if (req.status >= 200 && req.status < 300 || (!Tools.IsWindowObjectExist() && (req.status === 0))) {
                             callback(!useArrayBuffer ? req.responseText : <ArrayBuffer>req.response, req.responseURL);
@@ -556,7 +566,7 @@
                             }
                         }
 
-                        let e = new Error("Error status: " + req.status + " - Unable to load " + loadUrl);
+                        let e = new LoadFileError("Error status: " + req.status + " - Unable to load " + loadUrl);
                         if (onError) {
                             onError(req, e);
                         } else {
@@ -565,6 +575,8 @@
                     }
                 };
 
+                request.addEventListener("readystatechange", onreadystatechange);
+
                 request.send();
 
                 if (oldRequest && onRetry) {