Explorar o código

Clean up glTF loader after strict null checks

Gary Hsu %!s(int64=7) %!d(string=hai) anos
pai
achega
64c67e16e7

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

@@ -1547,7 +1547,7 @@ module BABYLON.GLTF1 {
             // do nothing
         }
 
-        public importMeshAsync(meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<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: ProgressEvent) => void, onError: (message: string) => void): boolean {
             scene.useRightHandedSystem = true;
 
             GLTFLoaderExtension.LoadRuntimeAsync(scene, data, rootUrl, gltfRuntime => {
@@ -1597,13 +1597,13 @@ module BABYLON.GLTF1 {
                         postLoad(gltfRuntime);
 
                         if (!BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                            onSuccess(meshes, null, skeletons);
+                            onSuccess(meshes, [], skeletons);
                         }
                     });
                 }, onProgress);
 
                 if (BABYLON.GLTFFileLoader.IncrementalLoading && onSuccess) {
-                    onSuccess(meshes, null, skeletons);
+                    onSuccess(meshes, [], skeletons);
                 }
             }, onError);
 

+ 17 - 21
loaders/src/glTF/2.0/Extensions/KHR_materials_pbrSpecularGlossiness.ts

@@ -15,13 +15,11 @@ module BABYLON.GLTF2.Extensions {
         }
 
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean {
-            return this._loadExtension<IKHRMaterialsPbrSpecularGlossiness>(material, (extension, onComplete) => {
+            return this._loadExtension<IKHRMaterialsPbrSpecularGlossiness>(context, material, (context, extension, onComplete) => {
                 loader._createPbrMaterial(material);
                 loader._loadMaterialBaseProperties(context, material);
                 this._loadSpecularGlossinessProperties(loader, context, material, extension);
-                if (material.babylonMaterial) {
-                    assign(material.babylonMaterial, true);
-                }
+                assign(material.babylonMaterial, true);
             });
         }
 
@@ -32,27 +30,25 @@ module BABYLON.GLTF2.Extensions {
             babylonMaterial.reflectivityColor = properties.specularFactor ? Color3.FromArray(properties.specularFactor) : new Color3(1, 1, 1);
             babylonMaterial.microSurface = properties.glossinessFactor == null ? 1 : properties.glossinessFactor;
 
-            if (loader._gltf.textures) {
-                if (properties.diffuseTexture) {
-                    const texture = GLTFUtils.GetArrayItem(loader._gltf.textures, properties.diffuseTexture.index);
-                    if (!texture) {
-                        throw new Error(context + ": Failed to find diffuse texture " + properties.diffuseTexture.index);
-                    }
-
-                    babylonMaterial.albedoTexture = loader._loadTexture("textures[" + texture.index + "]", texture, properties.diffuseTexture.texCoord);
+            if (properties.diffuseTexture) {
+                const texture = GLTFLoader._GetProperty(loader._gltf.textures, properties.diffuseTexture.index);
+                if (!texture) {
+                    throw new Error(context + ": Failed to find diffuse texture " + properties.diffuseTexture.index);
                 }
 
-                if (properties.specularGlossinessTexture) {
-                    const texture = GLTFUtils.GetArrayItem(loader._gltf.textures, properties.specularGlossinessTexture.index);
-                    if (!texture) {
-                        throw new Error(context + ": Failed to find diffuse texture " + properties.specularGlossinessTexture.index);
-                    }
+                babylonMaterial.albedoTexture = loader._loadTexture("textures[" + texture.index + "]", texture, properties.diffuseTexture.texCoord);
+            }
 
-                    babylonMaterial.reflectivityTexture = loader._loadTexture("textures[" + texture.index + "]", texture, properties.specularGlossinessTexture.texCoord);
-                    babylonMaterial.reflectivityTexture.hasAlpha = true;
-                    babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
+            if (properties.specularGlossinessTexture) {
+                const texture = GLTFLoader._GetProperty(loader._gltf.textures, properties.specularGlossinessTexture.index);
+                if (!texture) {
+                    throw new Error(context + ": Failed to find diffuse texture " + properties.specularGlossinessTexture.index);
                 }
-        }
+
+                babylonMaterial.reflectivityTexture = loader._loadTexture("textures[" + texture.index + "]", texture, properties.specularGlossinessTexture.texCoord);
+                babylonMaterial.reflectivityTexture.hasAlpha = true;
+                babylonMaterial.useMicroSurfaceFromReflectivityMapAlpha = true;
+            }
 
             loader._loadMaterialAlphaProperties(context, material, properties.diffuseFactor);
         }

+ 23 - 17
loaders/src/glTF/2.0/Extensions/MSFT_lod.ts

@@ -17,12 +17,9 @@ module BABYLON.GLTF2.Extensions {
         }
 
         protected _traverseNode(loader: GLTFLoader, context: string, node: IGLTFNode, action: (node: IGLTFNode, parentNode: IGLTFNode) => boolean, parentNode: IGLTFNode): boolean {
-            return this._loadExtension<IMSFTLOD>(node, (extension, onComplete) => {
-                if (!loader._gltf.nodes) {
-                    return;
-                }
+            return this._loadExtension<IMSFTLOD>(context, node, (context, extension, onComplete) => {
                 for (let i = extension.ids.length - 1; i >= 0; i--) {
-                    const lodNode = GLTFUtils.GetArrayItem(loader._gltf.nodes, extension.ids[i]);
+                    const lodNode = GLTFLoader._GetProperty(loader._gltf.nodes, extension.ids[i]);
                     if (!lodNode) {
                         throw new Error(context + ": Failed to find node " + extension.ids[i]);
                     }
@@ -36,9 +33,16 @@ module BABYLON.GLTF2.Extensions {
         }
 
         protected _loadNode(loader: GLTFLoader, context: string, node: IGLTFNode): boolean {
-            return this._loadExtension<IMSFTLOD>(node, (extension, onComplete) => {
-                
-                const nodes = [node.index, ...extension.ids].map(index => (<IGLTFNode[]>loader._gltf.nodes)[<number>index]);
+            return this._loadExtension<IMSFTLOD>(context, node, (context, extension, onComplete) => {
+                const nodes = [node];
+                for (let index of extension.ids) {
+                    const lodNode = GLTFLoader._GetProperty(loader._gltf.nodes, index);
+                    if (!lodNode) {
+                        throw new Error(context + ": Failed to find node " + index);
+                    }
+
+                    nodes.push(lodNode);
+                }
 
                 loader._addLoaderPendingData(node);
                 this._loadNodeLOD(loader, context, nodes, nodes.length - 1, () => {
@@ -54,10 +58,7 @@ module BABYLON.GLTF2.Extensions {
             }, () => {
                 if (index !== nodes.length - 1) {
                     const previousNode = nodes[index + 1];
-
-                    if (previousNode.babylonMesh) {
-                        previousNode.babylonMesh.setEnabled(false);
-                    }
+                    previousNode.babylonMesh.setEnabled(false);
                 }
 
                 if (index === 0) {
@@ -74,14 +75,19 @@ module BABYLON.GLTF2.Extensions {
         }
 
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean {
-            return this._loadExtension<IMSFTLOD>(material, (extension, onComplete) => {
-                const materials = [material.index, ...extension.ids].map(index => (<IGLTFMaterial[]>loader._gltf.materials)[<number>index]);
+            return this._loadExtension<IMSFTLOD>(context, material, (context, extension, onComplete) => {
+                const materials = [material];
+                for (let index of extension.ids) {
+                    const lodMaterial = GLTFLoader._GetProperty(loader._gltf.materials, index);
+                    if (!lodMaterial) {
+                        throw new Error(context + ": Failed to find material " + index);
+                    }
+
+                    materials.push(lodMaterial);
+                }
 
                 loader._addLoaderPendingData(material);
                 this._loadMaterialLOD(loader, context, materials, materials.length - 1, assign, () => {
-                    if (material.extensions) {
-                        material.extensions[this.name] = extension;
-                    }
                     loader._removeLoaderPendingData(material);
                     onComplete();
                 });

A diferenza do arquivo foi suprimida porque é demasiado grande
+ 309 - 262
loaders/src/glTF/2.0/babylon.glTFLoader.ts


+ 3 - 5
loaders/src/glTF/2.0/babylon.glTFLoaderExtension.ts

@@ -12,7 +12,7 @@ module BABYLON.GLTF2 {
 
         protected _loadMaterial(loader: GLTFLoader, context: string, material: IGLTFMaterial, assign: (babylonMaterial: Material, isNew: boolean) => void): boolean { return false; }
 
-        protected _loadExtension<T>(property: IGLTFProperty, action: (extension: T, onComplete: () => void) => void): boolean {
+        protected _loadExtension<T>(context: string, property: IGLTFProperty, action: (context: string, extension: T, onComplete: () => void) => void): boolean {
             if (!property.extensions) {
                 return false;
             }
@@ -25,11 +25,9 @@ module BABYLON.GLTF2 {
             // Clear out the extension before executing the action to avoid recursing into the same property.
             property.extensions[this.name] = undefined;
 
-            action(extension, () => {
+            action(context + "extensions/" + this.name, extension, () => {
                 // Restore the extension after completing the action.
-                if (property.extensions) {
-                    property.extensions[this.name] = extension;
-                }
+                property.extensions![this.name] = extension;
             });
 
             return true;

+ 17 - 17
loaders/src/glTF/2.0/babylon.glTFLoaderInterfaces.ts

@@ -84,7 +84,7 @@ module BABYLON.GLTF2 {
         sparse?: IGLTFAccessorSparse;
 
         // Runtime values
-        index?: number;
+        index: number;
     }
 
     export interface IGLTFAnimationChannel extends IGLTFProperty {
@@ -108,8 +108,8 @@ module BABYLON.GLTF2 {
         samplers: IGLTFAnimationSampler[];
 
         // Runtime values
-        index?: number;
-        targets?: any[];
+        index: number;
+        targets: any[];
     }
 
     export interface IGLTFAsset extends IGLTFChildRootProperty {
@@ -124,7 +124,7 @@ module BABYLON.GLTF2 {
         byteLength: number;
 
         // Runtime values
-        index?: number;
+        index: number;
         loadedData?: ArrayBufferView;
         loadedObservable?: Observable<IGLTFBuffer>;
     }
@@ -136,7 +136,7 @@ module BABYLON.GLTF2 {
         byteStride?: number;
 
         // Runtime values
-        index?: number;
+        index: number;
     }
 
     export interface IGLTFCameraOrthographic extends IGLTFProperty {
@@ -165,7 +165,7 @@ module BABYLON.GLTF2 {
         bufferView?: number;
 
         // Runtime values
-        index?: number;
+        index: number;
     }
 
     export interface IGLTFMaterialNormalTextureInfo extends IGLTFTextureInfo {
@@ -195,8 +195,8 @@ module BABYLON.GLTF2 {
         doubleSided?: boolean;
 
         // Runtime values
-        index?: number;
-        babylonMaterial?: Material;
+        index: number;
+        babylonMaterial: Material;
     }
 
     export interface IGLTFMeshPrimitive extends IGLTFProperty {
@@ -216,7 +216,7 @@ module BABYLON.GLTF2 {
         weights?: number[];
 
         // Runtime values
-        index?: number;
+        index: number;
     }
 
     export interface IGLTFNode extends IGLTFChildRootProperty {
@@ -231,11 +231,11 @@ module BABYLON.GLTF2 {
         weights?: number[];
 
         // Runtime values
-        index?: number;
+        index: number;
         parent?: IGLTFNode;
-        babylonMesh?: Mesh;
-        babylonBones?: { [skin: number]: Bone };
-        babylonAnimationTargets?: Node[];
+        babylonMesh: Mesh;
+        babylonBones: { [skin: number]: Bone };
+        babylonAnimationTargets: Node[];
     }
 
     export interface IGLTFSampler extends IGLTFChildRootProperty {
@@ -249,7 +249,7 @@ module BABYLON.GLTF2 {
         nodes: number[];
 
         // Runtime values
-        index?: number;
+        index: number;
     }
 
     export interface IGLTFSkin extends IGLTFChildRootProperty {
@@ -258,8 +258,8 @@ module BABYLON.GLTF2 {
         joints: number[];
 
         // Runtime values
-        index?: number;
-        babylonSkeleton?: Skeleton;
+        index: number;
+        babylonSkeleton: Skeleton;
     }
 
     export interface IGLTFTexture extends IGLTFChildRootProperty {
@@ -267,7 +267,7 @@ module BABYLON.GLTF2 {
         source: number;
 
         // Runtime values
-        index?: number;
+        index: number;
         url?: string;
         dataReadyObservable?: Observable<IGLTFTexture>;
     }

+ 0 - 67
loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts

@@ -32,72 +32,5 @@ module BABYLON.GLTF2 {
         public static ValidateUri(uri: string): boolean {
             return (uri.indexOf("..") === -1);
         }
-
-        public static AssignIndices(array?: Array<{index?: number}>): void {
-            if (array) {
-                for (let index = 0; index < array.length; index++) {
-                    array[index].index = index;
-                }
-            }
-        }
-
-        public static GetArrayItem<T>(array: Nullable<ArrayLike<T>> | undefined, index: number): Nullable<T> {
-            if (!array || !array[index]) {
-                return null;
-            }
-
-            return array[index];
-        }
-
-        public static GetTextureWrapMode(mode: ETextureWrapMode): number {
-            // Set defaults if undefined
-            mode = mode === undefined ? ETextureWrapMode.REPEAT : mode;
-
-            switch (mode) {
-                case ETextureWrapMode.CLAMP_TO_EDGE: return Texture.CLAMP_ADDRESSMODE;
-                case ETextureWrapMode.MIRRORED_REPEAT: return Texture.MIRROR_ADDRESSMODE;
-                case ETextureWrapMode.REPEAT: return Texture.WRAP_ADDRESSMODE;
-                default:
-                    Tools.Warn("Invalid texture wrap mode (" + mode + ")");
-                    return Texture.WRAP_ADDRESSMODE;
-            }
-        }
-
-        public static GetTextureSamplingMode(magFilter?: ETextureMagFilter, minFilter?: ETextureMinFilter): number {
-            // Set defaults if undefined
-            magFilter = magFilter === undefined ? ETextureMagFilter.LINEAR : magFilter;
-            minFilter = minFilter === undefined ? ETextureMinFilter.LINEAR_MIPMAP_LINEAR : minFilter;
-
-            if (magFilter === ETextureMagFilter.LINEAR) {
-                switch (minFilter) {
-                    case ETextureMinFilter.NEAREST: return Texture.LINEAR_NEAREST;
-                    case ETextureMinFilter.LINEAR: return Texture.LINEAR_LINEAR;
-                    case ETextureMinFilter.NEAREST_MIPMAP_NEAREST: return Texture.LINEAR_NEAREST_MIPNEAREST;
-                    case ETextureMinFilter.LINEAR_MIPMAP_NEAREST: return Texture.LINEAR_LINEAR_MIPNEAREST;
-                    case ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.LINEAR_NEAREST_MIPLINEAR;
-                    case ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.LINEAR_LINEAR_MIPLINEAR;
-                    default:
-                        Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
-                        return Texture.LINEAR_LINEAR_MIPLINEAR;
-                }
-            }
-            else {
-                if (magFilter !== ETextureMagFilter.NEAREST) {
-                    Tools.Warn("Invalid texture magnification filter (" + magFilter + ")");
-                }
-
-                switch (minFilter) {
-                    case ETextureMinFilter.NEAREST: return Texture.NEAREST_NEAREST;
-                    case ETextureMinFilter.LINEAR: return Texture.NEAREST_LINEAR;
-                    case ETextureMinFilter.NEAREST_MIPMAP_NEAREST: return Texture.NEAREST_NEAREST_MIPNEAREST;
-                    case ETextureMinFilter.LINEAR_MIPMAP_NEAREST: return Texture.NEAREST_LINEAR_MIPNEAREST;
-                    case ETextureMinFilter.NEAREST_MIPMAP_LINEAR: return Texture.NEAREST_NEAREST_MIPLINEAR;
-                    case ETextureMinFilter.LINEAR_MIPMAP_LINEAR: return Texture.NEAREST_LINEAR_MIPLINEAR;
-                    default:
-                        Tools.Warn("Invalid texture minification filter (" + minFilter + ")");
-                        return Texture.NEAREST_NEAREST_MIPNEAREST;
-                }
-            }
-        }
     }
 }

+ 57 - 74
loaders/src/glTF/babylon.glTFFileLoader.ts

@@ -19,7 +19,7 @@ module BABYLON {
     }
 
     export interface IGLTFLoader extends IDisposable {
-        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: Nullable<AbstractMesh[]>, particleSystems: Nullable<ParticleSystem[]>, skeletons: Nullable<Skeleton[]>) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
+        importMeshAsync: (meshesNames: any, scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: (meshes: AbstractMesh[], particleSystems: ParticleSystem[], skeletons: Skeleton[]) => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
         loadAsync: (scene: Scene, data: IGLTFLoaderData, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void) => void;
     }
 
@@ -51,7 +51,7 @@ module BABYLON {
          */
         public onComplete: () => void;
 
-        private _loader: Nullable<IGLTFLoader>;
+        private _loader: IGLTFLoader;
 
         public name = "gltf";
 
@@ -63,88 +63,74 @@ module BABYLON {
         public dispose(): void {
             if (this._loader) {
                 this._loader.dispose();
-                this._loader = null;
             }
         }
 
         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) => void): void {
-            const loaderData = GLTFFileLoader._parse(data, onError);
-            if (!loaderData) {
-                return;
-            }
+            try {
+                const loaderData = GLTFFileLoader._parse(data);
 
-            if (this.onParsed) {
-                this.onParsed(loaderData);
-            }
+                if (this.onParsed) {
+                    this.onParsed(loaderData);
+                }
 
-            this._loader = this._getLoader(loaderData, onError);
-            if (!this._loader) {
-                return;
+                this._loader = this._getLoader(loaderData);
+                this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            }
+            catch (e) {
+                onError(e.message);
             }
-
-            this._loader.importMeshAsync(meshesNames, scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         }
 
         public loadAsync(scene: Scene, data: string | ArrayBuffer, rootUrl: string, onSuccess: () => void, onProgress: (event: ProgressEvent) => void, onError: (message: string) => void): void {
-            const loaderData = GLTFFileLoader._parse(data, onError);
-            if (!loaderData) {
-                return;
-            }
+            try {
+                const loaderData = GLTFFileLoader._parse(data);
 
-            if (this.onParsed) {
-                this.onParsed(loaderData);
-            }
+                if (this.onParsed) {
+                    this.onParsed(loaderData);
+                }
 
-            this._loader = this._getLoader(loaderData, onError);
-            if (!this._loader) {
-                return;
+                this._loader = this._getLoader(loaderData);
+                this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
+            }
+            catch (e) {
+                onError(e.message);
             }
-
-            return this._loader.loadAsync(scene, loaderData, rootUrl, onSuccess, onProgress, onError);
         }
 
         public canDirectLoad(data: string): boolean {
             return ((data.indexOf("scene") !== -1) && (data.indexOf("node") !== -1));
         }
 
-        private static _parse(data: string | ArrayBuffer, onError: (message: string) => void): Nullable<IGLTFLoaderData> {
-            try {
-                if (data instanceof ArrayBuffer) {
-                    return GLTFFileLoader._parseBinary(data, onError);
-                }
-
-                return {
-                    json: JSON.parse(data),
-                    bin: null
-                };
-            }
-            catch (e) {
-                onError(e.message);
-                return null;
+        private static _parse(data: string | ArrayBuffer): IGLTFLoaderData {
+            if (data instanceof ArrayBuffer) {
+                return GLTFFileLoader._parseBinary(data);
             }
+
+            return {
+                json: JSON.parse(data),
+                bin: null
+            };
         }
 
-        private _getLoader(loaderData: IGLTFLoaderData, onError: (message: string) => void): Nullable<IGLTFLoader> {
+        private _getLoader(loaderData: IGLTFLoaderData): IGLTFLoader {
             const loaderVersion = { major: 2, minor: 0 };
 
             const asset = (<any>loaderData.json).asset || {};
 
             const version = GLTFFileLoader._parseVersion(asset.version);
             if (!version) {
-                onError("Invalid version: " + asset.version);
-                return null;
+                throw new Error("Invalid version: " + asset.version);
             }
 
             if (asset.minVersion !== undefined) {
                 const minVersion = GLTFFileLoader._parseVersion(asset.minVersion);
                 if (!minVersion) {
-                    onError("Invalid minimum version: " + asset.minVersion);
-                    return null;
+                    throw new Error("Invalid minimum version: " + asset.minVersion);
                 }
 
                 if (GLTFFileLoader._compareVersion(minVersion, loaderVersion) > 0) {
-                    onError("Incompatible minimum version: " + asset.minVersion);
-                    return null;
+                    throw new Error("Incompatible minimum version: " + asset.minVersion);
                 }
             }
 
@@ -155,14 +141,13 @@ module BABYLON {
 
             const createLoader = createLoaders[version.major];
             if (!createLoader) {
-                onError("Unsupported version: " + asset.version);
-                return null;
+                throw new Error("Unsupported version: " + asset.version);
             }
 
             return createLoader(this);
         }
 
-        private static _parseBinary(data: ArrayBuffer, onError: (message: string) => void): Nullable<IGLTFLoaderData> {
+        private static _parseBinary(data: ArrayBuffer): IGLTFLoaderData {
             const Binary = {
                 Magic: 0x46546C67
             };
@@ -171,29 +156,26 @@ module BABYLON {
 
             const magic = binaryReader.readUint32();
             if (magic !== Binary.Magic) {
-                onError("Unexpected magic: " + magic);
-                return null;
+                throw new Error("Unexpected magic: " + magic);
             }
 
             const version = binaryReader.readUint32();
             switch (version) {
-                case 1: return GLTFFileLoader._parseV1(binaryReader, onError);
-                case 2: return GLTFFileLoader._parseV2(binaryReader, onError);
+                case 1: return GLTFFileLoader._parseV1(binaryReader);
+                case 2: return GLTFFileLoader._parseV2(binaryReader);
             }
 
-            onError("Unsupported version: " + version);
-            return null;
+            throw new Error("Unsupported version: " + version);
         }
 
-        private static _parseV1(binaryReader: BinaryReader, onError: (message: string) => void): Nullable<IGLTFLoaderData> {
+        private static _parseV1(binaryReader: BinaryReader): IGLTFLoaderData {
             const ContentFormat = {
                 JSON: 0
             };
 
             const length = binaryReader.readUint32();
             if (length != binaryReader.getLength()) {
-                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
-                return null;
+                throw new Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
             }
 
             const contentLength = binaryReader.readUint32();
@@ -201,12 +183,13 @@ module BABYLON {
 
             let content: Object;
             switch (contentFormat) {
-                case ContentFormat.JSON:
+                case ContentFormat.JSON: {
                     content = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(contentLength)));
                     break;
-                default:
-                    onError("Unexpected content format: " + contentFormat);
-                    return null;
+                }
+                default: {
+                    throw new Error("Unexpected content format: " + contentFormat);
+                }
             }
 
             const bytesRemaining = binaryReader.getLength() - binaryReader.getPosition();
@@ -218,7 +201,7 @@ module BABYLON {
             };
         }
 
-        private static _parseV2(binaryReader: BinaryReader, onError: (message: string) => void): Nullable<IGLTFLoaderData> {
+        private static _parseV2(binaryReader: BinaryReader): IGLTFLoaderData {
             const ChunkFormat = {
                 JSON: 0x4E4F534A,
                 BIN: 0x004E4942
@@ -226,16 +209,14 @@ module BABYLON {
 
             const length = binaryReader.readUint32();
             if (length !== binaryReader.getLength()) {
-                onError("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
-                return null;
+                throw new Error("Length in header does not match actual data length: " + length + " != " + binaryReader.getLength());
             }
 
             // JSON chunk
             const chunkLength = binaryReader.readUint32();
             const chunkFormat = binaryReader.readUint32();
             if (chunkFormat !== ChunkFormat.JSON) {
-                onError("First chunk format is not JSON");
-                return null;
+                throw new Error("First chunk format is not JSON");
             }
             const json = JSON.parse(GLTFFileLoader._decodeBufferToText(binaryReader.readUint8Array(chunkLength)));
 
@@ -245,16 +226,18 @@ module BABYLON {
                 const chunkLength = binaryReader.readUint32();
                 const chunkFormat = binaryReader.readUint32();
                 switch (chunkFormat) {
-                    case ChunkFormat.JSON:
-                        onError("Unexpected JSON chunk");
-                        return null;
-                    case ChunkFormat.BIN:
+                    case ChunkFormat.JSON: {
+                        throw new Error("Unexpected JSON chunk");
+                    }
+                    case ChunkFormat.BIN: {
                         bin = binaryReader.readUint8Array(chunkLength);
                         break;
-                    default:
+                    }
+                    default: {
                         // ignore unrecognized chunkFormat
                         binaryReader.skipBytes(chunkLength);
                         break;
+                    }
                 }
             }