Explorar o código

Handle multi-image dds cubemaps

Ben Adams %!s(int64=7) %!d(string=hai) anos
pai
achega
893e1b4031
Modificáronse 3 ficheiros con 128 adicións e 46 borrados
  1. 105 28
      src/Engine/babylon.engine.ts
  2. 21 16
      src/Tools/babylon.dds.ts
  3. 2 2
      src/Tools/babylon.tools.ts

+ 105 - 28
src/Engine/babylon.engine.ts

@@ -116,20 +116,20 @@
         }
     }
 
-    var partialLoad = (url: string, index: number, loadedImages: any, scene: Nullable<Scene>,
+    var partialLoadImg = (url: string, index: number, loadedImages: HTMLImageElement[], scene: Nullable<Scene>,
         onfinish: (images: HTMLImageElement[]) => void, onErrorCallBack: Nullable<(message?: string, exception?: any) => void> = null) => {
 
         var img: HTMLImageElement;
 
         var onload = () => {
             loadedImages[index] = img;
-            loadedImages._internalCount++;
+            (<any>loadedImages)._internalCount++;
 
             if (scene) {
                 scene._removePendingData(img);
             }
 
-            if (loadedImages._internalCount === 6) {
+            if ((<any>loadedImages)._internalCount === 6) {
                 onfinish(loadedImages);
             }
         };
@@ -150,14 +150,46 @@
         }
     }
 
-    var cascadeLoad = (rootUrl: string, scene: Nullable<Scene>,
+    var cascadeLoadImgs = (rootUrl: string, scene: Nullable<Scene>,
         onfinish: (images: HTMLImageElement[]) => void, files: string[], onError: Nullable<(message?: string, exception?: any) => void> = null) => {
 
-        var loadedImages: any = [];
-        loadedImages._internalCount = 0;
+        var loadedImages: HTMLImageElement[] = [];
+        (<any>loadedImages)._internalCount = 0;
 
-        for (var index = 0; index < 6; index++) {
-            partialLoad(files[index], index, loadedImages, scene, onfinish, onError);
+        for (let index = 0; index < 6; index++) {
+            partialLoadImg(files[index], index, loadedImages, scene, onfinish, onError);
+        }
+    };
+
+    var partialLoadFile = (url: string, index: number, loadedFiles: (string | ArrayBuffer)[], scene: Nullable<Scene>,
+        onfinish: (files: (string | ArrayBuffer)[]) => void, onErrorCallBack: Nullable<(message?: string, exception?: any) => void> = null) => {
+
+        var onload = (data: string | ArrayBuffer) => {
+            loadedFiles[index] = data;
+            (<any>loadedFiles)._internalCount++;
+
+            if ((<any>loadedFiles)._internalCount === 6) {
+                onfinish(loadedFiles);
+            }
+        };
+
+        const onerror = (request: XMLHttpRequest, exception: any) => {
+            if (onErrorCallBack) {
+                onErrorCallBack(request.status + " " + request.statusText, exception);
+            }
+        };
+
+        Tools.LoadFile(url, onload, undefined, undefined, true, onerror);
+    }
+
+    var cascadeLoadFiles = (rootUrl: string, scene: Nullable<Scene>,
+        onfinish: (images: (string | ArrayBuffer)[]) => void, files: string[], onError: Nullable<(message?: string, exception?: any) => void> = null) => {
+
+        var loadedFiles: (string | ArrayBuffer)[] = [];
+        (<any>loadedFiles)._internalCount = 0;
+
+        for (let index = 0; index < 6; index++) {
+            partialLoadFile(files[index], index, loadedFiles, scene, onfinish, onError);
         }
     };
 
@@ -3901,7 +3933,7 @@
 
             let onerror = (request: XMLHttpRequest, exception: any) => {
                 if (onError) {
-                    onError(request.status + " " + request.statusText, exception)
+                    onError(request.status + " " + request.statusText, exception);
                 }
             }
 
@@ -3923,37 +3955,82 @@
                     texture.isReady = true;
                 }, undefined, undefined, true, onerror);
             } else if (isDDS) {
-                Tools.LoadFile(rootUrl, data => {
-                    var info = Internals.DDSTools.GetDDSInfo(data);
+                if (files) {
+                    cascadeLoadFiles(rootUrl,
+                        scene,
+                        imgs => {
+                            var info: Internals.DDSInfo | undefined;
+                            var loadMipmap: boolean = false;
+                            var width: number = 0;
+                            for (let index = 0; index < imgs.length; index++) {
+                                let data = imgs[index];
+                                info = Internals.DDSTools.GetDDSInfo(data);
+
+                                loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && !noMipmap;
+
+                                this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture);
+                                gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, info.isCompressed ? 1 : 0);
+
+                                Internals.DDSTools.UploadDDSLevels(this, this._gl, data, info, loadMipmap, 6, -1, index);
+
+                                if (!noMipmap && !info.isFourCC && info.mipmapCount === 1) {
+                                    gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+                                }
+
+                                texture.width = info.width;
+                                texture.height = info.height;
+                                texture.type = info.textureType;
+                                width = info.width;
+                            }
 
-                    var loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && !noMipmap;
+                            this.setCubeMapTextureParams(gl, loadMipmap);
+                            texture.isReady = true;
 
-                    this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture);
-                    gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, info.isCompressed ? 1 : 0);
+                            if (onLoad) {
+                                onLoad({ isDDS: true, width: width, info, imgs, texture });
+                            }
+                        },
+                        files,
+                        onError);
 
