Browse Source

new rescaler (now based on shaders)

David Catuhe 8 years ago
parent
commit
a25a27a8ac
4 changed files with 2957 additions and 2898 deletions
  1. 1418 1413
      dist/preview release/babylon.d.ts
  2. 1418 1413
      dist/preview release/babylon.module.d.ts
  3. 2 2
      src/Materials/babylon.effect.ts
  4. 119 70
      src/babylon.engine.ts

File diff suppressed because it is too large
+ 1418 - 1413
dist/preview release/babylon.d.ts


File diff suppressed because it is too large
+ 1418 - 1413
dist/preview release/babylon.module.d.ts


+ 2 - 2
src/Materials/babylon.effect.ts

@@ -254,8 +254,7 @@
                 return;
             }
             
-            var observer = this.onCompileObservable.add((effect) => {
-                this.onCompileObservable.remove(observer);
+            this.onCompileObservable.add((effect) => {
                 func(effect);
             });
         }
@@ -534,6 +533,7 @@
                     this.onCompiled(this);
                 }
                 this.onCompileObservable.notifyObservers(this);
+                this.onCompileObservable.clear();
             } catch (e) {
                 this._compilationError = e.message;
 

+ 119 - 70
src/babylon.engine.ts

@@ -103,48 +103,7 @@
             mag: magFilter
         }
     }
