Trevor Baron 6 rokov pred
rodič
commit
0d71f01fbd

+ 1 - 0
dist/preview release/what's new.md

@@ -60,6 +60,7 @@
 - Added opacity texture support to `GridMaterial` ([Deltakosh](https://github.com/deltakosh))
 - Added opacity texture support to `GridMaterial` ([Deltakosh](https://github.com/deltakosh))
 - Added support for deserializing morph target animations in animation groups
 - Added support for deserializing morph target animations in animation groups
 - AssetContainer dispose method ([TrevorDev](https://github.com/TrevorDev))
 - AssetContainer dispose method ([TrevorDev](https://github.com/TrevorDev))
+- Loading texture with KTX will fallback to non-KTX loader if KTX loader fails ([TrevorDev](https://github.com/TrevorDev))
 
 
 ### glTF Loader
 ### glTF Loader
 
 

+ 22 - 13
src/Engine/babylon.engine.ts

@@ -4243,12 +4243,13 @@ module BABYLON {
          * @param fallback an internal argument in case the function must be called again, due to etc1 not having alpha capabilities
          * @param fallback an internal argument in case the function must be called again, due to etc1 not having alpha capabilities
          * @param format internal format.  Default: RGB when extension is '.jpg' else RGBA.  Ignored for compressed textures
          * @param format internal format.  Default: RGB when extension is '.jpg' else RGBA.  Ignored for compressed textures
          * @param forcedExtension defines the extension to use to pick the right loader
          * @param forcedExtension defines the extension to use to pick the right loader
+         * @param excludeLoaders array of texture loaders that should be excluded when picking a loader for the texture (defualt: empty array)
          * @returns a InternalTexture for assignment back into BABYLON.Texture
          * @returns a InternalTexture for assignment back into BABYLON.Texture
          */
          */
         public createTexture(urlArg: Nullable<string>, noMipmap: boolean, invertY: boolean, scene: Nullable<Scene>, samplingMode: number = Engine.TEXTURE_TRILINEAR_SAMPLINGMODE,
         public createTexture(urlArg: Nullable<string>, noMipmap: boolean, invertY: boolean, scene: Nullable<Scene>, samplingMode: number = Engine.TEXTURE_TRILINEAR_SAMPLINGMODE,
             onLoad: Nullable<() => void> = null, onError: Nullable<(message: string, exception: any) => void> = null,
             onLoad: Nullable<() => void> = null, onError: Nullable<(message: string, exception: any) => void> = null,
             buffer: Nullable<string | ArrayBuffer | HTMLImageElement | Blob> = null, fallback: Nullable<InternalTexture> = null, format: Nullable<number> = null,
             buffer: Nullable<string | ArrayBuffer | HTMLImageElement | Blob> = null, fallback: Nullable<InternalTexture> = null, format: Nullable<number> = null,
-            forcedExtension: Nullable<string> = null): InternalTexture {
+            forcedExtension: Nullable<string> = null, excludeLoaders: Array<IInternalTextureLoader> = []): InternalTexture {
             var url = String(urlArg); // assign a new string, so that the original is still available in case of fallback
             var url = String(urlArg); // assign a new string, so that the original is still available in case of fallback
             var fromData = url.substr(0, 5) === "data:";
             var fromData = url.substr(0, 5) === "data:";
             var fromBlob = url.substr(0, 5) === "blob:";
             var fromBlob = url.substr(0, 5) === "blob:";
@@ -4262,7 +4263,7 @@ module BABYLON {
 
 
             let loader: Nullable<IInternalTextureLoader> = null;
             let loader: Nullable<IInternalTextureLoader> = null;
             for (let availableLoader of Engine._TextureLoaders) {
             for (let availableLoader of Engine._TextureLoaders) {
-                if (availableLoader.canLoad(extension, this._textureFormatInUse, fallback, isBase64, buffer ? true : false)) {
+                if (excludeLoaders.indexOf(availableLoader) == -1 && availableLoader.canLoad(extension, this._textureFormatInUse, fallback, isBase64, buffer ? true : false)) {
                     loader = availableLoader;
                     loader = availableLoader;
                     break;
                     break;
                 }
                 }
@@ -4303,7 +4304,9 @@ module BABYLON {
                     if (fallbackUrl) {
                     if (fallbackUrl) {
                         // Add Back
                         // Add Back
                         customFallback = true;
                         customFallback = true;
-                        this.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture);
+                        excludeLoaders.push(loader);
+                        Tools.Warn((loader.constructor as any).name + " failed when trying to load " + texture.url + ", falling back to the next supported loader");
+                        this.createTexture(urlArg, noMipmap, invertY, scene, samplingMode, null, onError, buffer, texture, undefined, undefined, excludeLoaders);
                     }
                     }
                 }
                 }
 
 
@@ -4324,12 +4327,15 @@ module BABYLON {
             // processing for non-image formats
             // processing for non-image formats
             if (loader) {
             if (loader) {
                 var callback = (data: string | ArrayBuffer) => {
                 var callback = (data: string | ArrayBuffer) => {
-                    loader!.loadData(data as ArrayBuffer, texture, (width: number, height: number, loadMipmap: boolean, isCompressed: boolean, done: () => void) => {
-                        this._prepareWebGLTexture(texture, scene, width, height, invertY, !loadMipmap, isCompressed, () => {
-                            done();
-                            return false;
-                        },
-                            samplingMode);
+                    loader!.loadData(data as ArrayBuffer, texture, (width: number, height: number, loadMipmap: boolean, isCompressed: boolean, done: () => void, loadFailed) => {
+                        if (loadFailed) {
+                            onInternalError("TextureLoader failed to load data");
+                        }else {
+                            this._prepareWebGLTexture(texture, scene, width, height, invertY, !loadMipmap, isCompressed, () => {
+                                done();
+                                return false;
+                            }, samplingMode);
+                        }
                     });
                     });
                 };
                 };
 
 
@@ -5674,9 +5680,10 @@ module BABYLON {
          * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
          * @param lodScale defines the scale applied to environment texture. This manages the range of LOD level used for IBL according to the roughness
          * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
          * @param lodOffset defines the offset applied to environment texture. This manages first LOD level used for IBL according to the roughness
          * @param fallback defines texture to use while falling back when (compressed) texture file not found.
          * @param fallback defines texture to use while falling back when (compressed) texture file not found.
+         * @param excludeLoaders array of texture loaders that should be excluded when picking a loader for the texture (defualt: empty array)
          * @returns the cube texture as an InternalTexture
          * @returns the cube texture as an InternalTexture
          */
          */
-        public createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad: Nullable<(data?: any) => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null, createPolynomials = false, lodScale: number = 0, lodOffset: number = 0, fallback: Nullable<InternalTexture> = null): InternalTexture {
+        public createCubeTexture(rootUrl: string, scene: Nullable<Scene>, files: Nullable<string[]>, noMipmap?: boolean, onLoad: Nullable<(data?: any) => void> = null, onError: Nullable<(message?: string, exception?: any) => void> = null, format?: number, forcedExtension: any = null, createPolynomials = false, lodScale: number = 0, lodOffset: number = 0, fallback: Nullable<InternalTexture> = null, excludeLoaders: Array<IInternalTextureLoader> = []): InternalTexture {
             var gl = this._gl;
             var gl = this._gl;
 
 
             var texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
             var texture = fallback ? fallback : new InternalTexture(this, InternalTexture.DATASOURCE_CUBE);
@@ -5696,7 +5703,7 @@ module BABYLON {
 
 
             let loader: Nullable<IInternalTextureLoader> = null;
             let loader: Nullable<IInternalTextureLoader> = null;
             for (let availableLoader of Engine._TextureLoaders) {
             for (let availableLoader of Engine._TextureLoaders) {
-                if (availableLoader.canLoad(extension, this._textureFormatInUse, fallback, false, false)) {
+                if (excludeLoaders.indexOf(availableLoader) == -1 && availableLoader.canLoad(extension, this._textureFormatInUse, fallback, false, false)) {
                     loader = availableLoader;
                     loader = availableLoader;
                     break;
                     break;
                 }
                 }
@@ -5704,9 +5711,11 @@ module BABYLON {
 
 
             let onInternalError = (request?: XMLHttpRequest, exception?: any) => {
             let onInternalError = (request?: XMLHttpRequest, exception?: any) => {
                 if (loader) {
                 if (loader) {
-                    const fallbackUrl = loader.getFallbackTextureUrl(rootUrl, this._textureFormatInUse);
+                    const fallbackUrl = loader.getFallbackTextureUrl(texture.url, this._textureFormatInUse);
+                    Tools.Warn((loader.constructor as any).name + " failed when trying to load " + texture.url + ", falling back to the next supported loader");
                     if (fallbackUrl) {
                     if (fallbackUrl) {
-                        this.createCubeTexture(fallbackUrl, scene, files, noMipmap, onLoad, onError, format, extension, createPolynomials, lodScale, lodOffset, texture);
+                        excludeLoaders.push(loader);
+                        this.createCubeTexture(fallbackUrl, scene, files, noMipmap, onLoad, onError, format, extension, createPolynomials, lodScale, lodOffset, texture, excludeLoaders);
                     }
                     }
                 }
                 }
 
 

+ 2 - 2
src/Materials/Textures/Loaders/babylon.ktxTextureLoader.ts

@@ -83,12 +83,12 @@ module BABYLON {
          * @param callback defines the method to call once ready to upload
          * @param callback defines the method to call once ready to upload
          */
          */
         public loadData(data: ArrayBuffer, texture: InternalTexture,
         public loadData(data: ArrayBuffer, texture: InternalTexture,
-            callback: (width: number, height: number, loadMipmap: boolean, isCompressed: boolean, done: () => void) => void): void {
+            callback: (width: number, height: number, loadMipmap: boolean, isCompressed: boolean, done: () => void, loadFailed: boolean) => void): void {
             var ktx = new KhronosTextureContainer(data, 1);
             var ktx = new KhronosTextureContainer(data, 1);
 
 
             callback(ktx.pixelWidth, ktx.pixelHeight, false, true, () => {
             callback(ktx.pixelWidth, ktx.pixelHeight, false, true, () => {
                 ktx.uploadLevels(texture, texture.generateMipMaps);
                 ktx.uploadLevels(texture, texture.generateMipMaps);
-            });
+            }, ktx.isInvalid);
         }
         }
     }
     }
 
 

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

@@ -52,6 +52,6 @@ module BABYLON {
          * @param callback defines the method to call once ready to upload
          * @param callback defines the method to call once ready to upload
          */
          */
         loadData(data: ArrayBuffer, texture: InternalTexture,
         loadData(data: ArrayBuffer, texture: InternalTexture,
-            callback: (width: number, height: number, loadMipmap: boolean, isCompressed: boolean, done: () => void) => void): void;
+            callback: (width: number, height: number, loadMipmap: boolean, isCompressed: boolean, done: () => void, loadFailed?: boolean) => void): void;
     }
     }
 }
 }

+ 6 - 1
src/Tools/babylon.khronosTextureContainer.ts

@@ -65,6 +65,10 @@ module BABYLON {
          * Gets the load type
          * Gets the load type
          */
          */
         public loadType: number;
         public loadType: number;
+        /**
+         * If the container has been made invalid (eg. constructor failed to correctly load array buffer)
+         */
+        public isInvalid = false;
 
 
         /**
         /**
          * Creates a new KhronosTextureContainer
          * Creates a new KhronosTextureContainer
@@ -82,7 +86,8 @@ module BABYLON {
             var identifier = new Uint8Array(this.arrayBuffer, 0, 12);
             var identifier = new Uint8Array(this.arrayBuffer, 0, 12);
             if (identifier[0] !== 0xAB || identifier[1] !== 0x4B || identifier[2] !== 0x54 || identifier[3] !== 0x58 || identifier[4] !== 0x20 || identifier[5] !== 0x31 ||
             if (identifier[0] !== 0xAB || identifier[1] !== 0x4B || identifier[2] !== 0x54 || identifier[3] !== 0x58 || identifier[4] !== 0x20 || identifier[5] !== 0x31 ||
                 identifier[6] !== 0x31 || identifier[7] !== 0xBB || identifier[8] !== 0x0D || identifier[9] !== 0x0A || identifier[10] !== 0x1A || identifier[11] !== 0x0A) {
                 identifier[6] !== 0x31 || identifier[7] !== 0xBB || identifier[8] !== 0x0D || identifier[9] !== 0x0A || identifier[10] !== 0x1A || identifier[11] !== 0x0A) {
-                Tools.Error("texture missing KTX identifier");
+                this.isInvalid = true;
+                    Tools.Error("texture missing KTX identifier");
                 return;
                 return;
             }
             }