-                    Internals.DDSTools.UploadDDSLevels(this, this._gl, data, info, loadMipmap, 6);
+                } else {
+                    Tools.LoadFile(rootUrl,
+                        data => {
+                            var info = Internals.DDSTools.GetDDSInfo(data);
 
-                    if (!noMipmap && !info.isFourCC && info.mipmapCount === 1) {
-                        gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
-                    }
+                            var loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && !noMipmap;
 
-                    this.setCubeMapTextureParams(gl, loadMipmap);
+                            this._bindTextureDirectly(gl.TEXTURE_CUBE_MAP, texture);
+                            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, info.isCompressed ? 1 : 0);
 
-                    texture.width = info.width;
-                    texture.height = info.height;
-                    texture.isReady = true;
-                    texture.type = info.textureType;
+                            Internals.DDSTools.UploadDDSLevels(this, this._gl, data, info, loadMipmap, 6);
 
-                    if (onLoad) {
-                        onLoad({ isDDS: true, width: info.width, info, data, texture });
-                    }
-                }, undefined, undefined, true, onerror);
+                            if (!noMipmap && !info.isFourCC && info.mipmapCount === 1) {
+                                gl.generateMipmap(gl.TEXTURE_CUBE_MAP);
+                            }
+
+                            this.setCubeMapTextureParams(gl, loadMipmap);
+
+                            texture.width = info.width;
+                            texture.height = info.height;
+                            texture.isReady = true;
+                            texture.type = info.textureType;
+
+                            if (onLoad) {
+                                onLoad({ isDDS: true, width: info.width, info, data, texture });
+                            }
+                        },
+                        undefined,
+                        undefined,
+                        true,
+                        onerror);
+                }
             } else {
                 if (!files) {
                     throw new Error("Cannot load cubemap because files were not defined");
                 }
 
-                cascadeLoad(rootUrl, scene, imgs => {
+                cascadeLoadImgs(rootUrl, scene, imgs => {
                     var width = this.needPOTTextures ? Tools.GetExponentOfTwo(imgs[0].width, this._caps.maxCubemapTextureSize) : imgs[0].width;
                     var height = width;
 

+ 21 - 16
src/Tools/babylon.dds.ts

@@ -361,17 +361,17 @@
             return byteArray;
         }
 
-        public static UploadDDSLevels(engine: Engine, gl:WebGLRenderingContext, arrayBuffer: any, info: DDSInfo, loadMipmaps: boolean, faces: number, lodIndex = -1): void {
+        public static UploadDDSLevels(engine: Engine, gl:WebGLRenderingContext, arrayBuffer: any, info: DDSInfo, loadMipmaps: boolean, faces: number, lodIndex = -1, currentFace?: number): void {
             var ext = engine.getCaps().s3tc;
 
-            var header = new Int32Array(arrayBuffer, 0, headerLengthInt),
-                fourCC, width, height, dataLength, dataOffset,
-                byteArray, mipmapCount, mip;
+            var header = new Int32Array(arrayBuffer, 0, headerLengthInt);
+            var fourCC: number, width: number, height: number, dataLength: number, dataOffset: number;
+            var byteArray: Uint8Array, mipmapCount: number, mip: number;
             let internalFormat = 0;
             let format = 0;
             let blockBytes = 1;
 
-            if (header[off_magic] != DDS_MAGIC) {
+            if (header[off_magic] !== DDS_MAGIC) {
                 Tools.Error("Invalid magic number in DDS header");
                 return;
             }
@@ -411,7 +411,7 @@
                     break;
                 case FOURCC_D3DFMT_R32G32B32A32F:
                     computeFormats = true;
-                    break;                    
+                    break;
                 case FOURCC_DX10:
                     // There is an additionnal header so dataOffset need to be changed
                     dataOffset += 5 * 4; // 5 uints
@@ -427,7 +427,7 @@
                             info.isFourCC = false;
                             bpp = 32;
                             supported = true;
-                            break;                        
+                            break;
                     }
 
                     if (supported) {
@@ -450,7 +450,7 @@
             }
             
             for (var face = 0; face < faces; face++) {
-                var sampler = faces === 1 ? gl.TEXTURE_2D : (gl.TEXTURE_CUBE_MAP_POSITIVE_X + face);
+                var sampler = faces === 1 ? gl.TEXTURE_2D : (gl.TEXTURE_CUBE_MAP_POSITIVE_X + face + (currentFace ? currentFace : 0));
 
                 width = header[off_width];
                 height = header[off_height];
@@ -462,14 +462,14 @@
 
                         if (!info.isCompressed && info.isFourCC) {
                             dataLength = width * height * 4;
-                            var FloatArray: Nullable<ArrayBufferView> = null;
+                            var floatArray: Nullable<ArrayBufferView> = null;
 
                             if (engine.badOS || engine.badDesktopOS || (!engine.getCaps().textureHalfFloat && !engine.getCaps().textureFloat)) { // Required because iOS has many issues with float and half float generation
                                 if (bpp === 128) {
-                                    FloatArray = DDSTools._GetFloatAsUIntRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);                                    
+                                    floatArray = DDSTools._GetFloatAsUIntRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);                                    
                                 }
                                 else if (bpp === 64) {
-                                    FloatArray = DDSTools._GetHalfFloatAsUIntRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
+                                    floatArray = DDSTools._GetHalfFloatAsUIntRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
                                 }
 
                                 info.textureType = Engine.TEXTURETYPE_UNSIGNED_INT;
@@ -478,20 +478,20 @@
                             }
                             else {
                                 if (bpp === 128) {
-                                    FloatArray = DDSTools._GetFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
+                                    floatArray = DDSTools._GetFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
                                 } else if (bpp === 64 && !engine.getCaps().textureHalfFloat) {
-                                    FloatArray = DDSTools._GetHalfFloatAsFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
+                                    floatArray = DDSTools._GetHalfFloatAsFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
 
                                     info.textureType = Engine.TEXTURETYPE_FLOAT;
                                     format = engine._getWebGLTextureType(info.textureType);    
                                     internalFormat = engine._getRGBABufferInternalSizedFormat(info.textureType);                            
                                 } else { // 64
-                                    FloatArray = DDSTools._GetHalfFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
+                                    floatArray = DDSTools._GetHalfFloatRGBAArrayBuffer(width, height, dataOffset, dataLength, arrayBuffer, i);
                                 }
                             }
 
-                            if (FloatArray) {
-                                engine._uploadDataToTexture(sampler, i, internalFormat, width, height, gl.RGBA, format, FloatArray);
+                            if (floatArray) {
+                                engine._uploadDataToTexture(sampler, i, internalFormat, width, height, gl.RGBA, format, floatArray);
                             }
                         } else if (info.isRGB) {
                             if (bpp === 24) {
@@ -523,6 +523,11 @@
 
                     width = Math.max(1.0, width);
                     height = Math.max(1.0, height);
+
+                    if (currentFace) {
+                        // Loading a single face
+                        break;
+                    }
                 }
             }
         }

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

@@ -484,7 +484,7 @@
             return img;
         }
 
-        public static LoadFile(url: string, callback: (data: any, responseURL?: string) => void, progressCallBack?: (data: any) => void, database?: Database, useArrayBuffer?: boolean, onError?: (request?: XMLHttpRequest, exception?: any) => void): Nullable<XMLHttpRequest> {
+        public static LoadFile(url: string, callback: (data: string | ArrayBuffer, responseURL?: string) => void, progressCallBack?: (data: any) => void, database?: Database, useArrayBuffer?: boolean, onError?: (request?: XMLHttpRequest, exception?: any) => void): Nullable<XMLHttpRequest> {
             url = Tools.CleanUrl(url);
 
             url = Tools.PreprocessUrl(url);
@@ -511,7 +511,7 @@
                         req.onreadystatechange = () => { };//some browsers have issues where onreadystatechange can be called multiple times with the same value
 
                         if (req.status >= 200 && req.status < 300 || (!Tools.IsWindowObjectExist() && (req.status === 0))) {
-                            callback(!useArrayBuffer ? req.responseText : req.response, req.responseURL);
+                            callback(!useArrayBuffer ? req.responseText : <ArrayBuffer>req.response, req.responseURL);
                         } else { // Failed
                             let e = new Error("Error status: " + req.status + " - Unable to load " + loadUrl);
                             if (onError) {