-
-    var prepareWebGLTexture = (texture: WebGLTexture, gl: WebGLRenderingContext, scene: Scene, width: number, height: number, invertY: boolean, noMipmap: boolean, isCompressed: boolean,
-        processFunction: (width: number, height: number) => void, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE) => {
-        var engine = scene.getEngine();
-        if (!engine) {
-            return;
-        }
-
-        var potWidth = engine.needPOTTextures ? Tools.GetExponentOfTwo(width, engine.getCaps().maxTextureSize) : width;
-        var potHeight = engine.needPOTTextures ? Tools.GetExponentOfTwo(height, engine.getCaps().maxTextureSize) : height;
-
-        engine._bindTextureDirectly(gl.TEXTURE_2D, texture);
-        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? 1 : (invertY ? 1 : 0));
-
-        texture._baseWidth = width;
-        texture._baseHeight = height;
-        texture._width = potWidth;
-        texture._height = potHeight;
-        texture.isReady = true;
-
-        processFunction(potWidth, potHeight);
-
-        var filters = getSamplingParameters(samplingMode, !noMipmap, gl);
-
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filters.mag);
-        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filters.min);
-
-        if (!noMipmap && !isCompressed) {
-            gl.generateMipmap(gl.TEXTURE_2D);
-        }
-
-        engine._bindTextureDirectly(gl.TEXTURE_2D, null);
-
-        engine.resetTextureCache();
-        scene._removePendingData(texture);
-
-        texture.onLoadedCallbacks.forEach(callback => {
-            callback();
-        });
-        texture.onLoadedCallbacks = [];
-    };
-
+  
     var partialLoad = (url: string, index: number, loadedImages: any, scene,
         onfinish: (images: HTMLImageElement[]) => void, onErrorCallBack: () => void = null) => {
 
@@ -662,6 +621,7 @@
 
         private _workingCanvas: HTMLCanvasElement;
         private _workingContext: CanvasRenderingContext2D;
+        private _rescalePostProcess: PassPostProcess;
 
         private _dummyFramebuffer: WebGLFramebuffer;
 
@@ -2585,8 +2545,9 @@
                     callback = (data) => {
                         var ktx = new Internals.KhronosTextureContainer(data, 1);
 
-                        prepareWebGLTexture(texture, this._gl, scene, ktx.pixelWidth, ktx.pixelHeight, invertY, false, true, () => {
+                        this._prepareWebGLTexture(texture, scene, ktx.pixelWidth, ktx.pixelHeight, invertY, false, true, () => {
                             ktx.uploadLevels(this._gl, !noMipmap);
+                            return false;
                         }, samplingMode);
                     };
                 } else if (isTGA) {
@@ -2595,8 +2556,9 @@
 
                         var header = Internals.TGATools.GetTGAHeader(data);
 
-                        prepareWebGLTexture(texture, this._gl, scene, header.width, header.height, invertY, noMipmap, false, () => {
+                        this._prepareWebGLTexture(texture, scene, header.width, header.height, invertY, noMipmap, false, () => {
                             Internals.TGATools.UploadContent(this._gl, data);
+                            return false;
                         }, samplingMode);
                     };
 
@@ -2605,8 +2567,9 @@
                         var info = Internals.DDSTools.GetDDSInfo(data);
 
                         var loadMipmap = (info.isRGB || info.isLuminance || info.mipmapCount > 1) && !noMipmap && ((info.width >> (info.mipmapCount - 1)) === 1);
-                        prepareWebGLTexture(texture, this._gl, scene, info.width, info.height, invertY, !loadMipmap, info.isFourCC, () => {
+                        this._prepareWebGLTexture(texture, scene, info.width, info.height, invertY, !loadMipmap, info.isFourCC, () => {
                             Internals.DDSTools.UploadDDSLevels(this, data, info, loadMipmap, 1);
+                            return false;
                         }, samplingMode);
                     };
                 }
@@ -2621,34 +2584,34 @@
                 // image format processing
             } else {
                 var onload = (img) => {
-                    prepareWebGLTexture(texture, this._gl, scene, img.width, img.height, invertY, noMipmap, false, (potWidth, potHeight) => {
+                    this._prepareWebGLTexture(texture, scene, img.width, img.height, invertY, noMipmap, false, (potWidth, potHeight, continuationCallback) => {
+                        let gl = this._gl;
                         var isPot = (img.width === potWidth && img.height === potHeight);
-                        if (!isPot) {
-                            this._prepareWorkingCanvas();
-                            this._workingCanvas.width = potWidth;
-                            this._workingCanvas.height = potHeight;
-
-                            if (samplingMode === Texture.NEAREST_SAMPLINGMODE) {
-                                this._workingContext.imageSmoothingEnabled = false;
-                                this._workingContext.mozImageSmoothingEnabled = false;
-                                this._workingContext.oImageSmoothingEnabled = false;
-                                this._workingContext.webkitImageSmoothingEnabled = false;
-                                this._workingContext.msImageSmoothingEnabled = false;
-                            }
-
-                            this._workingContext.drawImage(img, 0, 0, img.width, img.height, 0, 0, potWidth, potHeight);
+                        let internalFormat = format ? this._getInternalFormat(format) : ((extension === ".jpg") ? gl.RGB : gl.RGBA);
 
-                            if (samplingMode === Texture.NEAREST_SAMPLINGMODE) {
-                                this._workingContext.imageSmoothingEnabled = true;
-                                this._workingContext.mozImageSmoothingEnabled = true;
-                                this._workingContext.oImageSmoothingEnabled = true;
-                                this._workingContext.webkitImageSmoothingEnabled = true;
-                                this._workingContext.msImageSmoothingEnabled = true;
-                            }
+                        if (isPot) {
+                            gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, internalFormat, gl.UNSIGNED_BYTE, img);
+                            return false;
                         }
 
-                        let internalFormat = format ? this._getInternalFormat(format) : ((extension === ".jpg") ? this._gl.RGB : this._gl.RGBA);
-                        this._gl.texImage2D(this._gl.TEXTURE_2D, 0, internalFormat, internalFormat, this._gl.UNSIGNED_BYTE, isPot ? img : this._workingCanvas);
+                        // Using shaders to rescale because canvas.drawImage is lossy
+                        let source = gl.createTexture();
+                        this._bindTextureDirectly(gl.TEXTURE_2D, source);
+                        gl.texImage2D(gl.TEXTURE_2D, 0, internalFormat, internalFormat, gl.UNSIGNED_BYTE, img);
+
+                        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+                        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+                        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+                        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);                        
+
+                        this._rescaleTexture(source, texture, scene, internalFormat, () => {
+                            this._releaseTexture(source);
+                            this._bindTextureDirectly(gl.TEXTURE_2D, texture);
+
+                            continuationCallback();
+                        });
+
+                        return true;
                     }, samplingMode);
                 };
 
@@ -2663,6 +2626,41 @@
             return texture;
         }
 
+        private _rescaleTexture(source: WebGLTexture, destination: WebGLTexture, scene: Scene, internalFormat: number, onComplete: () => void): void {
+            let rtt = this.createRenderTargetTexture({
+                    width: destination._width,
+                    height: destination._height,
+                }, {
+                    generateMipMaps: false,
+                    type: Engine.TEXTURETYPE_UNSIGNED_INT,
+                    samplingMode: Texture.BILINEAR_SAMPLINGMODE,
+                    generateDepthBuffer: false,
+                    generateStencilBuffer: false
+                }
+            );
+
+            if (!this._rescalePostProcess) {
+                this._rescalePostProcess = new BABYLON.PassPostProcess("rescale", 1, null, Texture.BILINEAR_SAMPLINGMODE, this, false, Engine.TEXTURETYPE_UNSIGNED_INT);
+            }
+			this._rescalePostProcess.getEffect().executeWhenCompiled(() => {
+                this._rescalePostProcess.onApply = function (effect) {
+                    effect._bindTexture("textureSampler", source);
+                }
+
+                scene.postProcessManager.directRender([this._rescalePostProcess], rtt);
+
+                this._bindTextureDirectly(this._gl.TEXTURE_2D, destination);
+                this._gl.copyTexImage2D(this._gl.TEXTURE_2D, 0, internalFormat, 0, 0, destination._width, destination._height, 0);
+
+                this.unBindFramebuffer(rtt);
+                this._releaseTexture(rtt);
+                
+                if (onComplete) {
+                    onComplete();
+                }
+            });
+        }
+
         private _getInternalFormat(format: number): number {
             var internalFormat = this._gl.RGBA;
             switch (format) {
@@ -3656,6 +3654,53 @@
             return texture;
         };
 
+        private _prepareWebGLTextureContinuation(texture: WebGLTexture, scene: Scene, noMipmap: boolean, isCompressed: boolean, samplingMode: number): void {
+            var gl = this._gl;
+            var filters = getSamplingParameters(samplingMode, !noMipmap, gl);
+
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filters.mag);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filters.min);
+
+            if (!noMipmap && !isCompressed) {
+                gl.generateMipmap(gl.TEXTURE_2D);
+            }
+
+            this._bindTextureDirectly(gl.TEXTURE_2D, null);
+
+            this.resetTextureCache();
+            scene._removePendingData(texture);
+
+            texture.onLoadedCallbacks.forEach(callback => {
+                callback();
+            });
+            texture.onLoadedCallbacks = [];
+        }
+
+        private _prepareWebGLTexture(texture: WebGLTexture, scene: Scene, width: number, height: number, invertY: boolean, noMipmap: boolean, isCompressed: boolean,
+                                        processFunction: (width: number, height: number, continuationCallback: () => void) => boolean, samplingMode: number = Texture.TRILINEAR_SAMPLINGMODE): void {
+            var potWidth = this.needPOTTextures ? Tools.GetExponentOfTwo(width, this.getCaps().maxTextureSize) : width;
+            var potHeight = this.needPOTTextures ? Tools.GetExponentOfTwo(height, this.getCaps().maxTextureSize) : height;
+
+            var gl = this._gl;
+            this._bindTextureDirectly(gl.TEXTURE_2D, texture);
+            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, invertY === undefined ? 1 : (invertY ? 1 : 0));
+
+            texture._baseWidth = width;
+            texture._baseHeight = height;
+            texture._width = potWidth;
+            texture._height = potHeight;
+            texture.isReady = true;
+
+            if (processFunction(potWidth, potHeight, () => {
+                this._prepareWebGLTextureContinuation(texture, scene, noMipmap, isCompressed, samplingMode);
+            })) {
+                // Returning as texture needs extra async steps
+                return;
+            }         
+
+            this._prepareWebGLTextureContinuation(texture, scene, noMipmap, isCompressed, samplingMode);
+        }
+
         private _convertRGBtoRGBATextureData(rgbData: ArrayBufferView, width: number, height: number, textureType: number): ArrayBufferView {
             // Create new RGBA data container.
             var rgbaData: ArrayBufferView;
@@ -3820,7 +3865,6 @@
                 return;
             }
 
-
             var internalTexture = texture.isReady() ? texture.getInternalTexture() :
                 (texture.isCube ? this.emptyCubeTexture : this.emptyTexture);
 
@@ -4047,6 +4091,11 @@
                 this._emptyCubeTexture = null;
             }
 
+            // Rescale PP
+            if (this._rescalePostProcess) {
+                this._rescalePostProcess.dispose();
+            }
+
             // Release scenes
             while (this.scenes.length) {
                 this.scenes[0].dispose();