diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 401042c..78b8b52 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -33,7 +33,7 @@ utils.sayHello('webGL'); WebGLRenderer._TEMP__ = this; - + if (options) { for (var i in CONST.defaultRenderOptions) @@ -351,7 +351,7 @@ this.setRenderTarget(renderTarget); - + // reset the render session data.. this.drawCount = 0; @@ -383,6 +383,7 @@ { this.currentRenderTarget = renderTarget; this.currentRenderTarget.activate(); + this.stencilManager.setMaskStack( renderTarget.stencilMaskStack ); }; /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 401042c..78b8b52 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -33,7 +33,7 @@ utils.sayHello('webGL'); WebGLRenderer._TEMP__ = this; - + if (options) { for (var i in CONST.defaultRenderOptions) @@ -351,7 +351,7 @@ this.setRenderTarget(renderTarget); - + // reset the render session data.. this.drawCount = 0; @@ -383,6 +383,7 @@ { this.currentRenderTarget = renderTarget; this.currentRenderTarget.activate(); + this.stencilManager.setMaskStack( renderTarget.stencilMaskStack ); }; /** diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index b998aef..c419356 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -47,7 +47,7 @@ FilterManager.prototype.onContextChange = function () { this.texturePool.length = 0; - + var gl = this.renderer.gl; this.quad = new Quad(gl); }; @@ -80,12 +80,12 @@ // set the frame so the render target knows how much to render! texture.frame = bounds; - + this.renderer.setRenderTarget( texture ); // clear the texture.. texture.clear(); - + // TODO get rid of object creation! this.filterStack.push({ renderTarget:texture, @@ -107,12 +107,12 @@ var input = filterData.renderTarget; var output = previousFilterData.renderTarget; - + // use program var gl = this.renderer.gl; var filter = filterData.filter[0]; - + this.currentFrame = input.frame; this.quad.map(this.textureSize, input.frame); @@ -131,7 +131,7 @@ FilterManager.prototype.getRenderTarget = function () { var renderTarget = this.texturePool.pop() || new RenderTarget(this.renderer.gl, this.textureSize.width, this.textureSize.height); - renderTarget.frame = this.currentFrame; + renderTarget.frame = this.currentFrame; return renderTarget; }; @@ -154,7 +154,7 @@ // set the shader this.renderer.shaderManager.setShader(shader); - + shader.uniforms.projectionMatrix.value = this.renderer.currentRenderTarget.projectionMatrix.toArray(true); //TODO can this be optimised? @@ -183,7 +183,7 @@ var ratio = this.textureSize.height / this.textureSize.width; mappedMatrix.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height ); - + mappedMatrix.scale(1 , ratio); var translateScaleX = (this.textureSize.width / texture.width); @@ -213,13 +213,13 @@ // var ratio = this.textureSize.height / this.textureSize.width; // m.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height); - + // m.scale(1 , ratio); // var transform = wt.clone(); - + // var translateScaleX = (this.textureSize.width / 620); // var translateScaleY = (this.textureSize.height / 380); diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 401042c..78b8b52 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -33,7 +33,7 @@ utils.sayHello('webGL'); WebGLRenderer._TEMP__ = this; - + if (options) { for (var i in CONST.defaultRenderOptions) @@ -351,7 +351,7 @@ this.setRenderTarget(renderTarget); - + // reset the render session data.. this.drawCount = 0; @@ -383,6 +383,7 @@ { this.currentRenderTarget = renderTarget; this.currentRenderTarget.activate(); + this.stencilManager.setMaskStack( renderTarget.stencilMaskStack ); }; /** diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index b998aef..c419356 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -47,7 +47,7 @@ FilterManager.prototype.onContextChange = function () { this.texturePool.length = 0; - + var gl = this.renderer.gl; this.quad = new Quad(gl); }; @@ -80,12 +80,12 @@ // set the frame so the render target knows how much to render! texture.frame = bounds; - + this.renderer.setRenderTarget( texture ); // clear the texture.. texture.clear(); - + // TODO get rid of object creation! this.filterStack.push({ renderTarget:texture, @@ -107,12 +107,12 @@ var input = filterData.renderTarget; var output = previousFilterData.renderTarget; - + // use program var gl = this.renderer.gl; var filter = filterData.filter[0]; - + this.currentFrame = input.frame; this.quad.map(this.textureSize, input.frame); @@ -131,7 +131,7 @@ FilterManager.prototype.getRenderTarget = function () { var renderTarget = this.texturePool.pop() || new RenderTarget(this.renderer.gl, this.textureSize.width, this.textureSize.height); - renderTarget.frame = this.currentFrame; + renderTarget.frame = this.currentFrame; return renderTarget; }; @@ -154,7 +154,7 @@ // set the shader this.renderer.shaderManager.setShader(shader); - + shader.uniforms.projectionMatrix.value = this.renderer.currentRenderTarget.projectionMatrix.toArray(true); //TODO can this be optimised? @@ -183,7 +183,7 @@ var ratio = this.textureSize.height / this.textureSize.width; mappedMatrix.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height ); - + mappedMatrix.scale(1 , ratio); var translateScaleX = (this.textureSize.width / texture.width); @@ -213,13 +213,13 @@ // var ratio = this.textureSize.height / this.textureSize.width; // m.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height); - + // m.scale(1 , ratio); // var transform = wt.clone(); - + // var translateScaleX = (this.textureSize.width / 620); // var translateScaleY = (this.textureSize.height / 380); diff --git a/src/core/renderers/webgl/managers/MaskManager.js b/src/core/renderers/webgl/managers/MaskManager.js index 732438d..8abe133 100644 --- a/src/core/renderers/webgl/managers/MaskManager.js +++ b/src/core/renderers/webgl/managers/MaskManager.js @@ -55,7 +55,7 @@ MaskManager.prototype.pushSpriteMask = function (target, maskData) { var alphaMaskFilter = this.alphaMaskPool.pop(); - + if (!alphaMaskFilter) { alphaMaskFilter = [new AlphaMaskFilter(maskData)]; @@ -84,6 +84,7 @@ MaskManager.prototype.pushStencilMask = function (target, maskData) { + this.renderer.currentRenderTarget.attachStenilBuffer(); this.renderer.stencilManager.pushMask(maskData); }; diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 401042c..78b8b52 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -33,7 +33,7 @@ utils.sayHello('webGL'); WebGLRenderer._TEMP__ = this; - + if (options) { for (var i in CONST.defaultRenderOptions) @@ -351,7 +351,7 @@ this.setRenderTarget(renderTarget); - + // reset the render session data.. this.drawCount = 0; @@ -383,6 +383,7 @@ { this.currentRenderTarget = renderTarget; this.currentRenderTarget.activate(); + this.stencilManager.setMaskStack( renderTarget.stencilMaskStack ); }; /** diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index b998aef..c419356 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -47,7 +47,7 @@ FilterManager.prototype.onContextChange = function () { this.texturePool.length = 0; - + var gl = this.renderer.gl; this.quad = new Quad(gl); }; @@ -80,12 +80,12 @@ // set the frame so the render target knows how much to render! texture.frame = bounds; - + this.renderer.setRenderTarget( texture ); // clear the texture.. texture.clear(); - + // TODO get rid of object creation! this.filterStack.push({ renderTarget:texture, @@ -107,12 +107,12 @@ var input = filterData.renderTarget; var output = previousFilterData.renderTarget; - + // use program var gl = this.renderer.gl; var filter = filterData.filter[0]; - + this.currentFrame = input.frame; this.quad.map(this.textureSize, input.frame); @@ -131,7 +131,7 @@ FilterManager.prototype.getRenderTarget = function () { var renderTarget = this.texturePool.pop() || new RenderTarget(this.renderer.gl, this.textureSize.width, this.textureSize.height); - renderTarget.frame = this.currentFrame; + renderTarget.frame = this.currentFrame; return renderTarget; }; @@ -154,7 +154,7 @@ // set the shader this.renderer.shaderManager.setShader(shader); - + shader.uniforms.projectionMatrix.value = this.renderer.currentRenderTarget.projectionMatrix.toArray(true); //TODO can this be optimised? @@ -183,7 +183,7 @@ var ratio = this.textureSize.height / this.textureSize.width; mappedMatrix.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height ); - + mappedMatrix.scale(1 , ratio); var translateScaleX = (this.textureSize.width / texture.width); @@ -213,13 +213,13 @@ // var ratio = this.textureSize.height / this.textureSize.width; // m.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height); - + // m.scale(1 , ratio); // var transform = wt.clone(); - + // var translateScaleX = (this.textureSize.width / 620); // var translateScaleY = (this.textureSize.height / 380); diff --git a/src/core/renderers/webgl/managers/MaskManager.js b/src/core/renderers/webgl/managers/MaskManager.js index 732438d..8abe133 100644 --- a/src/core/renderers/webgl/managers/MaskManager.js +++ b/src/core/renderers/webgl/managers/MaskManager.js @@ -55,7 +55,7 @@ MaskManager.prototype.pushSpriteMask = function (target, maskData) { var alphaMaskFilter = this.alphaMaskPool.pop(); - + if (!alphaMaskFilter) { alphaMaskFilter = [new AlphaMaskFilter(maskData)]; @@ -84,6 +84,7 @@ MaskManager.prototype.pushStencilMask = function (target, maskData) { + this.renderer.currentRenderTarget.attachStenilBuffer(); this.renderer.stencilManager.pushMask(maskData); }; diff --git a/src/core/renderers/webgl/managers/StencilManager.js b/src/core/renderers/webgl/managers/StencilManager.js index 741ca8b..c93e061 100644 --- a/src/core/renderers/webgl/managers/StencilManager.js +++ b/src/core/renderers/webgl/managers/StencilManager.js @@ -9,16 +9,29 @@ function WebGLMaskManager(renderer) { WebGLManager.call(this, renderer); - - this.stencilStack = []; - this.reverse = true; - this.count = 0; + this.stencilMaskStack = null; } WebGLMaskManager.prototype = Object.create(WebGLManager.prototype); WebGLMaskManager.prototype.constructor = WebGLMaskManager; module.exports = WebGLMaskManager; +WebGLMaskManager.prototype.setMaskStack = function ( stencilMaskStack ) +{ + this.stencilMaskStack = stencilMaskStack; + + var gl = this.renderer.gl; + + if(stencilMaskStack.stencilStack.length === 0) + { + gl.disable(gl.STENCIL_TEST); + } + else + { + gl.enable(gl.STENCIL_TEST); + } +}; + /** * Applies the Mask and adds it to the current filter stack. * @@ -27,21 +40,22 @@ */ WebGLMaskManager.prototype.pushStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; this.bindGraphics(graphics, webGLData, this.renderer); - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { gl.enable(gl.STENCIL_TEST); gl.clear(gl.STENCIL_BUFFER_BIT); - this.reverse = true; - this.count = 0; + sms.reverse = true; + sms.count = 0; } - this.stencilStack.push(webGLData); + sms.stencilStack.push(webGLData); - var level = this.count; + var level = sms.count; gl.colorMask(false, false, false, false); @@ -54,7 +68,7 @@ { gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -68,7 +82,7 @@ // draw a quad to increment.. gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -77,11 +91,11 @@ gl.stencilFunc(gl.EQUAL,level+1, 0xFF); } - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; } else { - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -94,7 +108,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -107,7 +121,7 @@ gl.colorMask(true, true, true, true); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - this.count++; + sms.count++; }; /** @@ -182,13 +196,14 @@ */ WebGLMaskManager.prototype.popStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; - this.stencilStack.pop(); + sms.stencilStack.pop(); - this.count--; + sms.count--; - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { // the stack is empty! gl.disable(gl.STENCIL_TEST); @@ -197,7 +212,7 @@ else { - var level = this.count; + var level = sms.count; this.bindGraphics(graphics, webGLData, this.renderer); @@ -205,9 +220,9 @@ if (webGLData.mode === 1) { - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -227,7 +242,7 @@ // draw the triangle strip! gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -240,7 +255,7 @@ else { // console.log("<<>>") - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -253,7 +268,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -278,7 +293,7 @@ { WebGLManager.prototype.destroy.call(this); - this.stencilStack = null; + this.stencilMaskStack.stencilStack = null; }; /** diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 401042c..78b8b52 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -33,7 +33,7 @@ utils.sayHello('webGL'); WebGLRenderer._TEMP__ = this; - + if (options) { for (var i in CONST.defaultRenderOptions) @@ -351,7 +351,7 @@ this.setRenderTarget(renderTarget); - + // reset the render session data.. this.drawCount = 0; @@ -383,6 +383,7 @@ { this.currentRenderTarget = renderTarget; this.currentRenderTarget.activate(); + this.stencilManager.setMaskStack( renderTarget.stencilMaskStack ); }; /** diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index b998aef..c419356 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -47,7 +47,7 @@ FilterManager.prototype.onContextChange = function () { this.texturePool.length = 0; - + var gl = this.renderer.gl; this.quad = new Quad(gl); }; @@ -80,12 +80,12 @@ // set the frame so the render target knows how much to render! texture.frame = bounds; - + this.renderer.setRenderTarget( texture ); // clear the texture.. texture.clear(); - + // TODO get rid of object creation! this.filterStack.push({ renderTarget:texture, @@ -107,12 +107,12 @@ var input = filterData.renderTarget; var output = previousFilterData.renderTarget; - + // use program var gl = this.renderer.gl; var filter = filterData.filter[0]; - + this.currentFrame = input.frame; this.quad.map(this.textureSize, input.frame); @@ -131,7 +131,7 @@ FilterManager.prototype.getRenderTarget = function () { var renderTarget = this.texturePool.pop() || new RenderTarget(this.renderer.gl, this.textureSize.width, this.textureSize.height); - renderTarget.frame = this.currentFrame; + renderTarget.frame = this.currentFrame; return renderTarget; }; @@ -154,7 +154,7 @@ // set the shader this.renderer.shaderManager.setShader(shader); - + shader.uniforms.projectionMatrix.value = this.renderer.currentRenderTarget.projectionMatrix.toArray(true); //TODO can this be optimised? @@ -183,7 +183,7 @@ var ratio = this.textureSize.height / this.textureSize.width; mappedMatrix.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height ); - + mappedMatrix.scale(1 , ratio); var translateScaleX = (this.textureSize.width / texture.width); @@ -213,13 +213,13 @@ // var ratio = this.textureSize.height / this.textureSize.width; // m.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height); - + // m.scale(1 , ratio); // var transform = wt.clone(); - + // var translateScaleX = (this.textureSize.width / 620); // var translateScaleY = (this.textureSize.height / 380); diff --git a/src/core/renderers/webgl/managers/MaskManager.js b/src/core/renderers/webgl/managers/MaskManager.js index 732438d..8abe133 100644 --- a/src/core/renderers/webgl/managers/MaskManager.js +++ b/src/core/renderers/webgl/managers/MaskManager.js @@ -55,7 +55,7 @@ MaskManager.prototype.pushSpriteMask = function (target, maskData) { var alphaMaskFilter = this.alphaMaskPool.pop(); - + if (!alphaMaskFilter) { alphaMaskFilter = [new AlphaMaskFilter(maskData)]; @@ -84,6 +84,7 @@ MaskManager.prototype.pushStencilMask = function (target, maskData) { + this.renderer.currentRenderTarget.attachStenilBuffer(); this.renderer.stencilManager.pushMask(maskData); }; diff --git a/src/core/renderers/webgl/managers/StencilManager.js b/src/core/renderers/webgl/managers/StencilManager.js index 741ca8b..c93e061 100644 --- a/src/core/renderers/webgl/managers/StencilManager.js +++ b/src/core/renderers/webgl/managers/StencilManager.js @@ -9,16 +9,29 @@ function WebGLMaskManager(renderer) { WebGLManager.call(this, renderer); - - this.stencilStack = []; - this.reverse = true; - this.count = 0; + this.stencilMaskStack = null; } WebGLMaskManager.prototype = Object.create(WebGLManager.prototype); WebGLMaskManager.prototype.constructor = WebGLMaskManager; module.exports = WebGLMaskManager; +WebGLMaskManager.prototype.setMaskStack = function ( stencilMaskStack ) +{ + this.stencilMaskStack = stencilMaskStack; + + var gl = this.renderer.gl; + + if(stencilMaskStack.stencilStack.length === 0) + { + gl.disable(gl.STENCIL_TEST); + } + else + { + gl.enable(gl.STENCIL_TEST); + } +}; + /** * Applies the Mask and adds it to the current filter stack. * @@ -27,21 +40,22 @@ */ WebGLMaskManager.prototype.pushStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; this.bindGraphics(graphics, webGLData, this.renderer); - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { gl.enable(gl.STENCIL_TEST); gl.clear(gl.STENCIL_BUFFER_BIT); - this.reverse = true; - this.count = 0; + sms.reverse = true; + sms.count = 0; } - this.stencilStack.push(webGLData); + sms.stencilStack.push(webGLData); - var level = this.count; + var level = sms.count; gl.colorMask(false, false, false, false); @@ -54,7 +68,7 @@ { gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -68,7 +82,7 @@ // draw a quad to increment.. gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -77,11 +91,11 @@ gl.stencilFunc(gl.EQUAL,level+1, 0xFF); } - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; } else { - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -94,7 +108,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -107,7 +121,7 @@ gl.colorMask(true, true, true, true); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - this.count++; + sms.count++; }; /** @@ -182,13 +196,14 @@ */ WebGLMaskManager.prototype.popStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; - this.stencilStack.pop(); + sms.stencilStack.pop(); - this.count--; + sms.count--; - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { // the stack is empty! gl.disable(gl.STENCIL_TEST); @@ -197,7 +212,7 @@ else { - var level = this.count; + var level = sms.count; this.bindGraphics(graphics, webGLData, this.renderer); @@ -205,9 +220,9 @@ if (webGLData.mode === 1) { - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -227,7 +242,7 @@ // draw the triangle strip! gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -240,7 +255,7 @@ else { // console.log("<<>>") - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -253,7 +268,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -278,7 +293,7 @@ { WebGLManager.prototype.destroy.call(this); - this.stencilStack = null; + this.stencilMaskStack.stencilStack = null; }; /** diff --git a/src/core/renderers/webgl/utils/FilterTexture.js b/src/core/renderers/webgl/utils/FilterTexture.js deleted file mode 100644 index 4433d44..0000000 --- a/src/core/renderers/webgl/utils/FilterTexture.js +++ /dev/null @@ -1,111 +0,0 @@ -var CONST = require('../../../const'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - * @param width {number} the horizontal range of the filter - * @param height {number} the vertical range of the filter - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - */ -function FilterTexture(gl, width, height, scaleMode) -{ - /** - * @member {WebGLContext} - */ - this.gl = gl; - - // next time to create a frame buffer and texture - - /** - * @member {Any} - */ - this.frameBuffer = gl.createFramebuffer(); - - /** - * @member {Any} - */ - this.texture = gl.createTexture(); - - /** - * @member {number} - */ - scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - 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); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - // required for masking a mask?? - this.renderBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); - - this.resize(width, height); -} - -FilterTexture.prototype.constructor = FilterTexture; -module.exports = FilterTexture; - -/** - * Clears the filter texture. - * - */ -FilterTexture.prototype.clear = function () -{ - var gl = this.gl; - - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); -}; - -/** - * Resizes the texture to the specified width and height - * - * @param width {number} the new width of the texture - * @param height {number} the new height of the texture - */ -FilterTexture.prototype.resize = function (width, height) -{ - if (this.width === width && this.height === height) - { - return; - } - - this.width = width; - this.height = height; - - var gl = this.gl; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - // update the stencil buffer width and height - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); -}; - -/** - * Destroys the filter texture. - * - */ -FilterTexture.prototype.destroy = function () -{ - var gl = this.gl; - gl.deleteFramebuffer( this.frameBuffer ); - gl.deleteTexture( this.texture ); - - this.frameBuffer = null; - this.texture = null; -}; diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 401042c..78b8b52 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -33,7 +33,7 @@ utils.sayHello('webGL'); WebGLRenderer._TEMP__ = this; - + if (options) { for (var i in CONST.defaultRenderOptions) @@ -351,7 +351,7 @@ this.setRenderTarget(renderTarget); - + // reset the render session data.. this.drawCount = 0; @@ -383,6 +383,7 @@ { this.currentRenderTarget = renderTarget; this.currentRenderTarget.activate(); + this.stencilManager.setMaskStack( renderTarget.stencilMaskStack ); }; /** diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index b998aef..c419356 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -47,7 +47,7 @@ FilterManager.prototype.onContextChange = function () { this.texturePool.length = 0; - + var gl = this.renderer.gl; this.quad = new Quad(gl); }; @@ -80,12 +80,12 @@ // set the frame so the render target knows how much to render! texture.frame = bounds; - + this.renderer.setRenderTarget( texture ); // clear the texture.. texture.clear(); - + // TODO get rid of object creation! this.filterStack.push({ renderTarget:texture, @@ -107,12 +107,12 @@ var input = filterData.renderTarget; var output = previousFilterData.renderTarget; - + // use program var gl = this.renderer.gl; var filter = filterData.filter[0]; - + this.currentFrame = input.frame; this.quad.map(this.textureSize, input.frame); @@ -131,7 +131,7 @@ FilterManager.prototype.getRenderTarget = function () { var renderTarget = this.texturePool.pop() || new RenderTarget(this.renderer.gl, this.textureSize.width, this.textureSize.height); - renderTarget.frame = this.currentFrame; + renderTarget.frame = this.currentFrame; return renderTarget; }; @@ -154,7 +154,7 @@ // set the shader this.renderer.shaderManager.setShader(shader); - + shader.uniforms.projectionMatrix.value = this.renderer.currentRenderTarget.projectionMatrix.toArray(true); //TODO can this be optimised? @@ -183,7 +183,7 @@ var ratio = this.textureSize.height / this.textureSize.width; mappedMatrix.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height ); - + mappedMatrix.scale(1 , ratio); var translateScaleX = (this.textureSize.width / texture.width); @@ -213,13 +213,13 @@ // var ratio = this.textureSize.height / this.textureSize.width; // m.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height); - + // m.scale(1 , ratio); // var transform = wt.clone(); - + // var translateScaleX = (this.textureSize.width / 620); // var translateScaleY = (this.textureSize.height / 380); diff --git a/src/core/renderers/webgl/managers/MaskManager.js b/src/core/renderers/webgl/managers/MaskManager.js index 732438d..8abe133 100644 --- a/src/core/renderers/webgl/managers/MaskManager.js +++ b/src/core/renderers/webgl/managers/MaskManager.js @@ -55,7 +55,7 @@ MaskManager.prototype.pushSpriteMask = function (target, maskData) { var alphaMaskFilter = this.alphaMaskPool.pop(); - + if (!alphaMaskFilter) { alphaMaskFilter = [new AlphaMaskFilter(maskData)]; @@ -84,6 +84,7 @@ MaskManager.prototype.pushStencilMask = function (target, maskData) { + this.renderer.currentRenderTarget.attachStenilBuffer(); this.renderer.stencilManager.pushMask(maskData); }; diff --git a/src/core/renderers/webgl/managers/StencilManager.js b/src/core/renderers/webgl/managers/StencilManager.js index 741ca8b..c93e061 100644 --- a/src/core/renderers/webgl/managers/StencilManager.js +++ b/src/core/renderers/webgl/managers/StencilManager.js @@ -9,16 +9,29 @@ function WebGLMaskManager(renderer) { WebGLManager.call(this, renderer); - - this.stencilStack = []; - this.reverse = true; - this.count = 0; + this.stencilMaskStack = null; } WebGLMaskManager.prototype = Object.create(WebGLManager.prototype); WebGLMaskManager.prototype.constructor = WebGLMaskManager; module.exports = WebGLMaskManager; +WebGLMaskManager.prototype.setMaskStack = function ( stencilMaskStack ) +{ + this.stencilMaskStack = stencilMaskStack; + + var gl = this.renderer.gl; + + if(stencilMaskStack.stencilStack.length === 0) + { + gl.disable(gl.STENCIL_TEST); + } + else + { + gl.enable(gl.STENCIL_TEST); + } +}; + /** * Applies the Mask and adds it to the current filter stack. * @@ -27,21 +40,22 @@ */ WebGLMaskManager.prototype.pushStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; this.bindGraphics(graphics, webGLData, this.renderer); - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { gl.enable(gl.STENCIL_TEST); gl.clear(gl.STENCIL_BUFFER_BIT); - this.reverse = true; - this.count = 0; + sms.reverse = true; + sms.count = 0; } - this.stencilStack.push(webGLData); + sms.stencilStack.push(webGLData); - var level = this.count; + var level = sms.count; gl.colorMask(false, false, false, false); @@ -54,7 +68,7 @@ { gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -68,7 +82,7 @@ // draw a quad to increment.. gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -77,11 +91,11 @@ gl.stencilFunc(gl.EQUAL,level+1, 0xFF); } - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; } else { - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -94,7 +108,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -107,7 +121,7 @@ gl.colorMask(true, true, true, true); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - this.count++; + sms.count++; }; /** @@ -182,13 +196,14 @@ */ WebGLMaskManager.prototype.popStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; - this.stencilStack.pop(); + sms.stencilStack.pop(); - this.count--; + sms.count--; - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { // the stack is empty! gl.disable(gl.STENCIL_TEST); @@ -197,7 +212,7 @@ else { - var level = this.count; + var level = sms.count; this.bindGraphics(graphics, webGLData, this.renderer); @@ -205,9 +220,9 @@ if (webGLData.mode === 1) { - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -227,7 +242,7 @@ // draw the triangle strip! gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -240,7 +255,7 @@ else { // console.log("<<>>") - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -253,7 +268,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -278,7 +293,7 @@ { WebGLManager.prototype.destroy.call(this); - this.stencilStack = null; + this.stencilMaskStack.stencilStack = null; }; /** diff --git a/src/core/renderers/webgl/utils/FilterTexture.js b/src/core/renderers/webgl/utils/FilterTexture.js deleted file mode 100644 index 4433d44..0000000 --- a/src/core/renderers/webgl/utils/FilterTexture.js +++ /dev/null @@ -1,111 +0,0 @@ -var CONST = require('../../../const'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - * @param width {number} the horizontal range of the filter - * @param height {number} the vertical range of the filter - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - */ -function FilterTexture(gl, width, height, scaleMode) -{ - /** - * @member {WebGLContext} - */ - this.gl = gl; - - // next time to create a frame buffer and texture - - /** - * @member {Any} - */ - this.frameBuffer = gl.createFramebuffer(); - - /** - * @member {Any} - */ - this.texture = gl.createTexture(); - - /** - * @member {number} - */ - scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - 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); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - // required for masking a mask?? - this.renderBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); - - this.resize(width, height); -} - -FilterTexture.prototype.constructor = FilterTexture; -module.exports = FilterTexture; - -/** - * Clears the filter texture. - * - */ -FilterTexture.prototype.clear = function () -{ - var gl = this.gl; - - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); -}; - -/** - * Resizes the texture to the specified width and height - * - * @param width {number} the new width of the texture - * @param height {number} the new height of the texture - */ -FilterTexture.prototype.resize = function (width, height) -{ - if (this.width === width && this.height === height) - { - return; - } - - this.width = width; - this.height = height; - - var gl = this.gl; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - // update the stencil buffer width and height - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); -}; - -/** - * Destroys the filter texture. - * - */ -FilterTexture.prototype.destroy = function () -{ - var gl = this.gl; - gl.deleteFramebuffer( this.frameBuffer ); - gl.deleteTexture( this.texture ); - - this.frameBuffer = null; - this.texture = null; -}; diff --git a/src/core/renderers/webgl/utils/RenderTarget.js b/src/core/renderers/webgl/utils/RenderTarget.js index 5789327..e7ed9da 100644 --- a/src/core/renderers/webgl/utils/RenderTarget.js +++ b/src/core/renderers/webgl/utils/RenderTarget.js @@ -1,5 +1,7 @@ var math = require('../../../math'), - CONST = require('../../../const'); + CONST = require('../../../const'), + //StencilManager = require('../managers/StencilManager'), + StencilMaskStack = require('./StencilMaskStack'); /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -13,10 +15,10 @@ * @param height {Number} the vertical range of the filter * @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values */ -var RenderTarget = function(gl, width, height, scaleMode, root) +var RenderTarget = function(gl, width, height, scaleMode, root, createStencilBuffer) { - //TODO Resolution could go here ( eg low res blurs ) - + //TODO Resolution could go here ( eg low res blurs ) + /** * @property gl * @type WebGLContext @@ -45,6 +47,9 @@ this.frame = null; + this.stencilBuffer = null; + this.stencilMaskStack = new StencilMaskStack(); + /** * @property scaleMode * @type Number @@ -58,7 +63,6 @@ // this.flipY = true; this.frameBuffer = gl.createFramebuffer(); - /* A frame buffer needs a target to render to.. create a texture and bind it attach it to the framebuffer.. @@ -76,20 +80,17 @@ gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - - - /* - The stencil buffer is used for masking in pixi - lets create one and then add attach it to the framebuffer.. - */ - this.stencilBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencilBuffer); } + this.resize(width, height); + if(createStencilBuffer) + { + this.attachStenilBuffer(); + } + + }; RenderTarget.prototype.constructor = RenderTarget; @@ -108,13 +109,36 @@ gl.clear(gl.COLOR_BUFFER_BIT); }; +RenderTarget.prototype.attachStenilBuffer = function() +{ + + if( this.stencilBuffer ) + { + return; + } + + /* + The stencil buffer is used for masking in pixi + lets create one and then add attach it to the framebuffer.. + */ + if(!this.root) + { + var gl = this.gl; + + this.stencilBuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, this.width , this.height ); + } +}; + RenderTarget.prototype.activate = function() { //TOOD refactor usage of frame.. var gl = this.gl; gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer); - + var projectionFrame = this.frame || this.size; // TODO add a dirty flag to this of a setter for the frame? @@ -134,7 +158,7 @@ pm.a = 1 / projectionFrame.width*2; pm.d = 1 / projectionFrame.height*2; - pm.tx = -1 - projectionFrame.x * pm.a; + pm.tx = -1 - projectionFrame.x * pm.a; pm.ty = -1 - projectionFrame.y * pm.d; } else @@ -142,7 +166,7 @@ pm.a = 1 / projectionFrame.width*2; pm.d = -1 / projectionFrame.height*2; - pm.tx = -1 - projectionFrame.x * pm.a; + pm.tx = -1 - projectionFrame.x * pm.a; pm.ty = 1 - projectionFrame.y * pm.d; } }; @@ -174,10 +198,13 @@ gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - - // update the stencil buffer width and height - gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height ); + + if(this.stencilBuffer ) + { + // update the stencil buffer width and height + gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height ); + } } var projectionFrame = this.frame || this.size; diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 401042c..78b8b52 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -33,7 +33,7 @@ utils.sayHello('webGL'); WebGLRenderer._TEMP__ = this; - + if (options) { for (var i in CONST.defaultRenderOptions) @@ -351,7 +351,7 @@ this.setRenderTarget(renderTarget); - + // reset the render session data.. this.drawCount = 0; @@ -383,6 +383,7 @@ { this.currentRenderTarget = renderTarget; this.currentRenderTarget.activate(); + this.stencilManager.setMaskStack( renderTarget.stencilMaskStack ); }; /** diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index b998aef..c419356 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -47,7 +47,7 @@ FilterManager.prototype.onContextChange = function () { this.texturePool.length = 0; - + var gl = this.renderer.gl; this.quad = new Quad(gl); }; @@ -80,12 +80,12 @@ // set the frame so the render target knows how much to render! texture.frame = bounds; - + this.renderer.setRenderTarget( texture ); // clear the texture.. texture.clear(); - + // TODO get rid of object creation! this.filterStack.push({ renderTarget:texture, @@ -107,12 +107,12 @@ var input = filterData.renderTarget; var output = previousFilterData.renderTarget; - + // use program var gl = this.renderer.gl; var filter = filterData.filter[0]; - + this.currentFrame = input.frame; this.quad.map(this.textureSize, input.frame); @@ -131,7 +131,7 @@ FilterManager.prototype.getRenderTarget = function () { var renderTarget = this.texturePool.pop() || new RenderTarget(this.renderer.gl, this.textureSize.width, this.textureSize.height); - renderTarget.frame = this.currentFrame; + renderTarget.frame = this.currentFrame; return renderTarget; }; @@ -154,7 +154,7 @@ // set the shader this.renderer.shaderManager.setShader(shader); - + shader.uniforms.projectionMatrix.value = this.renderer.currentRenderTarget.projectionMatrix.toArray(true); //TODO can this be optimised? @@ -183,7 +183,7 @@ var ratio = this.textureSize.height / this.textureSize.width; mappedMatrix.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height ); - + mappedMatrix.scale(1 , ratio); var translateScaleX = (this.textureSize.width / texture.width); @@ -213,13 +213,13 @@ // var ratio = this.textureSize.height / this.textureSize.width; // m.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height); - + // m.scale(1 , ratio); // var transform = wt.clone(); - + // var translateScaleX = (this.textureSize.width / 620); // var translateScaleY = (this.textureSize.height / 380); diff --git a/src/core/renderers/webgl/managers/MaskManager.js b/src/core/renderers/webgl/managers/MaskManager.js index 732438d..8abe133 100644 --- a/src/core/renderers/webgl/managers/MaskManager.js +++ b/src/core/renderers/webgl/managers/MaskManager.js @@ -55,7 +55,7 @@ MaskManager.prototype.pushSpriteMask = function (target, maskData) { var alphaMaskFilter = this.alphaMaskPool.pop(); - + if (!alphaMaskFilter) { alphaMaskFilter = [new AlphaMaskFilter(maskData)]; @@ -84,6 +84,7 @@ MaskManager.prototype.pushStencilMask = function (target, maskData) { + this.renderer.currentRenderTarget.attachStenilBuffer(); this.renderer.stencilManager.pushMask(maskData); }; diff --git a/src/core/renderers/webgl/managers/StencilManager.js b/src/core/renderers/webgl/managers/StencilManager.js index 741ca8b..c93e061 100644 --- a/src/core/renderers/webgl/managers/StencilManager.js +++ b/src/core/renderers/webgl/managers/StencilManager.js @@ -9,16 +9,29 @@ function WebGLMaskManager(renderer) { WebGLManager.call(this, renderer); - - this.stencilStack = []; - this.reverse = true; - this.count = 0; + this.stencilMaskStack = null; } WebGLMaskManager.prototype = Object.create(WebGLManager.prototype); WebGLMaskManager.prototype.constructor = WebGLMaskManager; module.exports = WebGLMaskManager; +WebGLMaskManager.prototype.setMaskStack = function ( stencilMaskStack ) +{ + this.stencilMaskStack = stencilMaskStack; + + var gl = this.renderer.gl; + + if(stencilMaskStack.stencilStack.length === 0) + { + gl.disable(gl.STENCIL_TEST); + } + else + { + gl.enable(gl.STENCIL_TEST); + } +}; + /** * Applies the Mask and adds it to the current filter stack. * @@ -27,21 +40,22 @@ */ WebGLMaskManager.prototype.pushStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; this.bindGraphics(graphics, webGLData, this.renderer); - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { gl.enable(gl.STENCIL_TEST); gl.clear(gl.STENCIL_BUFFER_BIT); - this.reverse = true; - this.count = 0; + sms.reverse = true; + sms.count = 0; } - this.stencilStack.push(webGLData); + sms.stencilStack.push(webGLData); - var level = this.count; + var level = sms.count; gl.colorMask(false, false, false, false); @@ -54,7 +68,7 @@ { gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -68,7 +82,7 @@ // draw a quad to increment.. gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -77,11 +91,11 @@ gl.stencilFunc(gl.EQUAL,level+1, 0xFF); } - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; } else { - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -94,7 +108,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -107,7 +121,7 @@ gl.colorMask(true, true, true, true); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - this.count++; + sms.count++; }; /** @@ -182,13 +196,14 @@ */ WebGLMaskManager.prototype.popStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; - this.stencilStack.pop(); + sms.stencilStack.pop(); - this.count--; + sms.count--; - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { // the stack is empty! gl.disable(gl.STENCIL_TEST); @@ -197,7 +212,7 @@ else { - var level = this.count; + var level = sms.count; this.bindGraphics(graphics, webGLData, this.renderer); @@ -205,9 +220,9 @@ if (webGLData.mode === 1) { - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -227,7 +242,7 @@ // draw the triangle strip! gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -240,7 +255,7 @@ else { // console.log("<<>>") - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -253,7 +268,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -278,7 +293,7 @@ { WebGLManager.prototype.destroy.call(this); - this.stencilStack = null; + this.stencilMaskStack.stencilStack = null; }; /** diff --git a/src/core/renderers/webgl/utils/FilterTexture.js b/src/core/renderers/webgl/utils/FilterTexture.js deleted file mode 100644 index 4433d44..0000000 --- a/src/core/renderers/webgl/utils/FilterTexture.js +++ /dev/null @@ -1,111 +0,0 @@ -var CONST = require('../../../const'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - * @param width {number} the horizontal range of the filter - * @param height {number} the vertical range of the filter - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - */ -function FilterTexture(gl, width, height, scaleMode) -{ - /** - * @member {WebGLContext} - */ - this.gl = gl; - - // next time to create a frame buffer and texture - - /** - * @member {Any} - */ - this.frameBuffer = gl.createFramebuffer(); - - /** - * @member {Any} - */ - this.texture = gl.createTexture(); - - /** - * @member {number} - */ - scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - 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); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - // required for masking a mask?? - this.renderBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); - - this.resize(width, height); -} - -FilterTexture.prototype.constructor = FilterTexture; -module.exports = FilterTexture; - -/** - * Clears the filter texture. - * - */ -FilterTexture.prototype.clear = function () -{ - var gl = this.gl; - - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); -}; - -/** - * Resizes the texture to the specified width and height - * - * @param width {number} the new width of the texture - * @param height {number} the new height of the texture - */ -FilterTexture.prototype.resize = function (width, height) -{ - if (this.width === width && this.height === height) - { - return; - } - - this.width = width; - this.height = height; - - var gl = this.gl; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - // update the stencil buffer width and height - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); -}; - -/** - * Destroys the filter texture. - * - */ -FilterTexture.prototype.destroy = function () -{ - var gl = this.gl; - gl.deleteFramebuffer( this.frameBuffer ); - gl.deleteTexture( this.texture ); - - this.frameBuffer = null; - this.texture = null; -}; diff --git a/src/core/renderers/webgl/utils/RenderTarget.js b/src/core/renderers/webgl/utils/RenderTarget.js index 5789327..e7ed9da 100644 --- a/src/core/renderers/webgl/utils/RenderTarget.js +++ b/src/core/renderers/webgl/utils/RenderTarget.js @@ -1,5 +1,7 @@ var math = require('../../../math'), - CONST = require('../../../const'); + CONST = require('../../../const'), + //StencilManager = require('../managers/StencilManager'), + StencilMaskStack = require('./StencilMaskStack'); /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -13,10 +15,10 @@ * @param height {Number} the vertical range of the filter * @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values */ -var RenderTarget = function(gl, width, height, scaleMode, root) +var RenderTarget = function(gl, width, height, scaleMode, root, createStencilBuffer) { - //TODO Resolution could go here ( eg low res blurs ) - + //TODO Resolution could go here ( eg low res blurs ) + /** * @property gl * @type WebGLContext @@ -45,6 +47,9 @@ this.frame = null; + this.stencilBuffer = null; + this.stencilMaskStack = new StencilMaskStack(); + /** * @property scaleMode * @type Number @@ -58,7 +63,6 @@ // this.flipY = true; this.frameBuffer = gl.createFramebuffer(); - /* A frame buffer needs a target to render to.. create a texture and bind it attach it to the framebuffer.. @@ -76,20 +80,17 @@ gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - - - /* - The stencil buffer is used for masking in pixi - lets create one and then add attach it to the framebuffer.. - */ - this.stencilBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencilBuffer); } + this.resize(width, height); + if(createStencilBuffer) + { + this.attachStenilBuffer(); + } + + }; RenderTarget.prototype.constructor = RenderTarget; @@ -108,13 +109,36 @@ gl.clear(gl.COLOR_BUFFER_BIT); }; +RenderTarget.prototype.attachStenilBuffer = function() +{ + + if( this.stencilBuffer ) + { + return; + } + + /* + The stencil buffer is used for masking in pixi + lets create one and then add attach it to the framebuffer.. + */ + if(!this.root) + { + var gl = this.gl; + + this.stencilBuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, this.width , this.height ); + } +}; + RenderTarget.prototype.activate = function() { //TOOD refactor usage of frame.. var gl = this.gl; gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer); - + var projectionFrame = this.frame || this.size; // TODO add a dirty flag to this of a setter for the frame? @@ -134,7 +158,7 @@ pm.a = 1 / projectionFrame.width*2; pm.d = 1 / projectionFrame.height*2; - pm.tx = -1 - projectionFrame.x * pm.a; + pm.tx = -1 - projectionFrame.x * pm.a; pm.ty = -1 - projectionFrame.y * pm.d; } else @@ -142,7 +166,7 @@ pm.a = 1 / projectionFrame.width*2; pm.d = -1 / projectionFrame.height*2; - pm.tx = -1 - projectionFrame.x * pm.a; + pm.tx = -1 - projectionFrame.x * pm.a; pm.ty = 1 - projectionFrame.y * pm.d; } }; @@ -174,10 +198,13 @@ gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - - // update the stencil buffer width and height - gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height ); + + if(this.stencilBuffer ) + { + // update the stencil buffer width and height + gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height ); + } } var projectionFrame = this.frame || this.size; diff --git a/src/core/renderers/webgl/utils/SpriteMaskFilter.js b/src/core/renderers/webgl/utils/SpriteMaskFilter.js index 62f7c7e..cceb88a 100644 --- a/src/core/renderers/webgl/utils/SpriteMaskFilter.js +++ b/src/core/renderers/webgl/utils/SpriteMaskFilter.js @@ -2,7 +2,7 @@ math = require('../../../math'); /** - * The AlphaMaskFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. + * The SpriteMaskFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. * You can use this filter to apply all manor of crazy warping effects * Currently the r property of the texture is used to offset the x and the g property of the texture is used to offset the y. * @@ -11,7 +11,7 @@ * @namespace PIXI * @param texture {Texture} The texture used for the displacement map * must be power of 2 texture at the moment */ -function AlphaMaskFilter(sprite) +function SpriteMaskFilter(sprite) { var maskMatrix = new math.Matrix(); @@ -66,11 +66,11 @@ this.maskMatrix = maskMatrix; } -AlphaMaskFilter.prototype = Object.create(AbstractFilter.prototype); -AlphaMaskFilter.prototype.constructor = AlphaMaskFilter; -module.exports = AlphaMaskFilter; +SpriteMaskFilter.prototype = Object.create(AbstractFilter.prototype); +SpriteMaskFilter.prototype.constructor = SpriteMaskFilter; +module.exports = SpriteMaskFilter; -AlphaMaskFilter.prototype.applyFilter = function (renderer, input, output) +SpriteMaskFilter.prototype.applyFilter = function (renderer, input, output) { var filterManager = renderer.filterManager; @@ -78,18 +78,18 @@ this.uniforms.otherMatrix.value = this.maskMatrix.toArray(true); - shader = this.getShader(renderer); + var shader = this.getShader(renderer); // draw the filter... filterManager.applyFilter(shader, input, output); }; -Object.defineProperties(AlphaMaskFilter.prototype, { +Object.defineProperties(SpriteMaskFilter.prototype, { /** * The texture used for the displacement map. Must be power of 2 sized texture. * * @member {Texture} - * @memberof AlphaMaskFilter# + * @memberof SpriteMaskFilter# */ map: { get: function () @@ -106,7 +106,7 @@ * The offset used to move the displacement map. * * @member {Point} - * @memberof AlphaMaskFilter# + * @memberof SpriteMaskFilter# */ offset: { get: function() diff --git a/src/core/renderers/webgl/WebGLRenderer.js b/src/core/renderers/webgl/WebGLRenderer.js index 401042c..78b8b52 100644 --- a/src/core/renderers/webgl/WebGLRenderer.js +++ b/src/core/renderers/webgl/WebGLRenderer.js @@ -33,7 +33,7 @@ utils.sayHello('webGL'); WebGLRenderer._TEMP__ = this; - + if (options) { for (var i in CONST.defaultRenderOptions) @@ -351,7 +351,7 @@ this.setRenderTarget(renderTarget); - + // reset the render session data.. this.drawCount = 0; @@ -383,6 +383,7 @@ { this.currentRenderTarget = renderTarget; this.currentRenderTarget.activate(); + this.stencilManager.setMaskStack( renderTarget.stencilMaskStack ); }; /** diff --git a/src/core/renderers/webgl/managers/FilterManager.js b/src/core/renderers/webgl/managers/FilterManager.js index b998aef..c419356 100644 --- a/src/core/renderers/webgl/managers/FilterManager.js +++ b/src/core/renderers/webgl/managers/FilterManager.js @@ -47,7 +47,7 @@ FilterManager.prototype.onContextChange = function () { this.texturePool.length = 0; - + var gl = this.renderer.gl; this.quad = new Quad(gl); }; @@ -80,12 +80,12 @@ // set the frame so the render target knows how much to render! texture.frame = bounds; - + this.renderer.setRenderTarget( texture ); // clear the texture.. texture.clear(); - + // TODO get rid of object creation! this.filterStack.push({ renderTarget:texture, @@ -107,12 +107,12 @@ var input = filterData.renderTarget; var output = previousFilterData.renderTarget; - + // use program var gl = this.renderer.gl; var filter = filterData.filter[0]; - + this.currentFrame = input.frame; this.quad.map(this.textureSize, input.frame); @@ -131,7 +131,7 @@ FilterManager.prototype.getRenderTarget = function () { var renderTarget = this.texturePool.pop() || new RenderTarget(this.renderer.gl, this.textureSize.width, this.textureSize.height); - renderTarget.frame = this.currentFrame; + renderTarget.frame = this.currentFrame; return renderTarget; }; @@ -154,7 +154,7 @@ // set the shader this.renderer.shaderManager.setShader(shader); - + shader.uniforms.projectionMatrix.value = this.renderer.currentRenderTarget.projectionMatrix.toArray(true); //TODO can this be optimised? @@ -183,7 +183,7 @@ var ratio = this.textureSize.height / this.textureSize.width; mappedMatrix.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height ); - + mappedMatrix.scale(1 , ratio); var translateScaleX = (this.textureSize.width / texture.width); @@ -213,13 +213,13 @@ // var ratio = this.textureSize.height / this.textureSize.width; // m.translate(filterArea.x / this.textureSize.width, filterArea.y / this.textureSize.height); - + // m.scale(1 , ratio); // var transform = wt.clone(); - + // var translateScaleX = (this.textureSize.width / 620); // var translateScaleY = (this.textureSize.height / 380); diff --git a/src/core/renderers/webgl/managers/MaskManager.js b/src/core/renderers/webgl/managers/MaskManager.js index 732438d..8abe133 100644 --- a/src/core/renderers/webgl/managers/MaskManager.js +++ b/src/core/renderers/webgl/managers/MaskManager.js @@ -55,7 +55,7 @@ MaskManager.prototype.pushSpriteMask = function (target, maskData) { var alphaMaskFilter = this.alphaMaskPool.pop(); - + if (!alphaMaskFilter) { alphaMaskFilter = [new AlphaMaskFilter(maskData)]; @@ -84,6 +84,7 @@ MaskManager.prototype.pushStencilMask = function (target, maskData) { + this.renderer.currentRenderTarget.attachStenilBuffer(); this.renderer.stencilManager.pushMask(maskData); }; diff --git a/src/core/renderers/webgl/managers/StencilManager.js b/src/core/renderers/webgl/managers/StencilManager.js index 741ca8b..c93e061 100644 --- a/src/core/renderers/webgl/managers/StencilManager.js +++ b/src/core/renderers/webgl/managers/StencilManager.js @@ -9,16 +9,29 @@ function WebGLMaskManager(renderer) { WebGLManager.call(this, renderer); - - this.stencilStack = []; - this.reverse = true; - this.count = 0; + this.stencilMaskStack = null; } WebGLMaskManager.prototype = Object.create(WebGLManager.prototype); WebGLMaskManager.prototype.constructor = WebGLMaskManager; module.exports = WebGLMaskManager; +WebGLMaskManager.prototype.setMaskStack = function ( stencilMaskStack ) +{ + this.stencilMaskStack = stencilMaskStack; + + var gl = this.renderer.gl; + + if(stencilMaskStack.stencilStack.length === 0) + { + gl.disable(gl.STENCIL_TEST); + } + else + { + gl.enable(gl.STENCIL_TEST); + } +}; + /** * Applies the Mask and adds it to the current filter stack. * @@ -27,21 +40,22 @@ */ WebGLMaskManager.prototype.pushStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; this.bindGraphics(graphics, webGLData, this.renderer); - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { gl.enable(gl.STENCIL_TEST); gl.clear(gl.STENCIL_BUFFER_BIT); - this.reverse = true; - this.count = 0; + sms.reverse = true; + sms.count = 0; } - this.stencilStack.push(webGLData); + sms.stencilStack.push(webGLData); - var level = this.count; + var level = sms.count; gl.colorMask(false, false, false, false); @@ -54,7 +68,7 @@ { gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -68,7 +82,7 @@ // draw a quad to increment.. gl.drawElements(gl.TRIANGLE_FAN, 4, gl.UNSIGNED_SHORT, ( webGLData.indices.length - 4 ) * 2 ); - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -77,11 +91,11 @@ gl.stencilFunc(gl.EQUAL,level+1, 0xFF); } - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; } else { - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - level, 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.DECR); @@ -94,7 +108,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level+1), 0xFF); } @@ -107,7 +121,7 @@ gl.colorMask(true, true, true, true); gl.stencilOp(gl.KEEP,gl.KEEP,gl.KEEP); - this.count++; + sms.count++; }; /** @@ -182,13 +196,14 @@ */ WebGLMaskManager.prototype.popStencil = function (graphics, webGLData) { - var gl = this.renderer.gl; + var gl = this.renderer.gl, + sms = this.stencilMaskStack; - this.stencilStack.pop(); + sms.stencilStack.pop(); - this.count--; + sms.count--; - if (this.stencilStack.length === 0) + if (sms.stencilStack.length === 0) { // the stack is empty! gl.disable(gl.STENCIL_TEST); @@ -197,7 +212,7 @@ else { - var level = this.count; + var level = sms.count; this.bindGraphics(graphics, webGLData, this.renderer); @@ -205,9 +220,9 @@ if (webGLData.mode === 1) { - this.reverse = !this.reverse; + sms.reverse = !sms.reverse; - if (this.reverse) + if (sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -227,7 +242,7 @@ // draw the triangle strip! gl.drawElements(gl.TRIANGLE_FAN, webGLData.indices.length - 4, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -240,7 +255,7 @@ else { // console.log("<<>>") - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL, 0xFF - (level+1), 0xFF); gl.stencilOp(gl.KEEP,gl.KEEP,gl.INCR); @@ -253,7 +268,7 @@ gl.drawElements(gl.TRIANGLE_STRIP, webGLData.indices.length, gl.UNSIGNED_SHORT, 0 ); - if (!this.reverse) + if (!sms.reverse) { gl.stencilFunc(gl.EQUAL,0xFF-(level), 0xFF); } @@ -278,7 +293,7 @@ { WebGLManager.prototype.destroy.call(this); - this.stencilStack = null; + this.stencilMaskStack.stencilStack = null; }; /** diff --git a/src/core/renderers/webgl/utils/FilterTexture.js b/src/core/renderers/webgl/utils/FilterTexture.js deleted file mode 100644 index 4433d44..0000000 --- a/src/core/renderers/webgl/utils/FilterTexture.js +++ /dev/null @@ -1,111 +0,0 @@ -var CONST = require('../../../const'); - -/** - * @class - * @namespace PIXI - * @param gl {WebGLContext} the current WebGL drawing context - * @param width {number} the horizontal range of the filter - * @param height {number} the vertical range of the filter - * @param scaleMode {number} See {{#crossLink "PIXI/scaleModes:property"}}scaleModes{{/crossLink}} for possible values - */ -function FilterTexture(gl, width, height, scaleMode) -{ - /** - * @member {WebGLContext} - */ - this.gl = gl; - - // next time to create a frame buffer and texture - - /** - * @member {Any} - */ - this.frameBuffer = gl.createFramebuffer(); - - /** - * @member {Any} - */ - this.texture = gl.createTexture(); - - /** - * @member {number} - */ - scaleMode = scaleMode || CONST.scaleModes.DEFAULT; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, scaleMode === CONST.scaleModes.LINEAR ? gl.LINEAR : gl.NEAREST); - 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); - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - - gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); - gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - // required for masking a mask?? - this.renderBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.renderBuffer); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); - - this.resize(width, height); -} - -FilterTexture.prototype.constructor = FilterTexture; -module.exports = FilterTexture; - -/** - * Clears the filter texture. - * - */ -FilterTexture.prototype.clear = function () -{ - var gl = this.gl; - - gl.clearColor(0,0,0, 0); - gl.clear(gl.COLOR_BUFFER_BIT); -}; - -/** - * Resizes the texture to the specified width and height - * - * @param width {number} the new width of the texture - * @param height {number} the new height of the texture - */ -FilterTexture.prototype.resize = function (width, height) -{ - if (this.width === width && this.height === height) - { - return; - } - - this.width = width; - this.height = height; - - var gl = this.gl; - - gl.bindTexture(gl.TEXTURE_2D, this.texture); - gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - // update the stencil buffer width and height - gl.bindRenderbuffer(gl.RENDERBUFFER, this.renderBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height); - - // reset render buffer - gl.bindRenderbuffer(gl.RENDERBUFFER, null); -}; - -/** - * Destroys the filter texture. - * - */ -FilterTexture.prototype.destroy = function () -{ - var gl = this.gl; - gl.deleteFramebuffer( this.frameBuffer ); - gl.deleteTexture( this.texture ); - - this.frameBuffer = null; - this.texture = null; -}; diff --git a/src/core/renderers/webgl/utils/RenderTarget.js b/src/core/renderers/webgl/utils/RenderTarget.js index 5789327..e7ed9da 100644 --- a/src/core/renderers/webgl/utils/RenderTarget.js +++ b/src/core/renderers/webgl/utils/RenderTarget.js @@ -1,5 +1,7 @@ var math = require('../../../math'), - CONST = require('../../../const'); + CONST = require('../../../const'), + //StencilManager = require('../managers/StencilManager'), + StencilMaskStack = require('./StencilMaskStack'); /** * @author Mat Groves http://matgroves.com/ @Doormat23 @@ -13,10 +15,10 @@ * @param height {Number} the vertical range of the filter * @param scaleMode {Number} See {{#crossLink "PIXI/scaleModes:property"}}PIXI.scaleModes{{/crossLink}} for possible values */ -var RenderTarget = function(gl, width, height, scaleMode, root) +var RenderTarget = function(gl, width, height, scaleMode, root, createStencilBuffer) { - //TODO Resolution could go here ( eg low res blurs ) - + //TODO Resolution could go here ( eg low res blurs ) + /** * @property gl * @type WebGLContext @@ -45,6 +47,9 @@ this.frame = null; + this.stencilBuffer = null; + this.stencilMaskStack = new StencilMaskStack(); + /** * @property scaleMode * @type Number @@ -58,7 +63,6 @@ // this.flipY = true; this.frameBuffer = gl.createFramebuffer(); - /* A frame buffer needs a target to render to.. create a texture and bind it attach it to the framebuffer.. @@ -76,20 +80,17 @@ gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer ); gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, this.texture, 0); - - - - /* - The stencil buffer is used for masking in pixi - lets create one and then add attach it to the framebuffer.. - */ - this.stencilBuffer = gl.createRenderbuffer(); - gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); - gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencilBuffer); } + this.resize(width, height); + if(createStencilBuffer) + { + this.attachStenilBuffer(); + } + + }; RenderTarget.prototype.constructor = RenderTarget; @@ -108,13 +109,36 @@ gl.clear(gl.COLOR_BUFFER_BIT); }; +RenderTarget.prototype.attachStenilBuffer = function() +{ + + if( this.stencilBuffer ) + { + return; + } + + /* + The stencil buffer is used for masking in pixi + lets create one and then add attach it to the framebuffer.. + */ + if(!this.root) + { + var gl = this.gl; + + this.stencilBuffer = gl.createRenderbuffer(); + gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); + gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, this.stencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, this.width , this.height ); + } +}; + RenderTarget.prototype.activate = function() { //TOOD refactor usage of frame.. var gl = this.gl; gl.bindFramebuffer(gl.FRAMEBUFFER, this.frameBuffer); - + var projectionFrame = this.frame || this.size; // TODO add a dirty flag to this of a setter for the frame? @@ -134,7 +158,7 @@ pm.a = 1 / projectionFrame.width*2; pm.d = 1 / projectionFrame.height*2; - pm.tx = -1 - projectionFrame.x * pm.a; + pm.tx = -1 - projectionFrame.x * pm.a; pm.ty = -1 - projectionFrame.y * pm.d; } else @@ -142,7 +166,7 @@ pm.a = 1 / projectionFrame.width*2; pm.d = -1 / projectionFrame.height*2; - pm.tx = -1 - projectionFrame.x * pm.a; + pm.tx = -1 - projectionFrame.x * pm.a; pm.ty = 1 - projectionFrame.y * pm.d; } }; @@ -174,10 +198,13 @@ gl.bindTexture(gl.TEXTURE_2D, this.texture); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width , height , 0, gl.RGBA, gl.UNSIGNED_BYTE, null); - - // update the stencil buffer width and height - gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); - gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height ); + + if(this.stencilBuffer ) + { + // update the stencil buffer width and height + gl.bindRenderbuffer(gl.RENDERBUFFER, this.stencilBuffer); + gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, width , height ); + } } var projectionFrame = this.frame || this.size; diff --git a/src/core/renderers/webgl/utils/SpriteMaskFilter.js b/src/core/renderers/webgl/utils/SpriteMaskFilter.js index 62f7c7e..cceb88a 100644 --- a/src/core/renderers/webgl/utils/SpriteMaskFilter.js +++ b/src/core/renderers/webgl/utils/SpriteMaskFilter.js @@ -2,7 +2,7 @@ math = require('../../../math'); /** - * The AlphaMaskFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. + * The SpriteMaskFilter class uses the pixel values from the specified texture (called the displacement map) to perform a displacement of an object. * You can use this filter to apply all manor of crazy warping effects * Currently the r property of the texture is used to offset the x and the g property of the texture is used to offset the y. * @@ -11,7 +11,7 @@ * @namespace PIXI * @param texture {Texture} The texture used for the displacement map * must be power of 2 texture at the moment */ -function AlphaMaskFilter(sprite) +function SpriteMaskFilter(sprite) { var maskMatrix = new math.Matrix(); @@ -66,11 +66,11 @@ this.maskMatrix = maskMatrix; } -AlphaMaskFilter.prototype = Object.create(AbstractFilter.prototype); -AlphaMaskFilter.prototype.constructor = AlphaMaskFilter; -module.exports = AlphaMaskFilter; +SpriteMaskFilter.prototype = Object.create(AbstractFilter.prototype); +SpriteMaskFilter.prototype.constructor = SpriteMaskFilter; +module.exports = SpriteMaskFilter; -AlphaMaskFilter.prototype.applyFilter = function (renderer, input, output) +SpriteMaskFilter.prototype.applyFilter = function (renderer, input, output) { var filterManager = renderer.filterManager; @@ -78,18 +78,18 @@ this.uniforms.otherMatrix.value = this.maskMatrix.toArray(true); - shader = this.getShader(renderer); + var shader = this.getShader(renderer); // draw the filter... filterManager.applyFilter(shader, input, output); }; -Object.defineProperties(AlphaMaskFilter.prototype, { +Object.defineProperties(SpriteMaskFilter.prototype, { /** * The texture used for the displacement map. Must be power of 2 sized texture. * * @member {Texture} - * @memberof AlphaMaskFilter# + * @memberof SpriteMaskFilter# */ map: { get: function () @@ -106,7 +106,7 @@ * The offset used to move the displacement map. * * @member {Point} - * @memberof AlphaMaskFilter# + * @memberof SpriteMaskFilter# */ offset: { get: function() diff --git a/src/core/renderers/webgl/utils/StencilMaskStack.js b/src/core/renderers/webgl/utils/StencilMaskStack.js new file mode 100644 index 0000000..7cf5dff --- /dev/null +++ b/src/core/renderers/webgl/utils/StencilMaskStack.js @@ -0,0 +1,14 @@ +/** + * @class + * @namespace PIXI + * @param renderer {WebGLRenderer} The renderer this manager works for. + */ +function StencilMaskStack() +{ + this.stencilStack = []; + this.reverse = true; + this.count = 0; +} + +StencilMaskStack.prototype.constructor = StencilMaskStack; +module.exports = StencilMaskStack;