diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/filters/noise/NoiseFilter.js b/src/filters/noise/NoiseFilter.js new file mode 100644 index 0000000..f333659 --- /dev/null +++ b/src/filters/noise/NoiseFilter.js @@ -0,0 +1,50 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js + */ + +/** + * A Noise effect filter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function NoiseFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./noise.frag') + ); + + this.noise = 0.5; +} + +NoiseFilter.prototype = Object.create(core.Filter.prototype); +NoiseFilter.prototype.constructor = NoiseFilter; +module.exports = NoiseFilter; + +Object.defineProperties(NoiseFilter.prototype, { + /** + * The amount of noise to apply. + * + * @member {number} + * @memberof PIXI.filters.NoiseFilter# + * @default 0.5 + */ + noise: { + get: function () + { + return this.uniforms.noise; + }, + set: function (value) + { + this.uniforms.noise = value; + } + } +}); diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/filters/noise/NoiseFilter.js b/src/filters/noise/NoiseFilter.js new file mode 100644 index 0000000..f333659 --- /dev/null +++ b/src/filters/noise/NoiseFilter.js @@ -0,0 +1,50 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js + */ + +/** + * A Noise effect filter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function NoiseFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./noise.frag') + ); + + this.noise = 0.5; +} + +NoiseFilter.prototype = Object.create(core.Filter.prototype); +NoiseFilter.prototype.constructor = NoiseFilter; +module.exports = NoiseFilter; + +Object.defineProperties(NoiseFilter.prototype, { + /** + * The amount of noise to apply. + * + * @member {number} + * @memberof PIXI.filters.NoiseFilter# + * @default 0.5 + */ + noise: { + get: function () + { + return this.uniforms.noise; + }, + set: function (value) + { + this.uniforms.noise = value; + } + } +}); diff --git a/src/filters/noise/noise.frag b/src/filters/noise/noise.frag new file mode 100644 index 0000000..3954a0a --- /dev/null +++ b/src/filters/noise/noise.frag @@ -0,0 +1,25 @@ +precision highp float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform float noise; +uniform sampler2D uSampler; + +float rand(vec2 co) +{ + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + + float diff = (rand(gl_FragCoord.xy) - 0.5) * noise; + + color.r += diff; + color.g += diff; + color.b += diff; + + gl_FragColor = color; +} diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/filters/noise/NoiseFilter.js b/src/filters/noise/NoiseFilter.js new file mode 100644 index 0000000..f333659 --- /dev/null +++ b/src/filters/noise/NoiseFilter.js @@ -0,0 +1,50 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js + */ + +/** + * A Noise effect filter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function NoiseFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./noise.frag') + ); + + this.noise = 0.5; +} + +NoiseFilter.prototype = Object.create(core.Filter.prototype); +NoiseFilter.prototype.constructor = NoiseFilter; +module.exports = NoiseFilter; + +Object.defineProperties(NoiseFilter.prototype, { + /** + * The amount of noise to apply. + * + * @member {number} + * @memberof PIXI.filters.NoiseFilter# + * @default 0.5 + */ + noise: { + get: function () + { + return this.uniforms.noise; + }, + set: function (value) + { + this.uniforms.noise = value; + } + } +}); diff --git a/src/filters/noise/noise.frag b/src/filters/noise/noise.frag new file mode 100644 index 0000000..3954a0a --- /dev/null +++ b/src/filters/noise/noise.frag @@ -0,0 +1,25 @@ +precision highp float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform float noise; +uniform sampler2D uSampler; + +float rand(vec2 co) +{ + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + + float diff = (rand(gl_FragCoord.xy) - 0.5) * noise; + + color.r += diff; + color.g += diff; + color.b += diff; + + gl_FragColor = color; +} diff --git a/src/filters/shockwave/ShockwaveFilter.js b/src/filters/shockwave/ShockwaveFilter.js new file mode 100644 index 0000000..709bb86 --- /dev/null +++ b/src/filters/shockwave/ShockwaveFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ColorMatrixFilter class lets you apply a 4x4 matrix transformation on the RGBA + * color and alpha values of every pixel on your displayObject to produce a result + * with a new set of RGBA color and alpha values. It's pretty powerful! + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function ShockwaveFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./shockwave.frag'), + // custom uniforms + { + center: { type: 'v2', value: { x: 0.5, y: 0.5 } }, + params: { type: 'v3', value: { x: 10, y: 0.8, z: 0.1 } }, + time: { type: '1f', value: 0 } + } + ); + + this.center = [0.5, 0.5]; + this.params = [10, 0.8, 0.1]; + this.time = 0; +} + +ShockwaveFilter.prototype = Object.create(core.Filter.prototype); +ShockwaveFilter.prototype.constructor = ShockwaveFilter; +module.exports = ShockwaveFilter; + +Object.defineProperties(ShockwaveFilter.prototype, { + /** + * Sets the center of the shockwave in normalized screen coords. That is + * (0,0) is the top-left and (1,1) is the bottom right. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + center: { + get: function () + { + return this.uniforms.center; + }, + set: function (value) + { + this.uniforms.center = value; + } + }, + /** + * Sets the params of the shockwave. These modify the look and behavior of + * the shockwave as it ripples out. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + params: { + get: function () + { + return this.uniforms.params; + }, + set: function (value) + { + this.uniforms.params = value; + } + }, + /** + * Sets the elapsed time of the shockwave. This controls the speed at which + * the shockwave ripples out. + * + * @member {number} + * @memberof PIXI.filters.ShockwaveFilter# + */ + time: { + get: function () + { + return this.uniforms.time; + }, + set: function (value) + { + this.uniforms.time = value; + } + } +}); diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/filters/noise/NoiseFilter.js b/src/filters/noise/NoiseFilter.js new file mode 100644 index 0000000..f333659 --- /dev/null +++ b/src/filters/noise/NoiseFilter.js @@ -0,0 +1,50 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js + */ + +/** + * A Noise effect filter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function NoiseFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./noise.frag') + ); + + this.noise = 0.5; +} + +NoiseFilter.prototype = Object.create(core.Filter.prototype); +NoiseFilter.prototype.constructor = NoiseFilter; +module.exports = NoiseFilter; + +Object.defineProperties(NoiseFilter.prototype, { + /** + * The amount of noise to apply. + * + * @member {number} + * @memberof PIXI.filters.NoiseFilter# + * @default 0.5 + */ + noise: { + get: function () + { + return this.uniforms.noise; + }, + set: function (value) + { + this.uniforms.noise = value; + } + } +}); diff --git a/src/filters/noise/noise.frag b/src/filters/noise/noise.frag new file mode 100644 index 0000000..3954a0a --- /dev/null +++ b/src/filters/noise/noise.frag @@ -0,0 +1,25 @@ +precision highp float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform float noise; +uniform sampler2D uSampler; + +float rand(vec2 co) +{ + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + + float diff = (rand(gl_FragCoord.xy) - 0.5) * noise; + + color.r += diff; + color.g += diff; + color.b += diff; + + gl_FragColor = color; +} diff --git a/src/filters/shockwave/ShockwaveFilter.js b/src/filters/shockwave/ShockwaveFilter.js new file mode 100644 index 0000000..709bb86 --- /dev/null +++ b/src/filters/shockwave/ShockwaveFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ColorMatrixFilter class lets you apply a 4x4 matrix transformation on the RGBA + * color and alpha values of every pixel on your displayObject to produce a result + * with a new set of RGBA color and alpha values. It's pretty powerful! + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function ShockwaveFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./shockwave.frag'), + // custom uniforms + { + center: { type: 'v2', value: { x: 0.5, y: 0.5 } }, + params: { type: 'v3', value: { x: 10, y: 0.8, z: 0.1 } }, + time: { type: '1f', value: 0 } + } + ); + + this.center = [0.5, 0.5]; + this.params = [10, 0.8, 0.1]; + this.time = 0; +} + +ShockwaveFilter.prototype = Object.create(core.Filter.prototype); +ShockwaveFilter.prototype.constructor = ShockwaveFilter; +module.exports = ShockwaveFilter; + +Object.defineProperties(ShockwaveFilter.prototype, { + /** + * Sets the center of the shockwave in normalized screen coords. That is + * (0,0) is the top-left and (1,1) is the bottom right. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + center: { + get: function () + { + return this.uniforms.center; + }, + set: function (value) + { + this.uniforms.center = value; + } + }, + /** + * Sets the params of the shockwave. These modify the look and behavior of + * the shockwave as it ripples out. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + params: { + get: function () + { + return this.uniforms.params; + }, + set: function (value) + { + this.uniforms.params = value; + } + }, + /** + * Sets the elapsed time of the shockwave. This controls the speed at which + * the shockwave ripples out. + * + * @member {number} + * @memberof PIXI.filters.ShockwaveFilter# + */ + time: { + get: function () + { + return this.uniforms.time; + }, + set: function (value) + { + this.uniforms.time = value; + } + } +}); diff --git a/src/filters/shockwave/shockwave.frag b/src/filters/shockwave/shockwave.frag new file mode 100644 index 0000000..db2642e --- /dev/null +++ b/src/filters/shockwave/shockwave.frag @@ -0,0 +1,27 @@ +varying vec2 vTextureCoord; + +uniform sampler2D uSampler; + +uniform vec2 center; +uniform vec3 params; // 10.0, 0.8, 0.1 +uniform float time; + +void main() +{ + vec2 uv = vTextureCoord; + vec2 texCoord = uv; + + float dist = distance(uv, center); + + if ( (dist <= (time + params.z)) && (dist >= (time - params.z)) ) + { + float diff = (dist - time); + float powDiff = 1.0 - pow(abs(diff*params.x), params.y); + + float diffTime = diff * powDiff; + vec2 diffUV = normalize(uv - center); + texCoord = uv + (diffUV * diffTime); + } + + gl_FragColor = texture2D(uSampler, texCoord); +} diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/filters/noise/NoiseFilter.js b/src/filters/noise/NoiseFilter.js new file mode 100644 index 0000000..f333659 --- /dev/null +++ b/src/filters/noise/NoiseFilter.js @@ -0,0 +1,50 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js + */ + +/** + * A Noise effect filter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function NoiseFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./noise.frag') + ); + + this.noise = 0.5; +} + +NoiseFilter.prototype = Object.create(core.Filter.prototype); +NoiseFilter.prototype.constructor = NoiseFilter; +module.exports = NoiseFilter; + +Object.defineProperties(NoiseFilter.prototype, { + /** + * The amount of noise to apply. + * + * @member {number} + * @memberof PIXI.filters.NoiseFilter# + * @default 0.5 + */ + noise: { + get: function () + { + return this.uniforms.noise; + }, + set: function (value) + { + this.uniforms.noise = value; + } + } +}); diff --git a/src/filters/noise/noise.frag b/src/filters/noise/noise.frag new file mode 100644 index 0000000..3954a0a --- /dev/null +++ b/src/filters/noise/noise.frag @@ -0,0 +1,25 @@ +precision highp float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform float noise; +uniform sampler2D uSampler; + +float rand(vec2 co) +{ + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + + float diff = (rand(gl_FragCoord.xy) - 0.5) * noise; + + color.r += diff; + color.g += diff; + color.b += diff; + + gl_FragColor = color; +} diff --git a/src/filters/shockwave/ShockwaveFilter.js b/src/filters/shockwave/ShockwaveFilter.js new file mode 100644 index 0000000..709bb86 --- /dev/null +++ b/src/filters/shockwave/ShockwaveFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ColorMatrixFilter class lets you apply a 4x4 matrix transformation on the RGBA + * color and alpha values of every pixel on your displayObject to produce a result + * with a new set of RGBA color and alpha values. It's pretty powerful! + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function ShockwaveFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./shockwave.frag'), + // custom uniforms + { + center: { type: 'v2', value: { x: 0.5, y: 0.5 } }, + params: { type: 'v3', value: { x: 10, y: 0.8, z: 0.1 } }, + time: { type: '1f', value: 0 } + } + ); + + this.center = [0.5, 0.5]; + this.params = [10, 0.8, 0.1]; + this.time = 0; +} + +ShockwaveFilter.prototype = Object.create(core.Filter.prototype); +ShockwaveFilter.prototype.constructor = ShockwaveFilter; +module.exports = ShockwaveFilter; + +Object.defineProperties(ShockwaveFilter.prototype, { + /** + * Sets the center of the shockwave in normalized screen coords. That is + * (0,0) is the top-left and (1,1) is the bottom right. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + center: { + get: function () + { + return this.uniforms.center; + }, + set: function (value) + { + this.uniforms.center = value; + } + }, + /** + * Sets the params of the shockwave. These modify the look and behavior of + * the shockwave as it ripples out. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + params: { + get: function () + { + return this.uniforms.params; + }, + set: function (value) + { + this.uniforms.params = value; + } + }, + /** + * Sets the elapsed time of the shockwave. This controls the speed at which + * the shockwave ripples out. + * + * @member {number} + * @memberof PIXI.filters.ShockwaveFilter# + */ + time: { + get: function () + { + return this.uniforms.time; + }, + set: function (value) + { + this.uniforms.time = value; + } + } +}); diff --git a/src/filters/shockwave/shockwave.frag b/src/filters/shockwave/shockwave.frag new file mode 100644 index 0000000..db2642e --- /dev/null +++ b/src/filters/shockwave/shockwave.frag @@ -0,0 +1,27 @@ +varying vec2 vTextureCoord; + +uniform sampler2D uSampler; + +uniform vec2 center; +uniform vec3 params; // 10.0, 0.8, 0.1 +uniform float time; + +void main() +{ + vec2 uv = vTextureCoord; + vec2 texCoord = uv; + + float dist = distance(uv, center); + + if ( (dist <= (time + params.z)) && (dist >= (time - params.z)) ) + { + float diff = (dist - time); + float powDiff = 1.0 - pow(abs(diff*params.x), params.y); + + float diffTime = diff * powDiff; + vec2 diffUV = normalize(uv - center); + texCoord = uv + (diffUV * diffTime); + } + + gl_FragColor = texture2D(uSampler, texCoord); +} diff --git a/src/filters/tiltshift/TiltShiftAxisFilter.js b/src/filters/tiltshift/TiltShiftAxisFilter.js new file mode 100644 index 0000000..17a2dd5 --- /dev/null +++ b/src/filters/tiltshift/TiltShiftAxisFilter.js @@ -0,0 +1,121 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftAxisFilter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function TiltShiftAxisFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./tilt-shift.frag') + + ); + + this.uniforms.blur = 100; + this.uniforms.gradientBlur = 600; + this.uniforms.start = new PIXI.Point(0, window.innerHeight / 2); + this.uniforms.end = new PIXI.Point(600, window.innerHeight / 2); + this.uniforms.delta = new PIXI.Point(30, 30); + this.uniforms.texSize = new PIXI.Point(window.innerWidth, window.innerHeight); + + this.updateDelta(); +} + +TiltShiftAxisFilter.prototype = Object.create(core.Filter.prototype); +TiltShiftAxisFilter.prototype.constructor = TiltShiftAxisFilter; +module.exports = TiltShiftAxisFilter; + +/** + * Updates the filter delta values. + * This is overridden in the X and Y filters, does nothing for this class. + * + */ +TiltShiftAxisFilter.prototype.updateDelta = function () +{ + this.uniforms.delta.x = 0; + this.uniforms.delta.y = 0; +}; + +Object.defineProperties(TiltShiftAxisFilter.prototype, { + /** + * The strength of the blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + blur: { + get: function () + { + return this.uniforms.blur; + }, + set: function (value) + { + this.uniforms.blur = value; + } + }, + + /** + * The strength of the gradient blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + gradientBlur: { + get: function () + { + return this.uniforms.gradientBlur; + }, + set: function (value) + { + this.uniforms.gradientBlur = value; + } + }, + + /** + * The X value to start the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + start: { + get: function () + { + return this.uniforms.start; + }, + set: function (value) + { + this.uniforms.start = value; + this.updateDelta(); + } + }, + + /** + * The X value to end the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + end: { + get: function () + { + return this.uniforms.end; + }, + set: function (value) + { + this.uniforms.end = value; + this.updateDelta(); + } + } +}); diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/filters/noise/NoiseFilter.js b/src/filters/noise/NoiseFilter.js new file mode 100644 index 0000000..f333659 --- /dev/null +++ b/src/filters/noise/NoiseFilter.js @@ -0,0 +1,50 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js + */ + +/** + * A Noise effect filter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function NoiseFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./noise.frag') + ); + + this.noise = 0.5; +} + +NoiseFilter.prototype = Object.create(core.Filter.prototype); +NoiseFilter.prototype.constructor = NoiseFilter; +module.exports = NoiseFilter; + +Object.defineProperties(NoiseFilter.prototype, { + /** + * The amount of noise to apply. + * + * @member {number} + * @memberof PIXI.filters.NoiseFilter# + * @default 0.5 + */ + noise: { + get: function () + { + return this.uniforms.noise; + }, + set: function (value) + { + this.uniforms.noise = value; + } + } +}); diff --git a/src/filters/noise/noise.frag b/src/filters/noise/noise.frag new file mode 100644 index 0000000..3954a0a --- /dev/null +++ b/src/filters/noise/noise.frag @@ -0,0 +1,25 @@ +precision highp float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform float noise; +uniform sampler2D uSampler; + +float rand(vec2 co) +{ + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + + float diff = (rand(gl_FragCoord.xy) - 0.5) * noise; + + color.r += diff; + color.g += diff; + color.b += diff; + + gl_FragColor = color; +} diff --git a/src/filters/shockwave/ShockwaveFilter.js b/src/filters/shockwave/ShockwaveFilter.js new file mode 100644 index 0000000..709bb86 --- /dev/null +++ b/src/filters/shockwave/ShockwaveFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ColorMatrixFilter class lets you apply a 4x4 matrix transformation on the RGBA + * color and alpha values of every pixel on your displayObject to produce a result + * with a new set of RGBA color and alpha values. It's pretty powerful! + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function ShockwaveFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./shockwave.frag'), + // custom uniforms + { + center: { type: 'v2', value: { x: 0.5, y: 0.5 } }, + params: { type: 'v3', value: { x: 10, y: 0.8, z: 0.1 } }, + time: { type: '1f', value: 0 } + } + ); + + this.center = [0.5, 0.5]; + this.params = [10, 0.8, 0.1]; + this.time = 0; +} + +ShockwaveFilter.prototype = Object.create(core.Filter.prototype); +ShockwaveFilter.prototype.constructor = ShockwaveFilter; +module.exports = ShockwaveFilter; + +Object.defineProperties(ShockwaveFilter.prototype, { + /** + * Sets the center of the shockwave in normalized screen coords. That is + * (0,0) is the top-left and (1,1) is the bottom right. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + center: { + get: function () + { + return this.uniforms.center; + }, + set: function (value) + { + this.uniforms.center = value; + } + }, + /** + * Sets the params of the shockwave. These modify the look and behavior of + * the shockwave as it ripples out. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + params: { + get: function () + { + return this.uniforms.params; + }, + set: function (value) + { + this.uniforms.params = value; + } + }, + /** + * Sets the elapsed time of the shockwave. This controls the speed at which + * the shockwave ripples out. + * + * @member {number} + * @memberof PIXI.filters.ShockwaveFilter# + */ + time: { + get: function () + { + return this.uniforms.time; + }, + set: function (value) + { + this.uniforms.time = value; + } + } +}); diff --git a/src/filters/shockwave/shockwave.frag b/src/filters/shockwave/shockwave.frag new file mode 100644 index 0000000..db2642e --- /dev/null +++ b/src/filters/shockwave/shockwave.frag @@ -0,0 +1,27 @@ +varying vec2 vTextureCoord; + +uniform sampler2D uSampler; + +uniform vec2 center; +uniform vec3 params; // 10.0, 0.8, 0.1 +uniform float time; + +void main() +{ + vec2 uv = vTextureCoord; + vec2 texCoord = uv; + + float dist = distance(uv, center); + + if ( (dist <= (time + params.z)) && (dist >= (time - params.z)) ) + { + float diff = (dist - time); + float powDiff = 1.0 - pow(abs(diff*params.x), params.y); + + float diffTime = diff * powDiff; + vec2 diffUV = normalize(uv - center); + texCoord = uv + (diffUV * diffTime); + } + + gl_FragColor = texture2D(uSampler, texCoord); +} diff --git a/src/filters/tiltshift/TiltShiftAxisFilter.js b/src/filters/tiltshift/TiltShiftAxisFilter.js new file mode 100644 index 0000000..17a2dd5 --- /dev/null +++ b/src/filters/tiltshift/TiltShiftAxisFilter.js @@ -0,0 +1,121 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftAxisFilter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function TiltShiftAxisFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./tilt-shift.frag') + + ); + + this.uniforms.blur = 100; + this.uniforms.gradientBlur = 600; + this.uniforms.start = new PIXI.Point(0, window.innerHeight / 2); + this.uniforms.end = new PIXI.Point(600, window.innerHeight / 2); + this.uniforms.delta = new PIXI.Point(30, 30); + this.uniforms.texSize = new PIXI.Point(window.innerWidth, window.innerHeight); + + this.updateDelta(); +} + +TiltShiftAxisFilter.prototype = Object.create(core.Filter.prototype); +TiltShiftAxisFilter.prototype.constructor = TiltShiftAxisFilter; +module.exports = TiltShiftAxisFilter; + +/** + * Updates the filter delta values. + * This is overridden in the X and Y filters, does nothing for this class. + * + */ +TiltShiftAxisFilter.prototype.updateDelta = function () +{ + this.uniforms.delta.x = 0; + this.uniforms.delta.y = 0; +}; + +Object.defineProperties(TiltShiftAxisFilter.prototype, { + /** + * The strength of the blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + blur: { + get: function () + { + return this.uniforms.blur; + }, + set: function (value) + { + this.uniforms.blur = value; + } + }, + + /** + * The strength of the gradient blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + gradientBlur: { + get: function () + { + return this.uniforms.gradientBlur; + }, + set: function (value) + { + this.uniforms.gradientBlur = value; + } + }, + + /** + * The X value to start the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + start: { + get: function () + { + return this.uniforms.start; + }, + set: function (value) + { + this.uniforms.start = value; + this.updateDelta(); + } + }, + + /** + * The X value to end the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + end: { + get: function () + { + return this.uniforms.end; + }, + set: function (value) + { + this.uniforms.end = value; + this.updateDelta(); + } + } +}); diff --git a/src/filters/tiltshift/TiltShiftFilter.js b/src/filters/tiltshift/TiltShiftFilter.js new file mode 100644 index 0000000..671ac7a --- /dev/null +++ b/src/filters/tiltshift/TiltShiftFilter.js @@ -0,0 +1,108 @@ +var core = require('../../core'), + TiltShiftXFilter = require('./TiltShiftXFilter'), + TiltShiftYFilter = require('./TiltShiftYFilter'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShift Filter. Manages the pass of both a TiltShiftXFilter and TiltShiftYFilter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function TiltShiftFilter() +{ + core.Filter.call(this); + + this.tiltShiftXFilter = new TiltShiftXFilter(); + this.tiltShiftYFilter = new TiltShiftYFilter(); +} + +TiltShiftFilter.prototype = Object.create(core.Filter.prototype); +TiltShiftFilter.prototype.constructor = TiltShiftFilter; +module.exports = TiltShiftFilter; + +TiltShiftFilter.prototype.apply = function (filterManager, input, output) +{ + var renderTarget = filterManager.getRenderTarget(true); + + this.tiltShiftXFilter.apply(filterManager, input, renderTarget); + + this.tiltShiftYFilter.apply(filterManager, renderTarget, output); + + filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(TiltShiftFilter.prototype, { + /** + * The strength of the blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + blur: { + get: function () + { + return this.tiltShiftXFilter.blur; + }, + set: function (value) + { + this.tiltShiftXFilter.blur = this.tiltShiftYFilter.blur = value; + } + }, + + /** + * The strength of the gradient blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + gradientBlur: { + get: function () + { + return this.tiltShiftXFilter.gradientBlur; + }, + set: function (value) + { + this.tiltShiftXFilter.gradientBlur = this.tiltShiftYFilter.gradientBlur = value; + } + }, + + /** + * The Y value to start the effect at. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + start: { + get: function () + { + return this.tiltShiftXFilter.start; + }, + set: function (value) + { + this.tiltShiftXFilter.start = this.tiltShiftYFilter.start = value; + } + }, + + /** + * The Y value to end the effect at. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + end: { + get: function () + { + return this.tiltShiftXFilter.end; + }, + set: function (value) + { + this.tiltShiftXFilter.end = this.tiltShiftYFilter.end = value; + } + } +}); diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/filters/noise/NoiseFilter.js b/src/filters/noise/NoiseFilter.js new file mode 100644 index 0000000..f333659 --- /dev/null +++ b/src/filters/noise/NoiseFilter.js @@ -0,0 +1,50 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js + */ + +/** + * A Noise effect filter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function NoiseFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./noise.frag') + ); + + this.noise = 0.5; +} + +NoiseFilter.prototype = Object.create(core.Filter.prototype); +NoiseFilter.prototype.constructor = NoiseFilter; +module.exports = NoiseFilter; + +Object.defineProperties(NoiseFilter.prototype, { + /** + * The amount of noise to apply. + * + * @member {number} + * @memberof PIXI.filters.NoiseFilter# + * @default 0.5 + */ + noise: { + get: function () + { + return this.uniforms.noise; + }, + set: function (value) + { + this.uniforms.noise = value; + } + } +}); diff --git a/src/filters/noise/noise.frag b/src/filters/noise/noise.frag new file mode 100644 index 0000000..3954a0a --- /dev/null +++ b/src/filters/noise/noise.frag @@ -0,0 +1,25 @@ +precision highp float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform float noise; +uniform sampler2D uSampler; + +float rand(vec2 co) +{ + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + + float diff = (rand(gl_FragCoord.xy) - 0.5) * noise; + + color.r += diff; + color.g += diff; + color.b += diff; + + gl_FragColor = color; +} diff --git a/src/filters/shockwave/ShockwaveFilter.js b/src/filters/shockwave/ShockwaveFilter.js new file mode 100644 index 0000000..709bb86 --- /dev/null +++ b/src/filters/shockwave/ShockwaveFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ColorMatrixFilter class lets you apply a 4x4 matrix transformation on the RGBA + * color and alpha values of every pixel on your displayObject to produce a result + * with a new set of RGBA color and alpha values. It's pretty powerful! + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function ShockwaveFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./shockwave.frag'), + // custom uniforms + { + center: { type: 'v2', value: { x: 0.5, y: 0.5 } }, + params: { type: 'v3', value: { x: 10, y: 0.8, z: 0.1 } }, + time: { type: '1f', value: 0 } + } + ); + + this.center = [0.5, 0.5]; + this.params = [10, 0.8, 0.1]; + this.time = 0; +} + +ShockwaveFilter.prototype = Object.create(core.Filter.prototype); +ShockwaveFilter.prototype.constructor = ShockwaveFilter; +module.exports = ShockwaveFilter; + +Object.defineProperties(ShockwaveFilter.prototype, { + /** + * Sets the center of the shockwave in normalized screen coords. That is + * (0,0) is the top-left and (1,1) is the bottom right. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + center: { + get: function () + { + return this.uniforms.center; + }, + set: function (value) + { + this.uniforms.center = value; + } + }, + /** + * Sets the params of the shockwave. These modify the look and behavior of + * the shockwave as it ripples out. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + params: { + get: function () + { + return this.uniforms.params; + }, + set: function (value) + { + this.uniforms.params = value; + } + }, + /** + * Sets the elapsed time of the shockwave. This controls the speed at which + * the shockwave ripples out. + * + * @member {number} + * @memberof PIXI.filters.ShockwaveFilter# + */ + time: { + get: function () + { + return this.uniforms.time; + }, + set: function (value) + { + this.uniforms.time = value; + } + } +}); diff --git a/src/filters/shockwave/shockwave.frag b/src/filters/shockwave/shockwave.frag new file mode 100644 index 0000000..db2642e --- /dev/null +++ b/src/filters/shockwave/shockwave.frag @@ -0,0 +1,27 @@ +varying vec2 vTextureCoord; + +uniform sampler2D uSampler; + +uniform vec2 center; +uniform vec3 params; // 10.0, 0.8, 0.1 +uniform float time; + +void main() +{ + vec2 uv = vTextureCoord; + vec2 texCoord = uv; + + float dist = distance(uv, center); + + if ( (dist <= (time + params.z)) && (dist >= (time - params.z)) ) + { + float diff = (dist - time); + float powDiff = 1.0 - pow(abs(diff*params.x), params.y); + + float diffTime = diff * powDiff; + vec2 diffUV = normalize(uv - center); + texCoord = uv + (diffUV * diffTime); + } + + gl_FragColor = texture2D(uSampler, texCoord); +} diff --git a/src/filters/tiltshift/TiltShiftAxisFilter.js b/src/filters/tiltshift/TiltShiftAxisFilter.js new file mode 100644 index 0000000..17a2dd5 --- /dev/null +++ b/src/filters/tiltshift/TiltShiftAxisFilter.js @@ -0,0 +1,121 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftAxisFilter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function TiltShiftAxisFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./tilt-shift.frag') + + ); + + this.uniforms.blur = 100; + this.uniforms.gradientBlur = 600; + this.uniforms.start = new PIXI.Point(0, window.innerHeight / 2); + this.uniforms.end = new PIXI.Point(600, window.innerHeight / 2); + this.uniforms.delta = new PIXI.Point(30, 30); + this.uniforms.texSize = new PIXI.Point(window.innerWidth, window.innerHeight); + + this.updateDelta(); +} + +TiltShiftAxisFilter.prototype = Object.create(core.Filter.prototype); +TiltShiftAxisFilter.prototype.constructor = TiltShiftAxisFilter; +module.exports = TiltShiftAxisFilter; + +/** + * Updates the filter delta values. + * This is overridden in the X and Y filters, does nothing for this class. + * + */ +TiltShiftAxisFilter.prototype.updateDelta = function () +{ + this.uniforms.delta.x = 0; + this.uniforms.delta.y = 0; +}; + +Object.defineProperties(TiltShiftAxisFilter.prototype, { + /** + * The strength of the blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + blur: { + get: function () + { + return this.uniforms.blur; + }, + set: function (value) + { + this.uniforms.blur = value; + } + }, + + /** + * The strength of the gradient blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + gradientBlur: { + get: function () + { + return this.uniforms.gradientBlur; + }, + set: function (value) + { + this.uniforms.gradientBlur = value; + } + }, + + /** + * The X value to start the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + start: { + get: function () + { + return this.uniforms.start; + }, + set: function (value) + { + this.uniforms.start = value; + this.updateDelta(); + } + }, + + /** + * The X value to end the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + end: { + get: function () + { + return this.uniforms.end; + }, + set: function (value) + { + this.uniforms.end = value; + this.updateDelta(); + } + } +}); diff --git a/src/filters/tiltshift/TiltShiftFilter.js b/src/filters/tiltshift/TiltShiftFilter.js new file mode 100644 index 0000000..671ac7a --- /dev/null +++ b/src/filters/tiltshift/TiltShiftFilter.js @@ -0,0 +1,108 @@ +var core = require('../../core'), + TiltShiftXFilter = require('./TiltShiftXFilter'), + TiltShiftYFilter = require('./TiltShiftYFilter'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShift Filter. Manages the pass of both a TiltShiftXFilter and TiltShiftYFilter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function TiltShiftFilter() +{ + core.Filter.call(this); + + this.tiltShiftXFilter = new TiltShiftXFilter(); + this.tiltShiftYFilter = new TiltShiftYFilter(); +} + +TiltShiftFilter.prototype = Object.create(core.Filter.prototype); +TiltShiftFilter.prototype.constructor = TiltShiftFilter; +module.exports = TiltShiftFilter; + +TiltShiftFilter.prototype.apply = function (filterManager, input, output) +{ + var renderTarget = filterManager.getRenderTarget(true); + + this.tiltShiftXFilter.apply(filterManager, input, renderTarget); + + this.tiltShiftYFilter.apply(filterManager, renderTarget, output); + + filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(TiltShiftFilter.prototype, { + /** + * The strength of the blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + blur: { + get: function () + { + return this.tiltShiftXFilter.blur; + }, + set: function (value) + { + this.tiltShiftXFilter.blur = this.tiltShiftYFilter.blur = value; + } + }, + + /** + * The strength of the gradient blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + gradientBlur: { + get: function () + { + return this.tiltShiftXFilter.gradientBlur; + }, + set: function (value) + { + this.tiltShiftXFilter.gradientBlur = this.tiltShiftYFilter.gradientBlur = value; + } + }, + + /** + * The Y value to start the effect at. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + start: { + get: function () + { + return this.tiltShiftXFilter.start; + }, + set: function (value) + { + this.tiltShiftXFilter.start = this.tiltShiftYFilter.start = value; + } + }, + + /** + * The Y value to end the effect at. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + end: { + get: function () + { + return this.tiltShiftXFilter.end; + }, + set: function (value) + { + this.tiltShiftXFilter.end = this.tiltShiftYFilter.end = value; + } + } +}); diff --git a/src/filters/tiltshift/TiltShiftXFilter.js b/src/filters/tiltshift/TiltShiftXFilter.js new file mode 100644 index 0000000..d6d82ea --- /dev/null +++ b/src/filters/tiltshift/TiltShiftXFilter.js @@ -0,0 +1,36 @@ +var TiltShiftAxisFilter = require('./TiltShiftAxisFilter'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftXFilter. + * + * @class + * @extends PIXI.TiltShiftAxisFilter + * @memberof PIXI.filters + */ +function TiltShiftXFilter() +{ + TiltShiftAxisFilter.call(this); +} + +TiltShiftXFilter.prototype = Object.create(TiltShiftAxisFilter.prototype); +TiltShiftXFilter.prototype.constructor = TiltShiftXFilter; +module.exports = TiltShiftXFilter; + +/** + * Updates the filter delta values. + * + */ +TiltShiftXFilter.prototype.updateDelta = function () +{ + var dx = this.uniforms.end.x - this.uniforms.start.x; + var dy = this.uniforms.end.y - this.uniforms.start.y; + var d = Math.sqrt(dx * dx + dy * dy); + + this.uniforms.delta.x = dx / d; + this.uniforms.delta.y = dy / d; +}; diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/filters/noise/NoiseFilter.js b/src/filters/noise/NoiseFilter.js new file mode 100644 index 0000000..f333659 --- /dev/null +++ b/src/filters/noise/NoiseFilter.js @@ -0,0 +1,50 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js + */ + +/** + * A Noise effect filter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function NoiseFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./noise.frag') + ); + + this.noise = 0.5; +} + +NoiseFilter.prototype = Object.create(core.Filter.prototype); +NoiseFilter.prototype.constructor = NoiseFilter; +module.exports = NoiseFilter; + +Object.defineProperties(NoiseFilter.prototype, { + /** + * The amount of noise to apply. + * + * @member {number} + * @memberof PIXI.filters.NoiseFilter# + * @default 0.5 + */ + noise: { + get: function () + { + return this.uniforms.noise; + }, + set: function (value) + { + this.uniforms.noise = value; + } + } +}); diff --git a/src/filters/noise/noise.frag b/src/filters/noise/noise.frag new file mode 100644 index 0000000..3954a0a --- /dev/null +++ b/src/filters/noise/noise.frag @@ -0,0 +1,25 @@ +precision highp float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform float noise; +uniform sampler2D uSampler; + +float rand(vec2 co) +{ + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + + float diff = (rand(gl_FragCoord.xy) - 0.5) * noise; + + color.r += diff; + color.g += diff; + color.b += diff; + + gl_FragColor = color; +} diff --git a/src/filters/shockwave/ShockwaveFilter.js b/src/filters/shockwave/ShockwaveFilter.js new file mode 100644 index 0000000..709bb86 --- /dev/null +++ b/src/filters/shockwave/ShockwaveFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ColorMatrixFilter class lets you apply a 4x4 matrix transformation on the RGBA + * color and alpha values of every pixel on your displayObject to produce a result + * with a new set of RGBA color and alpha values. It's pretty powerful! + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function ShockwaveFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./shockwave.frag'), + // custom uniforms + { + center: { type: 'v2', value: { x: 0.5, y: 0.5 } }, + params: { type: 'v3', value: { x: 10, y: 0.8, z: 0.1 } }, + time: { type: '1f', value: 0 } + } + ); + + this.center = [0.5, 0.5]; + this.params = [10, 0.8, 0.1]; + this.time = 0; +} + +ShockwaveFilter.prototype = Object.create(core.Filter.prototype); +ShockwaveFilter.prototype.constructor = ShockwaveFilter; +module.exports = ShockwaveFilter; + +Object.defineProperties(ShockwaveFilter.prototype, { + /** + * Sets the center of the shockwave in normalized screen coords. That is + * (0,0) is the top-left and (1,1) is the bottom right. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + center: { + get: function () + { + return this.uniforms.center; + }, + set: function (value) + { + this.uniforms.center = value; + } + }, + /** + * Sets the params of the shockwave. These modify the look and behavior of + * the shockwave as it ripples out. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + params: { + get: function () + { + return this.uniforms.params; + }, + set: function (value) + { + this.uniforms.params = value; + } + }, + /** + * Sets the elapsed time of the shockwave. This controls the speed at which + * the shockwave ripples out. + * + * @member {number} + * @memberof PIXI.filters.ShockwaveFilter# + */ + time: { + get: function () + { + return this.uniforms.time; + }, + set: function (value) + { + this.uniforms.time = value; + } + } +}); diff --git a/src/filters/shockwave/shockwave.frag b/src/filters/shockwave/shockwave.frag new file mode 100644 index 0000000..db2642e --- /dev/null +++ b/src/filters/shockwave/shockwave.frag @@ -0,0 +1,27 @@ +varying vec2 vTextureCoord; + +uniform sampler2D uSampler; + +uniform vec2 center; +uniform vec3 params; // 10.0, 0.8, 0.1 +uniform float time; + +void main() +{ + vec2 uv = vTextureCoord; + vec2 texCoord = uv; + + float dist = distance(uv, center); + + if ( (dist <= (time + params.z)) && (dist >= (time - params.z)) ) + { + float diff = (dist - time); + float powDiff = 1.0 - pow(abs(diff*params.x), params.y); + + float diffTime = diff * powDiff; + vec2 diffUV = normalize(uv - center); + texCoord = uv + (diffUV * diffTime); + } + + gl_FragColor = texture2D(uSampler, texCoord); +} diff --git a/src/filters/tiltshift/TiltShiftAxisFilter.js b/src/filters/tiltshift/TiltShiftAxisFilter.js new file mode 100644 index 0000000..17a2dd5 --- /dev/null +++ b/src/filters/tiltshift/TiltShiftAxisFilter.js @@ -0,0 +1,121 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftAxisFilter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function TiltShiftAxisFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./tilt-shift.frag') + + ); + + this.uniforms.blur = 100; + this.uniforms.gradientBlur = 600; + this.uniforms.start = new PIXI.Point(0, window.innerHeight / 2); + this.uniforms.end = new PIXI.Point(600, window.innerHeight / 2); + this.uniforms.delta = new PIXI.Point(30, 30); + this.uniforms.texSize = new PIXI.Point(window.innerWidth, window.innerHeight); + + this.updateDelta(); +} + +TiltShiftAxisFilter.prototype = Object.create(core.Filter.prototype); +TiltShiftAxisFilter.prototype.constructor = TiltShiftAxisFilter; +module.exports = TiltShiftAxisFilter; + +/** + * Updates the filter delta values. + * This is overridden in the X and Y filters, does nothing for this class. + * + */ +TiltShiftAxisFilter.prototype.updateDelta = function () +{ + this.uniforms.delta.x = 0; + this.uniforms.delta.y = 0; +}; + +Object.defineProperties(TiltShiftAxisFilter.prototype, { + /** + * The strength of the blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + blur: { + get: function () + { + return this.uniforms.blur; + }, + set: function (value) + { + this.uniforms.blur = value; + } + }, + + /** + * The strength of the gradient blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + gradientBlur: { + get: function () + { + return this.uniforms.gradientBlur; + }, + set: function (value) + { + this.uniforms.gradientBlur = value; + } + }, + + /** + * The X value to start the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + start: { + get: function () + { + return this.uniforms.start; + }, + set: function (value) + { + this.uniforms.start = value; + this.updateDelta(); + } + }, + + /** + * The X value to end the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + end: { + get: function () + { + return this.uniforms.end; + }, + set: function (value) + { + this.uniforms.end = value; + this.updateDelta(); + } + } +}); diff --git a/src/filters/tiltshift/TiltShiftFilter.js b/src/filters/tiltshift/TiltShiftFilter.js new file mode 100644 index 0000000..671ac7a --- /dev/null +++ b/src/filters/tiltshift/TiltShiftFilter.js @@ -0,0 +1,108 @@ +var core = require('../../core'), + TiltShiftXFilter = require('./TiltShiftXFilter'), + TiltShiftYFilter = require('./TiltShiftYFilter'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShift Filter. Manages the pass of both a TiltShiftXFilter and TiltShiftYFilter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function TiltShiftFilter() +{ + core.Filter.call(this); + + this.tiltShiftXFilter = new TiltShiftXFilter(); + this.tiltShiftYFilter = new TiltShiftYFilter(); +} + +TiltShiftFilter.prototype = Object.create(core.Filter.prototype); +TiltShiftFilter.prototype.constructor = TiltShiftFilter; +module.exports = TiltShiftFilter; + +TiltShiftFilter.prototype.apply = function (filterManager, input, output) +{ + var renderTarget = filterManager.getRenderTarget(true); + + this.tiltShiftXFilter.apply(filterManager, input, renderTarget); + + this.tiltShiftYFilter.apply(filterManager, renderTarget, output); + + filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(TiltShiftFilter.prototype, { + /** + * The strength of the blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + blur: { + get: function () + { + return this.tiltShiftXFilter.blur; + }, + set: function (value) + { + this.tiltShiftXFilter.blur = this.tiltShiftYFilter.blur = value; + } + }, + + /** + * The strength of the gradient blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + gradientBlur: { + get: function () + { + return this.tiltShiftXFilter.gradientBlur; + }, + set: function (value) + { + this.tiltShiftXFilter.gradientBlur = this.tiltShiftYFilter.gradientBlur = value; + } + }, + + /** + * The Y value to start the effect at. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + start: { + get: function () + { + return this.tiltShiftXFilter.start; + }, + set: function (value) + { + this.tiltShiftXFilter.start = this.tiltShiftYFilter.start = value; + } + }, + + /** + * The Y value to end the effect at. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + end: { + get: function () + { + return this.tiltShiftXFilter.end; + }, + set: function (value) + { + this.tiltShiftXFilter.end = this.tiltShiftYFilter.end = value; + } + } +}); diff --git a/src/filters/tiltshift/TiltShiftXFilter.js b/src/filters/tiltshift/TiltShiftXFilter.js new file mode 100644 index 0000000..d6d82ea --- /dev/null +++ b/src/filters/tiltshift/TiltShiftXFilter.js @@ -0,0 +1,36 @@ +var TiltShiftAxisFilter = require('./TiltShiftAxisFilter'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftXFilter. + * + * @class + * @extends PIXI.TiltShiftAxisFilter + * @memberof PIXI.filters + */ +function TiltShiftXFilter() +{ + TiltShiftAxisFilter.call(this); +} + +TiltShiftXFilter.prototype = Object.create(TiltShiftAxisFilter.prototype); +TiltShiftXFilter.prototype.constructor = TiltShiftXFilter; +module.exports = TiltShiftXFilter; + +/** + * Updates the filter delta values. + * + */ +TiltShiftXFilter.prototype.updateDelta = function () +{ + var dx = this.uniforms.end.x - this.uniforms.start.x; + var dy = this.uniforms.end.y - this.uniforms.start.y; + var d = Math.sqrt(dx * dx + dy * dy); + + this.uniforms.delta.x = dx / d; + this.uniforms.delta.y = dy / d; +}; diff --git a/src/filters/tiltshift/TiltShiftYFilter.js b/src/filters/tiltshift/TiltShiftYFilter.js new file mode 100644 index 0000000..f8804bb --- /dev/null +++ b/src/filters/tiltshift/TiltShiftYFilter.js @@ -0,0 +1,36 @@ +var TiltShiftAxisFilter = require('./TiltShiftAxisFilter'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftYFilter. + * + * @class + * @extends PIXI.TiltShiftAxisFilter + * @memberof PIXI.filters + */ +function TiltShiftYFilter() +{ + TiltShiftAxisFilter.call(this); +} + +TiltShiftYFilter.prototype = Object.create(TiltShiftAxisFilter.prototype); +TiltShiftYFilter.prototype.constructor = TiltShiftYFilter; +module.exports = TiltShiftYFilter; + +/** + * Updates the filter delta values. + * + */ +TiltShiftYFilter.prototype.updateDelta = function () +{ + var dx = this.uniforms.end.x - this.uniforms.start.x; + var dy = this.uniforms.end.y - this.uniforms.start.y; + var d = Math.sqrt(dx * dx + dy * dy); + + this.uniforms.delta.x = -dy / d; + this.uniforms.delta.y = dx / d; +}; diff --git a/src/deprecation.js b/src/deprecation.js index 56dcbfd..1a3c76f 100644 --- a/src/deprecation.js +++ b/src/deprecation.js @@ -497,21 +497,6 @@ /** * @class * @private - * @name PIXI.filters.FXAAFilter - * @see PIXI.FXAAFilter - * @deprecated since version 3.0.6 - */ - FXAAFilter: { - get: function() - { - warn('filters.FXAAFilter is an undocumented alias, please use FXAAFilter from now on.'); - return core.FXAAFilter; - } - }, - - /** - * @class - * @private * @name PIXI.filters.SpriteMaskFilter * @see PIXI.SpriteMaskFilter * @deprecated since version 3.0.6 diff --git a/src/filters/FXAA/FXAA.frag b/src/filters/FXAA/FXAA.frag old mode 100755 new mode 100644 index bb6b18b..568e50b --- a/src/filters/FXAA/FXAA.frag +++ b/src/filters/FXAA/FXAA.frag @@ -1,124 +1,22 @@ -/** -Basic FXAA implementation based on the code on geeks3d.com with the -modification that the texture2DLod stuff was removed since it's -unsupported by WebGL. - --- - -From: -https://github.com/mitsuhiko/webgl-meincraft - -Copyright (c) 2011 by Armin Ronacher. - -Some rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials provided - with the distribution. - - * The names of the contributors may not be used to endorse or - promote products derived from this software without specific - prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef FXAA_REDUCE_MIN - #define FXAA_REDUCE_MIN (1.0/ 128.0) -#endif -#ifndef FXAA_REDUCE_MUL - #define FXAA_REDUCE_MUL (1.0 / 8.0) -#endif -#ifndef FXAA_SPAN_MAX - #define FXAA_SPAN_MAX 8.0 -#endif - -//optimized version for mobile, where dependent -//texture reads can be a bottleneck -vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, - vec2 v_rgbNW, vec2 v_rgbNE, - vec2 v_rgbSW, vec2 v_rgbSE, - vec2 v_rgbM) { - vec4 color; - mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); - vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; - vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; - vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; - vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; - vec4 texColor = texture2D(tex, v_rgbM); - vec3 rgbM = texColor.xyz; - vec3 luma = vec3(0.299, 0.587, 0.114); - float lumaNW = dot(rgbNW, luma); - float lumaNE = dot(rgbNE, luma); - float lumaSW = dot(rgbSW, luma); - float lumaSE = dot(rgbSE, luma); - float lumaM = dot(rgbM, luma); - float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); - float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); - - mediump vec2 dir; - dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); - dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); - - float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); - - float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); - dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), - max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), - dir * rcpDirMin)) * inverseVP; - - vec3 rgbA = 0.5 * ( - texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + - texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); - vec3 rgbB = rgbA * 0.5 + 0.25 * ( - texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + - texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); - - float lumaB = dot(rgbB, luma); - if ((lumaB < lumaMin) || (lumaB > lumaMax)) - color = vec4(rgbA, texColor.a); - else - color = vec4(rgbB, texColor.a); - return color; -} - - -varying vec2 vTextureCoord; -varying vec4 vColor; -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +varying vec2 vTextureCoord; uniform sampler2D uSampler; +uniform vec4 filterArea; +#pragma glslify: fxaa = require('./fxaa.glsl') -void main(void){ +void main() { - gl_FragColor = fxaa(uSampler, vTextureCoord * vResolution, vResolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + vec2 fragCoord = vTextureCoord * filterArea.xy; + vec4 color; + + color = fxaa(uSampler, fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); + + gl_FragColor = color; } diff --git a/src/filters/FXAA/FXAA.vert b/src/filters/FXAA/FXAA.vert old mode 100755 new mode 100644 index 9d1db9b..a37a262 --- a/src/filters/FXAA/FXAA.vert +++ b/src/filters/FXAA/FXAA.vert @@ -1,42 +1,44 @@ + attribute vec2 aVertexPosition; attribute vec2 aTextureCoord; -attribute vec4 aColor; uniform mat3 projectionMatrix; -uniform vec2 resolution; -varying vec2 vTextureCoord; -varying vec4 vColor; - -varying vec2 vResolution; - -//texcoords computed in vertex step -//to avoid dependent texture reads varying vec2 v_rgbNW; varying vec2 v_rgbNE; varying vec2 v_rgbSW; varying vec2 v_rgbSE; varying vec2 v_rgbM; +uniform vec4 filterArea; -void texcoords(vec2 fragCoord, vec2 resolution, - out vec2 v_rgbNW, out vec2 v_rgbNE, - out vec2 v_rgbSW, out vec2 v_rgbSE, - out vec2 v_rgbM) { - vec2 inverseVP = 1.0 / resolution.xy; - v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; - v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; - v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; - v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; - v_rgbM = vec2(fragCoord * inverseVP); +varying vec2 vTextureCoord; + +vec2 mapCoord( vec2 coord ) +{ + coord *= filterArea.xy; + coord += filterArea.zw; + + return coord; } -void main(void){ +vec2 unmapCoord( vec2 coord ) +{ + coord -= filterArea.zw; + coord /= filterArea.xy; + + return coord; +} + +#pragma glslify: texcoords = require('./texcoords.glsl') + +void main(void) { + gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0); - vTextureCoord = aTextureCoord; - vColor = vec4(aColor.rgb * aColor.a, aColor.a); - vResolution = resolution; - //compute the texture coords and send them to varyings - texcoords(aTextureCoord * resolution, resolution, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); -} + vTextureCoord = aTextureCoord; + + vec2 fragCoord = vTextureCoord * filterArea.xy; + + texcoords(fragCoord, filterArea.xy, v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM); +} \ No newline at end of file diff --git a/src/filters/FXAA/FXAAFilter.js b/src/filters/FXAA/FXAAFilter.js index 4d7aaff..b2a77c7 100644 --- a/src/filters/FXAA/FXAAFilter.js +++ b/src/filters/FXAA/FXAAFilter.js @@ -1,6 +1,5 @@ -var AbstractFilter = require('./AbstractFilter'); -// @see https://github.com/substack/brfs/issues/25 -var fs = require('fs'); +var core = require('../../core'); +var glslify = require('glslify'); /** * @@ -19,35 +18,18 @@ */ function FXAAFilter() { - AbstractFilter.call(this, + //TODO - needs work + core.Filter.call(this, + // vertex shader - fs.readFileSync(__dirname + '/FXAA.vert', 'utf8'), + glslify('./fxaa.vert'), // fragment shader - fs.readFileSync(__dirname + '/FXAA.frag', 'utf8'), - // uniforms - { - resolution: { type: 'v2', value: { x: 1, y: 1 } } - } + glslify('./fxaa.frag') ); } -FXAAFilter.prototype = Object.create(AbstractFilter.prototype); +FXAAFilter.prototype = Object.create(core.Filter.prototype); FXAAFilter.prototype.constructor = FXAAFilter; + module.exports = FXAAFilter; - -/** - * Applies the filter - * - * @param renderer {PIXI.WebGLRenderer} The renderer to retrieve the filter from - * @param input {PIXI.RenderTarget} - * @param output {PIXI.RenderTarget} - */ -FXAAFilter.prototype.applyFilter = function (renderer, input, output) -{ - var filterManager = renderer.filterManager; - - var shader = this.getShader( renderer ); - // draw the filter... - filterManager.applyFilter(shader, input, output); -}; diff --git a/src/filters/convolution/ConvolutionFilter.js b/src/filters/convolution/ConvolutionFilter.js new file mode 100644 index 0000000..51775ba --- /dev/null +++ b/src/filters/convolution/ConvolutionFilter.js @@ -0,0 +1,87 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ConvolutionFilter class applies a matrix convolution filter effect. + * A convolution combines pixels in the input image with neighboring pixels to produce a new image. + * A wide variety of image effects can be achieved through convolutions, including blurring, edge + * detection, sharpening, embossing, and beveling. The matrix should be specified as a 9 point Array. + * See http://docs.gimp.org/en/plug-in-convmatrix.html for more info. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + * @param matrix {number[]} An array of values used for matrix transformation. Specified as a 9 point Array. + * @param width {number} Width of the object you are transforming + * @param height {number} Height of the object you are transforming + */ +function ConvolutionFilter(matrix, width, height) +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./convolution.frag') + ); + + this.matrix = matrix; + this.width = width; + this.height = height; +} + +ConvolutionFilter.prototype = Object.create(core.Filter.prototype); +ConvolutionFilter.prototype.constructor = ConvolutionFilter; +module.exports = ConvolutionFilter; + +Object.defineProperties(ConvolutionFilter.prototype, { + /** + * An array of values used for matrix transformation. Specified as a 9 point Array. + * + * @member {number[]} + * @memberof PIXI.filters.ConvolutionFilter# + */ + matrix: { + get: function () + { + return this.uniforms.matrix; + }, + set: function (value) + { + this.uniforms.matrix = new Float32Array(value); + } + }, + + /** + * Width of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + width: { + get: function () + { + return 1/this.uniforms.texelSize[0]; + }, + set: function (value) + { + this.uniforms.texelSize[0] = 1/value; + } + }, + + /** + * Height of the object you are transforming + * + * @member {number} + * @memberof PIXI.filters.ConvolutionFilter# + */ + height: { + get: function () + { + return 1/this.uniforms.texelSize[1]; + }, + set: function (value) + { + this.uniforms.texelSize[1] = 1/value; + } + } +}); diff --git a/src/filters/convolution/convolution.frag b/src/filters/convolution/convolution.frag new file mode 100644 index 0000000..e6fe7b5 --- /dev/null +++ b/src/filters/convolution/convolution.frag @@ -0,0 +1,29 @@ +precision mediump float; + +varying mediump vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform vec2 texelSize; +uniform float matrix[9]; + +void main(void) +{ + vec4 c11 = texture2D(uSampler, vTextureCoord - texelSize); // top left + vec4 c12 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y - texelSize.y)); // top center + vec4 c13 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y - texelSize.y)); // top right + + vec4 c21 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y)); // mid left + vec4 c22 = texture2D(uSampler, vTextureCoord); // mid center + vec4 c23 = texture2D(uSampler, vec2(vTextureCoord.x + texelSize.x, vTextureCoord.y)); // mid right + + vec4 c31 = texture2D(uSampler, vec2(vTextureCoord.x - texelSize.x, vTextureCoord.y + texelSize.y)); // bottom left + vec4 c32 = texture2D(uSampler, vec2(vTextureCoord.x, vTextureCoord.y + texelSize.y)); // bottom center + vec4 c33 = texture2D(uSampler, vTextureCoord + texelSize); // bottom right + + gl_FragColor = + c11 * matrix[0] + c12 * matrix[1] + c13 * matrix[2] + + c21 * matrix[3] + c22 * matrix[4] + c23 * matrix[5] + + c31 * matrix[6] + c32 * matrix[7] + c33 * matrix[8]; + + gl_FragColor.a = c22.a; +} diff --git a/src/filters/dot/DotFilter.js b/src/filters/dot/DotFilter.js new file mode 100644 index 0000000..d2bc544 --- /dev/null +++ b/src/filters/dot/DotFilter.js @@ -0,0 +1,66 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Mat Groves http://matgroves.com/ @Doormat23 + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/fun/dotscreen.js + */ + +/** + * This filter applies a dotscreen effect making display objects appear to be made out of + * black and white halftone dots like an old printer. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function DotFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./dot.frag') + ); + + this.scale = 1; + this.angle = 5; +} + +DotFilter.prototype = Object.create(core.Filter.prototype); +DotFilter.prototype.constructor = DotFilter; +module.exports = DotFilter; + +Object.defineProperties(DotFilter.prototype, { + /** + * The scale of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + scale: { + get: function () + { + return this.uniforms.scale; + }, + set: function (value) + { + this.uniforms.scale = value; + } + }, + + /** + * The radius of the effect. + * @member {number} + * @memberof PIXI.filters.DotFilter# + */ + angle: { + get: function () + { + return this.uniforms.angle; + }, + set: function (value) + { + this.uniforms.angle = value; + } + } +}); diff --git a/src/filters/dot/dot.frag b/src/filters/dot/dot.frag new file mode 100644 index 0000000..91341b1 --- /dev/null +++ b/src/filters/dot/dot.frag @@ -0,0 +1,28 @@ +precision mediump float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform vec4 filterArea; +uniform sampler2D uSampler; + +uniform float angle; +uniform float scale; + +float pattern() +{ + float s = sin(angle), c = cos(angle); + vec2 tex = vTextureCoord * filterArea.xy; + vec2 point = vec2( + c * tex.x - s * tex.y, + s * tex.x + c * tex.y + ) * scale; + return (sin(point.x) * sin(point.y)) * 4.0; +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + float average = (color.r + color.g + color.b) / 3.0; + gl_FragColor = vec4(vec3(average * 10.0 - 5.0 + pattern()), color.a); +} diff --git a/src/filters/dropshadow/BlurYTintFilter.js b/src/filters/dropshadow/BlurYTintFilter.js new file mode 100644 index 0000000..9767b01 --- /dev/null +++ b/src/filters/dropshadow/BlurYTintFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); + +// @see https://github.com/substack/brfs/issues/25 +var fs = require('fs'); + +/** + * The BlurYTintFilter applies a vertical Gaussian blur to an object. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function BlurYTintFilter() +{ + core.AbstractFilter.call(this, + // vertex shader + fs.readFileSync(__dirname + '/blurYTint.vert', 'utf8'), + // fragment shader + fs.readFileSync(__dirname + '/blurYTint.frag', 'utf8'), + // set the uniforms + { + blur: { type: '1f', value: 1 / 512 }, + color: { type: 'c', value: [0,0,0]}, + alpha: { type: '1f', value: 0.7 }, + offset: { type: '2f', value:[5, 5]}, + strength: { type: '1f', value:1} + } + ); + + this.passes = 1; + this.strength = 4; +} + +BlurYTintFilter.prototype = Object.create(core.AbstractFilter.prototype); +BlurYTintFilter.prototype.constructor = BlurYTintFilter; +module.exports = BlurYTintFilter; + +BlurYTintFilter.prototype.applyFilter = function (renderer, input, output, clear) +{ + var shader = this.getShader(renderer); + + this.uniforms.strength.value = this.strength / 4 / this.passes * (input.frame.height / input.size.height); + + if(this.passes === 1) + { + renderer.filterManager.applyFilter(shader, input, output, clear); + } + else + { + var renderTarget = renderer.filterManager.getRenderTarget(true); + var flip = input; + var flop = renderTarget; + + for(var i = 0; i < this.passes-1; i++) + { + renderer.filterManager.applyFilter(shader, flip, flop, clear); + + var temp = flop; + flop = flip; + flip = temp; + } + + renderer.filterManager.applyFilter(shader, flip, output, clear); + + renderer.filterManager.returnRenderTarget(renderTarget); + } +}; + + +Object.defineProperties(BlurYTintFilter.prototype, { + /** + * Sets the strength of both the blur. + * + * @member {number} + * @memberof PIXI.filters.BlurYTintFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.strength; + }, + set: function (value) + { + this.padding = value * 0.5; + this.strength = value; + } + } +}); diff --git a/src/filters/dropshadow/DropShadowFilter.js b/src/filters/dropshadow/DropShadowFilter.js new file mode 100644 index 0000000..e34b223 --- /dev/null +++ b/src/filters/dropshadow/DropShadowFilter.js @@ -0,0 +1,191 @@ +var core = require('../../core'), + BlurXFilter = require('../blur/BlurXFilter'), + BlurYTintFilter = require('./BlurYTintFilter'); + +/** + * The DropShadowFilter applies a Gaussian blur to an object. + * The strength of the blur can be set for x- and y-axis separately. + * + * @class + * @extends PIXI.AbstractFilter + * @memberof PIXI.filters + */ +function DropShadowFilter() +{ + core.AbstractFilter.call(this); + + this.blurXFilter = new BlurXFilter(); + this.blurYTintFilter = new BlurYTintFilter(); + + this.defaultFilter = new core.AbstractFilter(); + + this.padding = 30; + + this._dirtyPosition = true; + this._angle = 45 * Math.PI / 180; + this._distance = 10; + this.alpha = 0.75; + this.hideObject = false; + this.blendMode = core.BLEND_MODES.MULTIPLY; +} + +DropShadowFilter.prototype = Object.create(core.AbstractFilter.prototype); +DropShadowFilter.prototype.constructor = DropShadowFilter; +module.exports = DropShadowFilter; + +DropShadowFilter.prototype.applyFilter = function (renderer, input, output) +{ + var renderTarget = renderer.filterManager.getRenderTarget(true); + + //TODO - copyTexSubImage2D could be used here? + if(this._dirtyPosition) + { + this._dirtyPosition = false; + + this.blurYTintFilter.uniforms.offset.value[0] = Math.sin(this._angle) * this._distance; + this.blurYTintFilter.uniforms.offset.value[1] = Math.cos(this._angle) * this._distance; + } + + this.blurXFilter.applyFilter(renderer, input, renderTarget); + + renderer.blendModeManager.setBlendMode(this.blendMode); + + this.blurYTintFilter.applyFilter(renderer, renderTarget, output); + + renderer.blendModeManager.setBlendMode(core.BLEND_MODES.NORMAL); + + if(!this.hideObject) + { + + this.defaultFilter.applyFilter(renderer, input, output); + } + + + renderer.filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(DropShadowFilter.prototype, { + /** + * Sets the strength of both the blurX and blurY properties simultaneously + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blur: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurX property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurX: { + get: function () + { + return this.blurXFilter.blur; + }, + set: function (value) + { + this.blurXFilter.blur = value; + } + }, + + /** + * Sets the strength of the blurY property + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + * @default 2 + */ + blurY: { + get: function () + { + return this.blurYTintFilter.blur; + }, + set: function (value) + { + this.blurYTintFilter.blur = value; + } + }, + + /** + * Sets the color of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + color: { + get: function () + { + return core.utils.rgb2hex( this.blurYTintFilter.uniforms.color.value ); + }, + set: function (value) + { + this.blurYTintFilter.uniforms.color.value = core.utils.hex2rgb(value); + } + }, + + /** + * Sets the alpha of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + alpha: { + get: function () + { + return this.blurYTintFilter.uniforms.alpha.value; + }, + set: function (value) + { + this.blurYTintFilter.uniforms.alpha.value = value; + } + }, + + /** + * Sets the distance of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + distance: { + get: function () + { + return this._distance; + }, + set: function (value) + { + this._dirtyPosition = true; + this._distance = value; + } + }, + + /** + * Sets the angle of the shadow + * + * @member {number} + * @memberOf PIXI.filters.DropShadowFilter# + */ + angle: { + get: function () + { + return this._angle; + }, + set: function (value) + { + this._dirtyPosition = true; + this._angle = value; + } + } +}); diff --git a/src/filters/dropshadow/blurYTint.frag b/src/filters/dropshadow/blurYTint.frag new file mode 100644 index 0000000..650e093 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.frag @@ -0,0 +1,25 @@ +precision lowp float; + +varying vec2 vTextureCoord; +varying vec2 vBlurTexCoords[6]; +varying vec4 vColor; + +uniform vec3 color; +uniform float alpha; + +uniform sampler2D uSampler; + +void main(void) +{ + vec4 sum = vec4(0.0); + + sum += texture2D(uSampler, vBlurTexCoords[ 0])*0.004431848411938341; + sum += texture2D(uSampler, vBlurTexCoords[ 1])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 2])*0.2419707245191454; + sum += texture2D(uSampler, vTextureCoord )*0.3989422804014327; + sum += texture2D(uSampler, vBlurTexCoords[ 3])*0.2419707245191454; + sum += texture2D(uSampler, vBlurTexCoords[ 4])*0.05399096651318985; + sum += texture2D(uSampler, vBlurTexCoords[ 5])*0.004431848411938341; + + gl_FragColor = vec4( color.rgb * sum.a * alpha, sum.a * alpha ); +} diff --git a/src/filters/dropshadow/blurYTint.vert b/src/filters/dropshadow/blurYTint.vert new file mode 100644 index 0000000..7262333 --- /dev/null +++ b/src/filters/dropshadow/blurYTint.vert @@ -0,0 +1,27 @@ +attribute vec2 aVertexPosition; +attribute vec2 aTextureCoord; +attribute vec4 aColor; + +uniform float strength; +uniform vec2 offset; + +uniform mat3 projectionMatrix; + +varying vec2 vTextureCoord; +varying vec4 vColor; +varying vec2 vBlurTexCoords[6]; + +void main(void) +{ + gl_Position = vec4((projectionMatrix * vec3((aVertexPosition+offset), 1.0)).xy, 0.0, 1.0); + vTextureCoord = aTextureCoord; + + vBlurTexCoords[ 0] = aTextureCoord + vec2(0.0, -0.012 * strength); + vBlurTexCoords[ 1] = aTextureCoord + vec2(0.0, -0.008 * strength); + vBlurTexCoords[ 2] = aTextureCoord + vec2(0.0, -0.004 * strength); + vBlurTexCoords[ 3] = aTextureCoord + vec2(0.0, 0.004 * strength); + vBlurTexCoords[ 4] = aTextureCoord + vec2(0.0, 0.008 * strength); + vBlurTexCoords[ 5] = aTextureCoord + vec2(0.0, 0.012 * strength); + + vColor = vec4(aColor.rgb * aColor.a, aColor.a); +} diff --git a/src/filters/fxaa/fxaa.glsl b/src/filters/fxaa/fxaa.glsl new file mode 100644 index 0000000..cc30c00 --- /dev/null +++ b/src/filters/fxaa/fxaa.glsl @@ -0,0 +1,104 @@ +/** +Basic FXAA implementation based on the code on geeks3d.com with the +modification that the texture2DLod stuff was removed since it's +unsupported by WebGL. + +-- + +From: +https://github.com/mitsuhiko/webgl-meincraft + +Copyright (c) 2011 by Armin Ronacher. + +Some rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + + * The names of the contributors may not be used to endorse or + promote products derived from this software without specific + prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef FXAA_REDUCE_MIN + #define FXAA_REDUCE_MIN (1.0/ 128.0) +#endif +#ifndef FXAA_REDUCE_MUL + #define FXAA_REDUCE_MUL (1.0 / 8.0) +#endif +#ifndef FXAA_SPAN_MAX + #define FXAA_SPAN_MAX 8.0 +#endif + +//optimized version for mobile, where dependent +//texture reads can be a bottleneck +vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution, + vec2 v_rgbNW, vec2 v_rgbNE, + vec2 v_rgbSW, vec2 v_rgbSE, + vec2 v_rgbM) { + vec4 color; + mediump vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y); + vec3 rgbNW = texture2D(tex, v_rgbNW).xyz; + vec3 rgbNE = texture2D(tex, v_rgbNE).xyz; + vec3 rgbSW = texture2D(tex, v_rgbSW).xyz; + vec3 rgbSE = texture2D(tex, v_rgbSE).xyz; + vec4 texColor = texture2D(tex, v_rgbM); + vec3 rgbM = texColor.xyz; + vec3 luma = vec3(0.299, 0.587, 0.114); + float lumaNW = dot(rgbNW, luma); + float lumaNE = dot(rgbNE, luma); + float lumaSW = dot(rgbSW, luma); + float lumaSE = dot(rgbSE, luma); + float lumaM = dot(rgbM, luma); + float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE))); + float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE))); + + mediump vec2 dir; + dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE)); + dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); + + float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); + + float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); + dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), + max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), + dir * rcpDirMin)) * inverseVP; + + vec3 rgbA = 0.5 * ( + texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz + + texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz); + vec3 rgbB = rgbA * 0.5 + 0.25 * ( + texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz + + texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz); + + float lumaB = dot(rgbB, luma); + if ((lumaB < lumaMin) || (lumaB > lumaMax)) + color = vec4(rgbA, texColor.a); + else + color = vec4(rgbB, texColor.a); + return color; +} + +#pragma glslify: export(fxaa) diff --git a/src/filters/fxaa/texcoords.glsl b/src/filters/fxaa/texcoords.glsl new file mode 100644 index 0000000..ef3ab0c --- /dev/null +++ b/src/filters/fxaa/texcoords.glsl @@ -0,0 +1,19 @@ +//To save 9 dependent texture reads, you can compute +//these in the vertex shader and use the optimized +//frag.glsl function in your frag shader. + +//This is best suited for mobile devices, like iOS. + +void texcoords(vec2 fragCoord, vec2 resolution, + out vec2 v_rgbNW, out vec2 v_rgbNE, + out vec2 v_rgbSW, out vec2 v_rgbSE, + out vec2 v_rgbM) { + vec2 inverseVP = 1.0 / resolution.xy; + v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP; + v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP; + v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP; + v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP; + v_rgbM = vec2(fragCoord * inverseVP); +} + +#pragma glslify: export(texcoords) \ No newline at end of file diff --git a/src/filters/index.js b/src/filters/index.js index 3f37abc..6709e39 100644 --- a/src/filters/index.js +++ b/src/filters/index.js @@ -11,21 +11,18 @@ module.exports = { AsciiFilter: require('./ascii/AsciiFilter'), BloomFilter: require('./bloom/BloomFilter'), - // BlurDirFilter: require('./blur/BlurDirFilter'), - // ColorStepFilter: require('./color/ColorStepFilter'), - // ConvolutionFilter: require('./convolution/ConvolutionFilter'), + ConvolutionFilter: require('./convolution/ConvolutionFilter'), CrossHatchFilter: require('./crosshatch/CrossHatchFilter'), - // DotScreenFilter: require('./dot/DotScreenFilter'), + DotFilter: require('./dot/DotFilter'), + FXAAFilter: require('./fxaa/FXAAFilter'), // DropShadowFilter: require('./dropshadow/DropShadowFilter'), - // InvertFilter: require('./invert/InvertFilter'), - // NoiseFilter: require('./noise/NoiseFilter'), + NoiseFilter: require('./noise/NoiseFilter'), PixelateFilter: require('./pixelate/PixelateFilter'), RGBSplitFilter: require('./rgb/RGBSplitFilter'), EmbossFilter: require('./emboss/EmbossFilter'), - // ShockwaveFilter: require('./shockwave/ShockwaveFilter'), - // SepiaFilter: require('./sepia/SepiaFilter'), + ShockwaveFilter: require('./shockwave/ShockwaveFilter'), // SmartBlurFilter: require('./blur/SmartBlurFilter'), - // TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), + TiltShiftFilter: require('./tiltshift/TiltShiftFilter'), // TiltShiftXFilter: require('./tiltshift/TiltShiftXFilter'), //TiltShiftYFilter: require('./tiltshift/TiltShiftYFilter'), DisplacementFilter: require('./displacement/DisplacementFilter'), @@ -35,6 +32,5 @@ ColorMatrixFilter: require('./colormatrix/ColorMatrixFilter'), TwistFilter: require('./twist/TwistFilter'), - //GrayFilter: require('./gray/GrayFilter'), VoidFilter: require('./void/VoidFilter') }; diff --git a/src/filters/noise/NoiseFilter.js b/src/filters/noise/NoiseFilter.js new file mode 100644 index 0000000..f333659 --- /dev/null +++ b/src/filters/noise/NoiseFilter.js @@ -0,0 +1,50 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter: https://github.com/evanw/glfx.js/blob/master/src/filters/adjust/noise.js + */ + +/** + * A Noise effect filter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function NoiseFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./noise.frag') + ); + + this.noise = 0.5; +} + +NoiseFilter.prototype = Object.create(core.Filter.prototype); +NoiseFilter.prototype.constructor = NoiseFilter; +module.exports = NoiseFilter; + +Object.defineProperties(NoiseFilter.prototype, { + /** + * The amount of noise to apply. + * + * @member {number} + * @memberof PIXI.filters.NoiseFilter# + * @default 0.5 + */ + noise: { + get: function () + { + return this.uniforms.noise; + }, + set: function (value) + { + this.uniforms.noise = value; + } + } +}); diff --git a/src/filters/noise/noise.frag b/src/filters/noise/noise.frag new file mode 100644 index 0000000..3954a0a --- /dev/null +++ b/src/filters/noise/noise.frag @@ -0,0 +1,25 @@ +precision highp float; + +varying vec2 vTextureCoord; +varying vec4 vColor; + +uniform float noise; +uniform sampler2D uSampler; + +float rand(vec2 co) +{ + return fract(sin(dot(co.xy, vec2(12.9898, 78.233))) * 43758.5453); +} + +void main() +{ + vec4 color = texture2D(uSampler, vTextureCoord); + + float diff = (rand(gl_FragCoord.xy) - 0.5) * noise; + + color.r += diff; + color.g += diff; + color.b += diff; + + gl_FragColor = color; +} diff --git a/src/filters/shockwave/ShockwaveFilter.js b/src/filters/shockwave/ShockwaveFilter.js new file mode 100644 index 0000000..709bb86 --- /dev/null +++ b/src/filters/shockwave/ShockwaveFilter.js @@ -0,0 +1,89 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * The ColorMatrixFilter class lets you apply a 4x4 matrix transformation on the RGBA + * color and alpha values of every pixel on your displayObject to produce a result + * with a new set of RGBA color and alpha values. It's pretty powerful! + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function ShockwaveFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./shockwave.frag'), + // custom uniforms + { + center: { type: 'v2', value: { x: 0.5, y: 0.5 } }, + params: { type: 'v3', value: { x: 10, y: 0.8, z: 0.1 } }, + time: { type: '1f', value: 0 } + } + ); + + this.center = [0.5, 0.5]; + this.params = [10, 0.8, 0.1]; + this.time = 0; +} + +ShockwaveFilter.prototype = Object.create(core.Filter.prototype); +ShockwaveFilter.prototype.constructor = ShockwaveFilter; +module.exports = ShockwaveFilter; + +Object.defineProperties(ShockwaveFilter.prototype, { + /** + * Sets the center of the shockwave in normalized screen coords. That is + * (0,0) is the top-left and (1,1) is the bottom right. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + center: { + get: function () + { + return this.uniforms.center; + }, + set: function (value) + { + this.uniforms.center = value; + } + }, + /** + * Sets the params of the shockwave. These modify the look and behavior of + * the shockwave as it ripples out. + * + * @member {object} + * @memberof PIXI.filters.ShockwaveFilter# + */ + params: { + get: function () + { + return this.uniforms.params; + }, + set: function (value) + { + this.uniforms.params = value; + } + }, + /** + * Sets the elapsed time of the shockwave. This controls the speed at which + * the shockwave ripples out. + * + * @member {number} + * @memberof PIXI.filters.ShockwaveFilter# + */ + time: { + get: function () + { + return this.uniforms.time; + }, + set: function (value) + { + this.uniforms.time = value; + } + } +}); diff --git a/src/filters/shockwave/shockwave.frag b/src/filters/shockwave/shockwave.frag new file mode 100644 index 0000000..db2642e --- /dev/null +++ b/src/filters/shockwave/shockwave.frag @@ -0,0 +1,27 @@ +varying vec2 vTextureCoord; + +uniform sampler2D uSampler; + +uniform vec2 center; +uniform vec3 params; // 10.0, 0.8, 0.1 +uniform float time; + +void main() +{ + vec2 uv = vTextureCoord; + vec2 texCoord = uv; + + float dist = distance(uv, center); + + if ( (dist <= (time + params.z)) && (dist >= (time - params.z)) ) + { + float diff = (dist - time); + float powDiff = 1.0 - pow(abs(diff*params.x), params.y); + + float diffTime = diff * powDiff; + vec2 diffUV = normalize(uv - center); + texCoord = uv + (diffUV * diffTime); + } + + gl_FragColor = texture2D(uSampler, texCoord); +} diff --git a/src/filters/tiltshift/TiltShiftAxisFilter.js b/src/filters/tiltshift/TiltShiftAxisFilter.js new file mode 100644 index 0000000..17a2dd5 --- /dev/null +++ b/src/filters/tiltshift/TiltShiftAxisFilter.js @@ -0,0 +1,121 @@ +var core = require('../../core'); +var glslify = require('glslify'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftAxisFilter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function TiltShiftAxisFilter() +{ + core.Filter.call(this, + // vertex shader + glslify('../fragments/default.vert'), + // fragment shader + glslify('./tilt-shift.frag') + + ); + + this.uniforms.blur = 100; + this.uniforms.gradientBlur = 600; + this.uniforms.start = new PIXI.Point(0, window.innerHeight / 2); + this.uniforms.end = new PIXI.Point(600, window.innerHeight / 2); + this.uniforms.delta = new PIXI.Point(30, 30); + this.uniforms.texSize = new PIXI.Point(window.innerWidth, window.innerHeight); + + this.updateDelta(); +} + +TiltShiftAxisFilter.prototype = Object.create(core.Filter.prototype); +TiltShiftAxisFilter.prototype.constructor = TiltShiftAxisFilter; +module.exports = TiltShiftAxisFilter; + +/** + * Updates the filter delta values. + * This is overridden in the X and Y filters, does nothing for this class. + * + */ +TiltShiftAxisFilter.prototype.updateDelta = function () +{ + this.uniforms.delta.x = 0; + this.uniforms.delta.y = 0; +}; + +Object.defineProperties(TiltShiftAxisFilter.prototype, { + /** + * The strength of the blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + blur: { + get: function () + { + return this.uniforms.blur; + }, + set: function (value) + { + this.uniforms.blur = value; + } + }, + + /** + * The strength of the gradient blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + gradientBlur: { + get: function () + { + return this.uniforms.gradientBlur; + }, + set: function (value) + { + this.uniforms.gradientBlur = value; + } + }, + + /** + * The X value to start the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + start: { + get: function () + { + return this.uniforms.start; + }, + set: function (value) + { + this.uniforms.start = value; + this.updateDelta(); + } + }, + + /** + * The X value to end the effect at. + * + * @member {PIXI.Point} + * @memberof PIXI.filters.TiltShiftAxisFilter# + */ + end: { + get: function () + { + return this.uniforms.end; + }, + set: function (value) + { + this.uniforms.end = value; + this.updateDelta(); + } + } +}); diff --git a/src/filters/tiltshift/TiltShiftFilter.js b/src/filters/tiltshift/TiltShiftFilter.js new file mode 100644 index 0000000..671ac7a --- /dev/null +++ b/src/filters/tiltshift/TiltShiftFilter.js @@ -0,0 +1,108 @@ +var core = require('../../core'), + TiltShiftXFilter = require('./TiltShiftXFilter'), + TiltShiftYFilter = require('./TiltShiftYFilter'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShift Filter. Manages the pass of both a TiltShiftXFilter and TiltShiftYFilter. + * + * @class + * @extends PIXI.Filter + * @memberof PIXI.filters + */ +function TiltShiftFilter() +{ + core.Filter.call(this); + + this.tiltShiftXFilter = new TiltShiftXFilter(); + this.tiltShiftYFilter = new TiltShiftYFilter(); +} + +TiltShiftFilter.prototype = Object.create(core.Filter.prototype); +TiltShiftFilter.prototype.constructor = TiltShiftFilter; +module.exports = TiltShiftFilter; + +TiltShiftFilter.prototype.apply = function (filterManager, input, output) +{ + var renderTarget = filterManager.getRenderTarget(true); + + this.tiltShiftXFilter.apply(filterManager, input, renderTarget); + + this.tiltShiftYFilter.apply(filterManager, renderTarget, output); + + filterManager.returnRenderTarget(renderTarget); +}; + +Object.defineProperties(TiltShiftFilter.prototype, { + /** + * The strength of the blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + blur: { + get: function () + { + return this.tiltShiftXFilter.blur; + }, + set: function (value) + { + this.tiltShiftXFilter.blur = this.tiltShiftYFilter.blur = value; + } + }, + + /** + * The strength of the gradient blur. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + gradientBlur: { + get: function () + { + return this.tiltShiftXFilter.gradientBlur; + }, + set: function (value) + { + this.tiltShiftXFilter.gradientBlur = this.tiltShiftYFilter.gradientBlur = value; + } + }, + + /** + * The Y value to start the effect at. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + start: { + get: function () + { + return this.tiltShiftXFilter.start; + }, + set: function (value) + { + this.tiltShiftXFilter.start = this.tiltShiftYFilter.start = value; + } + }, + + /** + * The Y value to end the effect at. + * + * @member {number} + * @memberof PIXI.filters.TiltShiftFilter# + */ + end: { + get: function () + { + return this.tiltShiftXFilter.end; + }, + set: function (value) + { + this.tiltShiftXFilter.end = this.tiltShiftYFilter.end = value; + } + } +}); diff --git a/src/filters/tiltshift/TiltShiftXFilter.js b/src/filters/tiltshift/TiltShiftXFilter.js new file mode 100644 index 0000000..d6d82ea --- /dev/null +++ b/src/filters/tiltshift/TiltShiftXFilter.js @@ -0,0 +1,36 @@ +var TiltShiftAxisFilter = require('./TiltShiftAxisFilter'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftXFilter. + * + * @class + * @extends PIXI.TiltShiftAxisFilter + * @memberof PIXI.filters + */ +function TiltShiftXFilter() +{ + TiltShiftAxisFilter.call(this); +} + +TiltShiftXFilter.prototype = Object.create(TiltShiftAxisFilter.prototype); +TiltShiftXFilter.prototype.constructor = TiltShiftXFilter; +module.exports = TiltShiftXFilter; + +/** + * Updates the filter delta values. + * + */ +TiltShiftXFilter.prototype.updateDelta = function () +{ + var dx = this.uniforms.end.x - this.uniforms.start.x; + var dy = this.uniforms.end.y - this.uniforms.start.y; + var d = Math.sqrt(dx * dx + dy * dy); + + this.uniforms.delta.x = dx / d; + this.uniforms.delta.y = dy / d; +}; diff --git a/src/filters/tiltshift/TiltShiftYFilter.js b/src/filters/tiltshift/TiltShiftYFilter.js new file mode 100644 index 0000000..f8804bb --- /dev/null +++ b/src/filters/tiltshift/TiltShiftYFilter.js @@ -0,0 +1,36 @@ +var TiltShiftAxisFilter = require('./TiltShiftAxisFilter'); + +/** + * @author Vico @vicocotea + * original filter https://github.com/evanw/glfx.js/blob/master/src/filters/blur/tiltshift.js by Evan Wallace : http://madebyevan.com/ + */ + +/** + * A TiltShiftYFilter. + * + * @class + * @extends PIXI.TiltShiftAxisFilter + * @memberof PIXI.filters + */ +function TiltShiftYFilter() +{ + TiltShiftAxisFilter.call(this); +} + +TiltShiftYFilter.prototype = Object.create(TiltShiftAxisFilter.prototype); +TiltShiftYFilter.prototype.constructor = TiltShiftYFilter; +module.exports = TiltShiftYFilter; + +/** + * Updates the filter delta values. + * + */ +TiltShiftYFilter.prototype.updateDelta = function () +{ + var dx = this.uniforms.end.x - this.uniforms.start.x; + var dy = this.uniforms.end.y - this.uniforms.start.y; + var d = Math.sqrt(dx * dx + dy * dy); + + this.uniforms.delta.x = -dy / d; + this.uniforms.delta.y = dx / d; +}; diff --git a/src/filters/tiltshift/tilt-shift.frag b/src/filters/tiltshift/tilt-shift.frag new file mode 100644 index 0000000..fff2be0 --- /dev/null +++ b/src/filters/tiltshift/tilt-shift.frag @@ -0,0 +1,37 @@ +varying vec2 vTextureCoord; + +uniform sampler2D uSampler; +uniform float blur; +uniform float gradientBlur; +uniform vec2 start; +uniform vec2 end; +uniform vec2 delta; +uniform vec2 texSize; + +float random(vec3 scale, float seed) +{ + return fract(sin(dot(gl_FragCoord.xyz + seed, scale)) * 43758.5453 + seed); +} + +void main(void) +{ + vec4 color = vec4(0.0); + float total = 0.0; + + float offset = random(vec3(12.9898, 78.233, 151.7182), 0.0); + vec2 normal = normalize(vec2(start.y - end.y, end.x - start.x)); + float radius = smoothstep(0.0, 1.0, abs(dot(vTextureCoord * texSize - start, normal)) / gradientBlur) * blur; + + for (float t = -30.0; t <= 30.0; t++) + { + float percent = (t + offset - 0.5) / 30.0; + float weight = 1.0 - abs(percent); + vec4 sample = texture2D(uSampler, vTextureCoord + delta / texSize * percent * radius); + sample.rgb *= sample.a; + color += sample * weight; + total += weight; + } + + gl_FragColor = color / total; + gl_FragColor.rgb /= gl_FragColor.a + 0.00001; +}