From 93fcb7acbf8a40fc1aa851f109456b745c04a7f7 Mon Sep 17 00:00:00 2001 From: photonstorm Date: Wed, 20 Nov 2013 04:04:48 +0000 Subject: [PATCH] Loads more shaders and some fixes and enhancements to PixiShader --- examples/wip/classicTunnelFilter.js | 96 ++ examples/wip/deformStarFilter.js | 2 +- examples/wip/filter.js | 50 +- examples/wip/hueRotationFilter.js | 118 +++ examples/wip/mengerTunnelFilter.js | 163 ++++ examples/wip/shadertoy-effect.js | 1200 ++++++++++++++++++++++++ examples/wip/sineWaveFilter.js | 89 ++ examples/wip/softTunnelFilter.js | 192 ++++ examples/wip/starNurseryFilter.js | 4 +- examples/wip/starfieldFilter.js | 6 +- examples/wip/tunnelFilter.js | 157 ++++ examples/wip/vortexFilter.js | 111 +++ src/pixi/renderers/webgl/PixiShader.js | 120 ++- 13 files changed, 2263 insertions(+), 45 deletions(-) create mode 100644 examples/wip/classicTunnelFilter.js create mode 100644 examples/wip/hueRotationFilter.js create mode 100644 examples/wip/mengerTunnelFilter.js create mode 100644 examples/wip/shadertoy-effect.js create mode 100644 examples/wip/sineWaveFilter.js create mode 100644 examples/wip/softTunnelFilter.js create mode 100644 examples/wip/tunnelFilter.js create mode 100644 examples/wip/vortexFilter.js diff --git a/examples/wip/classicTunnelFilter.js b/examples/wip/classicTunnelFilter.js new file mode 100644 index 00000000..89bce09c --- /dev/null +++ b/examples/wip/classicTunnelFilter.js @@ -0,0 +1,96 @@ +PIXI.TunnelFilter = function(width, height, texture) +{ + PIXI.AbstractFilter.call( this ); + + this.passes = [this]; + + var d = new Date(); + + var dates = [ + d.getFullYear(), // the year (four digits) + d.getMonth(), // the month (from 0-11) + d.getDate(), // the day of the month (from 1-31) + d.getHours()*60.0*60 + d.getMinutes()*60 + d.getSeconds() + ]; + + this.uniforms = { + iResolution: { type: 'f3', value: { x: width, y: height, z: 0 }}, + iGlobalTime: { type: 'f', value: 1 }, + iDate: { type: 'f4', value: dates }, + iChannel0: { type: 'sampler2D', value: texture, wrap: 'repeat' } + }; + + // Shader by 4rknova (https://www.shadertoy.com/view/lssGDn) + this.fragmentSrc = [ + "precision mediump float;", + "uniform vec3 iResolution;", + "uniform float iGlobalTime;", + "uniform float iChannelTime[4];", + "uniform vec4 iMouse;", + "uniform vec4 iDate;", + "uniform vec3 iChannelResolution[4];", + "uniform sampler2D iChannel0;", + "// add any extra uniforms here", + + "#ifdef GL_ES", + "precision highp float;", + "#endif", + + "#define S 0.79577471545 // Precalculated 2.5 / PI", + "#define E 0.0001", + + "void main(void)", + "{", + "vec2 p = (2.0 * gl_FragCoord.xy / iResolution.xy - 1.0)", + "* vec2(iResolution.x / iResolution.y, 1.0);", + "vec2 t = vec2(S * atan(p.x, p.y), 1.0 / max(length(p), E));", + "vec3 c = texture2D(iChannel0, t + vec2(iGlobalTime * 0.1, iGlobalTime)).xyz;", + "gl_FragColor = vec4(c / (t.y + 0.5), 1.0);", + "}" + ]; + +} + +PIXI.TunnelFilter.prototype = Object.create( PIXI.AbstractFilter.prototype ); +PIXI.TunnelFilter.prototype.constructor = PIXI.TunnelFilter; + +Object.defineProperty(PIXI.TunnelFilter.prototype, 'iGlobalTime', { + get: function() { + return this.uniforms.iGlobalTime.value; + }, + set: function(value) { + this.uniforms.iGlobalTime.value = value; + } +}); + +var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('texture', 'wip/tex00.jpg'); + +} + +var filter; +var sprite; + +function create() { + + sprite = game.add.sprite(0, 0, 'texture'); + sprite.width = 800; + sprite.height = 600; + + filter = new PIXI.TunnelFilter(sprite.width, sprite.height, sprite.texture); + + sprite.filters = [filter]; + +} + +function update() { + + filter.iGlobalTime = game.time.totalElapsedSeconds(); + +} + +function render() { +} diff --git a/examples/wip/deformStarFilter.js b/examples/wip/deformStarFilter.js index b62695e5..6ec09516 100644 --- a/examples/wip/deformStarFilter.js +++ b/examples/wip/deformStarFilter.js @@ -17,7 +17,7 @@ PIXI.DeformStarFilter = function(width, height, texture) iResolution: { type: 'f3', value: { x: width, y: height, z: 0 }}, iGlobalTime: { type: 'f', value: 1 }, iDate: { type: 'f4', value: dates }, - iChannel0: { type: 'sampler2D', value: texture } + iChannel0: { type: 'sampler2D', value: texture, wrap: 'repeat' } }; // Shader by iq (https://www.shadertoy.com/view/4dXGRn) diff --git a/examples/wip/filter.js b/examples/wip/filter.js index 994aa2da..10ac4704 100644 --- a/examples/wip/filter.js +++ b/examples/wip/filter.js @@ -17,7 +17,7 @@ PIXI.StarNestFilter = function(width, height, texture) iResolution: { type: 'f3', value: { x: width, y: height, z: 0 }}, iGlobalTime: { type: 'f', value: 1 }, iDate: { type: 'f4', value: dates }, - iChannel0: { type: 'sampler2D', value: texture } + iChannel0: { type: 'sampler2D', value: texture, wrap: 'repeat' } }; // Shader by Kali (https://www.shadertoy.com/view/4dfGDM) @@ -32,43 +32,38 @@ PIXI.StarNestFilter = function(width, height, texture) "uniform sampler2D iChannel0;", "// add any extra uniforms here", - "#define M_PI 3.1415926535897932384626433832795", + "#ifdef GL_ES", + "precision highp float;", + "#endif", - "float rand(vec2 co)", - "{", - "return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);", - "}", + "#define PI 3.1416", "void main(void)", "{", - "float size = 30.0;", - "float prob = 0.95;", + "//map the xy pixel co-ordinates to be between -1.0 to +1.0 on x and y axes", + "//and alter the x value according to the aspect ratio so it isn't 'stretched'", + "vec2 p = (2.0 * gl_FragCoord.xy / iResolution.xy - 1.0)", + "* vec2(iResolution.x / iResolution.y, 1.0);", - "vec2 pos = floor(1.0 / size * gl_FragCoord.xy);", + "//now, this is the usual part that uses the formula for texture mapping a ray-", + "//traced cylinder using the vector p that describes the position of the pixel", + "//from the centre.", + "vec2 uv = vec2(atan(p.y, p.x) * 1.0/PI, 1.0 / sqrt(dot(p, p))) * vec2(2.0, 1.0);", - "float color = 0.0;", - "float starValue = rand(pos);", - "if (starValue > prob)", - "{", - "vec2 center = size * pos + vec2(size, size) * 0.5;", + "//now this just 'warps' the texture read by altering the u coordinate depending on", + "//the val of the v coordinate and the current time", + "uv.x += sin(2.0 * uv.y + iGlobalTime * 0.5);", - "float t = 0.9 + 0.2 * sin(iGlobalTime + (starValue - prob) / (1.0 - prob) * 45.0);", + "vec3 c = texture2D(iChannel0, uv).xyz", - "color = 1.0 - distance(gl_FragCoord.xy, center) / (0.5 * size);", - "color = color * t / (abs(gl_FragCoord.y - center.y)) * t / (abs(gl_FragCoord.x - center.x));", - "}", - "else if (rand(gl_FragCoord.xy / iResolution.xy) > 0.996)", - "{", - "float r = rand(gl_FragCoord.xy);", - "color = r * (0.25 * sin(iGlobalTime * (r * 5.0) + 720.0 * r) + 0.75);", - "}", + "//this divison makes the color value 'darker' into the distance, otherwise", + "//everything will be a uniform brightness and no sense of depth will be present.", + "/ (uv.y * 0.5 + 1.0);", - "gl_FragColor = vec4(vec3(color), 1.0);", + "gl_FragColor = vec4(c, 1.0);", "}"]; - - } PIXI.StarNestFilter.prototype = Object.create( PIXI.AbstractFilter.prototype ); @@ -87,8 +82,7 @@ var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: p function preload() { - // game.load.image('texture', 'wip/64x64.png'); - game.load.image('texture', 'wip/tex08.jpg'); + game.load.image('texture', 'wip/tex00.jpg'); } diff --git a/examples/wip/hueRotationFilter.js b/examples/wip/hueRotationFilter.js new file mode 100644 index 00000000..06cf3f48 --- /dev/null +++ b/examples/wip/hueRotationFilter.js @@ -0,0 +1,118 @@ +PIXI.HueRotationFilter = function(width, height, texture) +{ + PIXI.AbstractFilter.call( this ); + + this.passes = [this]; + + var d = new Date(); + + var dates = [ + d.getFullYear(), // the year (four digits) + d.getMonth(), // the month (from 0-11) + d.getDate(), // the day of the month (from 1-31) + d.getHours()*60.0*60 + d.getMinutes()*60 + d.getSeconds() + ]; + + this.uniforms = { + iResolution: { type: 'f3', value: { x: width, y: height, z: 0 }}, + iGlobalTime: { type: 'f', value: 1 }, + iDate: { type: 'f4', value: dates }, + iChannel0: { type: 'sampler2D', value: texture } + }; + + // Shader by Daniil (https://www.shadertoy.com/view/4sl3DH) + this.fragmentSrc = [ + "precision mediump float;", + "uniform vec3 iResolution;", + "uniform float iGlobalTime;", + "uniform float iChannelTime[4];", + "uniform vec4 iMouse;", + "uniform vec4 iDate;", + "uniform vec3 iChannelResolution[4];", + "uniform sampler2D iChannel0;", + "// add any extra uniforms here", + + "/* Simple hue rotation filter based on article:", + "http://beesbuzz.biz/code/hsv_color_transforms.php", + "*/", + + "#define SPEED 10.0", + + "void main(void)", + "{", + "vec2 uv = gl_FragCoord.xy / iResolution.xy;", + + "float c = cos(iGlobalTime*SPEED);", + "float s = sin(iGlobalTime*SPEED);", + + "mat4 hueRotation =", + "mat4( 0.299, 0.587, 0.114, 0.0,", + "0.299, 0.587, 0.114, 0.0,", + "0.299, 0.587, 0.114, 0.0,", + "0.000, 0.000, 0.000, 1.0) +", + + "mat4( 0.701, -0.587, -0.114, 0.0,", + "-0.299, 0.413, -0.114, 0.0,", + "-0.300, -0.588, 0.886, 0.0,", + "0.000, 0.000, 0.000, 0.0) * c +", + + "mat4( 0.168, 0.330, -0.497, 0.0,", + "-0.328, 0.035, 0.292, 0.0,", + "1.250, -1.050, -0.203, 0.0,", + "0.000, 0.000, 0.000, 0.0) * s;", + + "vec4 pixel = texture2D(iChannel0, uv);", + + "gl_FragColor = pixel * hueRotation;", + + "}"]; + + + +} + +PIXI.HueRotationFilter.prototype = Object.create( PIXI.AbstractFilter.prototype ); +PIXI.HueRotationFilter.prototype.constructor = PIXI.HueRotationFilter; + +Object.defineProperty(PIXI.HueRotationFilter.prototype, 'iGlobalTime', { + get: function() { + return this.uniforms.iGlobalTime.value; + }, + set: function(value) { + this.uniforms.iGlobalTime.value = value; + } +}); + +var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + // game.load.image('texture', 'wip/64x64.png'); + // game.load.image('texture', 'wip/64x64.png'); + game.load.image('texture', 'assets/pics/ra_einstein.png'); + +} + +var filter; +var sprite; + +function create() { + + sprite = game.add.sprite(0, 0, 'texture'); + // sprite.width = 800; + // sprite.height = 600; + + filter = new PIXI.HueRotationFilter(sprite.width, sprite.height, sprite.texture); + + sprite.filters = [filter]; + +} + +function update() { + + filter.iGlobalTime = game.time.totalElapsedSeconds(); + +} + +function render() { +} diff --git a/examples/wip/mengerTunnelFilter.js b/examples/wip/mengerTunnelFilter.js new file mode 100644 index 00000000..cf724865 --- /dev/null +++ b/examples/wip/mengerTunnelFilter.js @@ -0,0 +1,163 @@ +PIXI.MengerTunnelFilter = function(width, height, texture) +{ + PIXI.AbstractFilter.call( this ); + + this.passes = [this]; + + var d = new Date(); + + var dates = [ + d.getFullYear(), // the year (four digits) + d.getMonth(), // the month (from 0-11) + d.getDate(), // the day of the month (from 1-31) + d.getHours()*60.0*60 + d.getMinutes()*60 + d.getSeconds() + ]; + + this.uniforms = { + iResolution: { type: 'f3', value: { x: width, y: height, z: 0 }}, + iGlobalTime: { type: 'f', value: 1 }, + iDate: { type: 'f4', value: dates }, + iChannel0: { type: 'sampler2D', value: texture, wrap: 'repeat' } + }; + + // Shader by fb39ca4 (https://www.shadertoy.com/view/XslGzl) + this.fragmentSrc = [ + "precision mediump float;", + "uniform vec3 iResolution;", + "uniform float iGlobalTime;", + "uniform float iChannelTime[4];", + "uniform vec4 iMouse;", + "uniform vec4 iDate;", + "uniform vec3 iChannelResolution[4];", + "uniform sampler2D iChannel0;", + "// add any extra uniforms here", + + "const int MAX_RAY_STEPS = 64;", + "const float RAY_STOP_TRESHOLD = 0.0001;", + "const int MENGER_ITERATIONS = 5;", + + "float maxcomp(vec2 v) { return max(v.x, v.y); }", + + "float sdCross(vec3 p) {", + "p = abs(p);", + "vec3 d = vec3(max(p.x, p.y),", + "max(p.y, p.z),", + "max(p.z, p.x));", + "return min(d.x, min(d.y, d.z)) - (1.0 / 3.0);", + "}", + + "float sdCrossRep(vec3 p) {", + "vec3 q = mod(p + 1.0, 2.0) - 1.0;", + "return sdCross(q);", + "}", + + "float sdCrossRepScale(vec3 p, float s) {", + "return sdCrossRep(p * s) / s;", + "}", + + "float scene(vec3 p) {", + "float scale = 1.0;", + "float dist = 0.0;", + "for (int i = 0; i < MENGER_ITERATIONS; i++) {", + "dist = max(dist, -sdCrossRepScale(p, scale));", + "scale *= 3.0;", + "}", + "return dist;", + "}", + + "vec3 hsv2rgb(vec3 c)", + "{", + "vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);", + "vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);", + "return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);", + "}", + + "vec4 colorize(float c) {", + + "float hue = mix(0.6, 1.15, min(c * 1.2 - 0.05, 1.0));", + "float sat = 1.0 - pow(c, 4.0);", + "float lum = c;", + "vec3 hsv = vec3(hue, sat, lum);", + "vec3 rgb = hsv2rgb(hsv);", + "return vec4(rgb, 1.0);", + "}", + + + "void main(void)", + "{", + "vec2 screenPos = gl_FragCoord.xy / iResolution.xy * 2.0 - 1.0;", + "vec2 mousePos = iMouse.xy / iResolution.xy * 2.0 - 1.0;", + + "vec3 cameraPos = vec3(0.16 * sin(iGlobalTime), 0.16 * cos(iGlobalTime), iGlobalTime);", + "//vec3 cameraPos = vec3(0.0);", + "vec3 cameraDir = vec3(0.0, 0.0, 1.0);", + "vec3 cameraPlaneU = vec3(1.0, 0.0, 0.0);", + "vec3 cameraPlaneV = vec3(0.0, 1.0, 0.0) * (iResolution.y / iResolution.x);", + + "vec3 rayPos = cameraPos;", + "vec3 rayDir = cameraDir + screenPos.x * cameraPlaneU + screenPos.y * cameraPlaneV;", + + "rayDir = normalize(rayDir);", + + "float dist = scene(rayPos);", + "int stepsTaken;", + "for (int i = 0; i < MAX_RAY_STEPS; i++) {", + "if (dist < RAY_STOP_TRESHOLD) {", + "continue;", + "}", + "rayPos += rayDir * dist;", + "dist = scene(rayPos);", + "stepsTaken = i;", + "}", + + "vec4 color = colorize(pow(float(stepsTaken) / float(MAX_RAY_STEPS), 0.9));", + + "gl_FragColor = color;", + "}"]; + + +} + +PIXI.MengerTunnelFilter.prototype = Object.create( PIXI.AbstractFilter.prototype ); +PIXI.MengerTunnelFilter.prototype.constructor = PIXI.MengerTunnelFilter; + +Object.defineProperty(PIXI.MengerTunnelFilter.prototype, 'iGlobalTime', { + get: function() { + return this.uniforms.iGlobalTime.value; + }, + set: function(value) { + this.uniforms.iGlobalTime.value = value; + } +}); + +var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('texture', 'wip/tex15.png'); + +} + +var filter; +var sprite; + +function create() { + + sprite = game.add.sprite(0, 0, 'texture'); + sprite.width = 800; + sprite.height = 600; + + filter = new PIXI.MengerTunnelFilter(sprite.width, sprite.height, sprite.texture); + + sprite.filters = [filter]; + +} + +function update() { + + filter.iGlobalTime = game.time.totalElapsedSeconds(); + +} + +function render() { +} diff --git a/examples/wip/shadertoy-effect.js b/examples/wip/shadertoy-effect.js new file mode 100644 index 00000000..552b50ed --- /dev/null +++ b/examples/wip/shadertoy-effect.js @@ -0,0 +1,1200 @@ +var vsSource = [ + "attribute vec2 pos;", + "void main()", + "{", + "gl_Position = vec4(pos.x,pos.y,0.0,1.0);", + "}" + ].join("\n"); + + +var fsSource = [ + "void main()", + "{", + "gl_FragColor = vec4(0.0,0.0,0.0,1.0);", + "}" + ].join("\n"); + +//-------------------------------------- + +function createGLTexture( ctx, image, format, texture ) +{ + if( ctx==null ) return; + + ctx.bindTexture( ctx.TEXTURE_2D, texture); + ctx.pixelStorei( ctx.UNPACK_FLIP_Y_WEBGL, false ); + ctx.texImage2D( ctx.TEXTURE_2D, 0, format, ctx.RGBA, ctx.UNSIGNED_BYTE, image); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_LINEAR); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.REPEAT); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.REPEAT); + ctx.generateMipmap(ctx.TEXTURE_2D); + ctx.bindTexture(ctx.TEXTURE_2D, null); +} + +function createGLTextureLinear( ctx, image, texture ) +{ + if( ctx==null ) return; + + ctx.bindTexture( ctx.TEXTURE_2D, texture); + ctx.pixelStorei( ctx.UNPACK_FLIP_Y_WEBGL, false ); + ctx.texImage2D( ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); + ctx.bindTexture(ctx.TEXTURE_2D, null); +} + + +function createGLTextureNearestRepeat( ctx, image, texture ) +{ + if( ctx==null ) return; + + ctx.bindTexture(ctx.TEXTURE_2D, texture); + ctx.pixelStorei( ctx.UNPACK_FLIP_Y_WEBGL, false ); + ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST); + ctx.bindTexture(ctx.TEXTURE_2D, null); +} + +function createGLTextureNearest( ctx, image, texture ) +{ + if( ctx==null ) return; + + ctx.bindTexture(ctx.TEXTURE_2D, texture); + ctx.pixelStorei( ctx.UNPACK_FLIP_Y_WEBGL, false ); + ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); + ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); + + ctx.bindTexture(ctx.TEXTURE_2D, null); +} + +function createAudioTexture( ctx, texture ) +{ + if( ctx==null ) return; + + ctx.bindTexture( ctx.TEXTURE_2D, texture ); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR ); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR ); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE ); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE) ; + ctx.texImage2D( ctx.TEXTURE_2D, 0, ctx.LUMINANCE, 512, 2, 0, ctx.LUMINANCE, ctx.UNSIGNED_BYTE, null); + ctx.bindTexture( ctx.TEXTURE_2D, null); +} + +function createKeyboardTexture( ctx, texture ) +{ + if( ctx==null ) return; + + ctx.bindTexture( ctx.TEXTURE_2D, texture ); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST ); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST ); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE ); + ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE) ; + ctx.texImage2D( ctx.TEXTURE_2D, 0, ctx.LUMINANCE, 256, 2, 0, ctx.LUMINANCE, ctx.UNSIGNED_BYTE, null); + ctx.bindTexture( ctx.TEXTURE_2D, null); +} + + +function Effect( ac, gl, xres, yres, callback, obj, forceMuted, forcePaused) +{ + this.mAudioContext = ac; + this.mNoAudioMessageShowed = false; + this.mGLContext = gl; + this.mQuadVBO = null; + this.mProgram = null; + this.mXres = xres; + this.mYres = yres; + this.mInputs = new Array(4); + this.mInputs[0] = null; + this.mInputs[1] = null; + this.mInputs[2] = null; + this.mInputs[3] = null; + this.mTextureCallbackFun = callback; + this.mTextureCallbackObj = obj; + this.mSource = null; + this.mForceMuted = forceMuted; + this.mForcePaused = forcePaused; + this.mSupportsDerivatives = false; + + //------------- + if( gl==null ) return; + + var ext = gl.getExtension('OES_standard_derivatives'); + this.mSupportsDerivatives = (ext != null); + + if( this.mSupportsDerivatives ) + { + gl.hint( ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.NICEST ); + } + + var ext2 = gl.getExtension('OES_texture_float'); + this.mSupportTextureFloat = (ext2 != null ); + + var vertices = new Float32Array( [ -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0] ); + + this.mQuadVBO = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, this.mQuadVBO); + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); + + var res = this.NewShader(fsSource); + + this.DetermineShaderPrecission(); + + this.MakeHeader(); +} + +Effect.prototype.DestroyInput = function( id ) +{ + if( this.mInputs[id]==null ) return; + if( this.mGLContext== null ) return; + + var gl = this.mGLContext; + if( this.mInputs[id].mInfo.mType=="texture" ) + { + gl.deleteTexture( this.mInputs[id].globject ); + } + else if( this.mInputs[id].mInfo.mType=="slideshow" ) + { + gl.deleteTexture( this.mInputs[id].globject ); + } + else if( this.mInputs[id].mInfo.mType=="webcam" ) + { + gl.deleteTexture( this.mInputs[id].globject ); + } + else if( this.mInputs[id].mInfo.mType=="video" ) + { + this.mInputs[id].video.pause(); + this.mInputs[id].video = null; + gl.deleteTexture( this.mInputs[id].globject ); + } + else if( this.mInputs[id].mInfo.mType=="music" ) + { + this.mInputs[id].audio.pause(); + this.mInputs[id].audio = null; + gl.deleteTexture( this.mInputs[id].globject ); + } + else if( this.mInputs[id].mInfo.mType=="cubemap" ) + { + gl.deleteTexture( this.mInputs[id].globject ); + } + else if( this.mInputs[id].mInfo.mType=="keyboard" ) + { + gl.deleteTexture( this.mInputs[id].globject ); + } + + this.mInputs[id] = null; +} + + + +Effect.prototype.NewTexture = function( slot, url ) +{ + var me = this; + var gl = this.mGLContext; + + var texture = null; + + if (url!=null && url.mType=="webcam" && this.mForceMuted) + { + url.mType = "texture"; + } + + if( url==null ) + { + if( me.mTextureCallbackFun!=null ) + me.mTextureCallbackFun( this.mTextureCallbackObj, slot, null, false, true, 0, -1.0 ); + return false; + } + else if( url.mType=="texture" ) + { + texture = {}; + texture.mInfo = url; + texture.globject = (gl!=null) ? gl.createTexture() : null; + texture.loaded = false; + texture.image = new Image(); + texture.image.crossOrigin = ''; + texture.image.onload = function() + { + var format = gl.RGBA; + if( url.mSrc=="/presets/tex15.png" || url.mSrc=="/presets/tex17.png" ) + format = gl.LUMINANCE; + + if( url.mSrc=="/presets/tex14.png" ) + createGLTextureNearest( gl, texture.image, texture.globject ); + else if( url.mSrc=="/presets/tex15.png" ) + createGLTextureNearestRepeat( gl, texture.image, texture.globject ); + else + createGLTexture( gl, texture.image, format, texture.globject ); + + texture.loaded = true; + if( me.mTextureCallbackFun!=null ) + me.mTextureCallbackFun( me.mTextureCallbackObj, slot, texture.image, true, true, 0, -1.0 ); + } + texture.image.src = url.mSrc; + } + else if( url.mType=="slideshow" ) + { + texture = {}; + texture.mInfo = url; + texture.globject = (gl!=null) ? gl.createTexture() : null; + texture.loaded = false; + texture.image = new Image(); + texture.image.crossOrigin = ''; + texture.image.onload = function() + { + createGLTexture( gl, texture.image, gl.RGBA, texture.globject ); + texture.loaded = true; + if( me.mTextureCallbackFun!=null ) + me.mTextureCallbackFun( me.mTextureCallbackObj, slot, texture.image, true, true, 3, -1.0 ); + } + texture.slideshow = {}; + texture.slideshow.mCurrentSlide = 0; + texture.slideshow.mNewTextureReady = false; + var urlSlide = url.mSrc.replace("??","00"); + texture.image.src = urlSlide; + } + else if( url.mType=="cubemap" ) + { + texture = {}; + texture.mInfo = url; + texture.globject = (gl!=null) ? gl.createTexture() : null; + texture.loaded = false; + texture.image = [ new Image(), new Image(), new Image(), new Image(), new Image(), new Image() ]; + + gl.bindTexture( gl.TEXTURE_CUBE_MAP, texture.globject ); + gl.texParameteri( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR ); + gl.texParameteri( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR ); + gl.bindTexture( gl.TEXTURE_CUBE_MAP, null ); + + texture.loaded = true; + + for( var i=0; i<6; i++ ) + { + texture.image[i].mId = i; + texture.image[i].crossOrigin = ''; + texture.image[i].onload = function() + { + var id = this.mId; + gl.bindTexture( gl.TEXTURE_CUBE_MAP, texture.globject ); + gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, false ); + gl.texImage2D( gl.TEXTURE_CUBE_MAP_POSITIVE_X + id, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image[id] ); + gl.bindTexture( gl.TEXTURE_CUBE_MAP, null ); + if( me.mTextureCallbackFun!=null ) + me.mTextureCallbackFun( me.mTextureCallbackObj, slot, texture.image[0], true, true, 0, -1.0 ); + } + + texture.image[i].src = url.mSrc.replace( "_0.", "_" + i + "." ); + } + } + else if( url.mType=="webcam" ) + { + texture = {}; + texture.mInfo = url; + texture.globject = null; + texture.loaded = false; + + texture.video = document.createElement('video'); + texture.video.width = 320; + texture.video.height = 240; + texture.video.autoplay = true; + texture.video.loop = true; + texture.video.paused = true; + + navigator.getUserMedia( { "video": true, "audio": false }, + function(stream) + { + texture.video.src = window.URL.createObjectURL(stream); + + texture.globject = gl.createTexture(); + try + { + createGLTextureLinear( gl, texture.video, texture.globject ); + texture.loaded = true; + } + catch(e) + { + alert( 'Your browser can not transfer webcam data to the GPU.'); + } + }, + function(error) + { + alert( 'Unable to capture WebCam. Please reload the page.' ); + } ); + } + else if( url.mType=="video" ) + { + texture = {}; + texture.mInfo = url; + texture.globject = null; + texture.loaded = false; + texture.video = document.createElement('video'); + texture.video.width = 256; + texture.video.height = 256; + texture.video.loop = true; + texture.video.paused = true;//this.mForcePaused; + texture.video.mPaused = true;//this.mForcePaused; + texture.video.mMuted = this.mForceMuted; + texture.video.muted = this.mForceMuted; + if( this.mForceMuted==true ) + texture.video.volume = 0; + texture.video.autoplay = false; + texture.video.hasFalled = false; + + texture.video.addEventListener( "canplay", function(e) + { + texture.video.play(); + texture.video.paused = false; + texture.video.mPaused = false; + + texture.globject = gl.createTexture(); + createGLTextureLinear( gl, texture.video, texture.globject ); + texture.loaded = true; + + if( me.mTextureCallbackFun!=null ) + me.mTextureCallbackFun( me.mTextureCallbackObj, slot, texture.video, true, true, 1, -1.0 ); + + } ); + + texture.video.addEventListener( "error", function(e) + { + if( texture.video.hasFalled==true ) { alert("Error: cannot load video" ); return; } + var str = texture.video.src; + str = str.substr(0,str.lastIndexOf('.') ) + ".mp4"; + texture.video.src = str; + texture.video.hasFalled = true; + } ); + + + texture.video.src = url.mSrc; + } + else if( url.mType=="music" ) + { + texture = {}; + texture.mInfo = url; + texture.globject = null; + texture.loaded = false; + texture.audio = document.createElement('audio'); + texture.audio.loop = true; + texture.audio.mMuted = this.mForceMuted; + texture.audio.mForceMuted = this.mForceMuted; + + texture.audio.muted = this.mForceMuted; + if( this.mForceMuted==true ) + texture.audio.volume = 0; + texture.audio.autoplay = true; + texture.audio.hasFalled = false; + texture.audio.paused = true; + texture.audio.mPaused = true; + texture.audio.mSound = {}; + + if( this.mForceMuted ) + { + texture.globject = gl.createTexture(); + createAudioTexture( gl, texture.globject ); + var num = 512; + texture.audio.mSound.mFreqData = new Uint8Array( num ); + texture.audio.mSound.mWaveData = new Uint8Array( num ); + texture.loaded = true; + texture.audio.paused = false; + texture.audio.mPaused = false; + } + + texture.audio.addEventListener( "canplay", function() + { + if( this.mForceMuted ) return; + + texture.globject = gl.createTexture(); + createAudioTexture( gl, texture.globject ); + + if( me.mAudioContext != null ) + { + var ctx = me.mAudioContext; + texture.audio.mSound.mSource = ctx.createMediaElementSource( texture.audio ); + texture.audio.mSound.mAnalyser = ctx.createAnalyser(); + texture.audio.mSound.mGain = ctx.createGain(); + + texture.audio.mSound.mSource.connect( texture.audio.mSound.mAnalyser ); + texture.audio.mSound.mAnalyser.connect( texture.audio.mSound.mGain ); + texture.audio.mSound.mGain.connect( ctx.destination ); + + texture.audio.mSound.mFreqData = new Uint8Array( texture.audio.mSound.mAnalyser.frequencyBinCount ); + texture.audio.mSound.mWaveData = new Uint8Array( texture.audio.mSound.mAnalyser.frequencyBinCount ); + + texture.loaded = true; + texture.audio.paused = false; + texture.audio.mPaused = false; + } + else + { + if( me.mNoAudioMessageShowed==false ) + { + var ve = document.getElementById( "centerScreen" ); + doAlert( getCoords(ve), {mX:420,mY:160}, "Error", "Your browser does not support WebAudio.

This shader will not work as the author intended. Please consider using a WebAudio-friendly browser (Chrome).", false, null ); + me.mNoAudioMessageShowed = true; + } + } + } ); + + texture.audio.addEventListener( "error", function(e) + { + if( this.mForceMuted ) return; + + if( texture.audio.hasFalled==true ) { /*alert("Error: cannot load music" ); */return; } + var str = texture.audio.src; + str = str.substr(0,str.lastIndexOf('.') ) + ".ogg"; + texture.audio.src = str; + texture.audio.hasFalled = true; + } ); + + if( !this.mForceMuted ) + { + texture.audio.src = url.mSrc; + } + + + if( me.mTextureCallbackFun!=null ) + me.mTextureCallbackFun( me.mTextureCallbackObj, slot, null, false, true, 2, -1.0 ); + } + else if( url.mType=="keyboard" ) + { + texture = {}; + texture.mInfo = url; + texture.globject = gl.createTexture(); + texture.loaded = true; + + texture.keyboard = {}; + + texture.keyboard.mImage = new Image(); + texture.keyboard.mImage.onload = function() + { + texture.loaded = true; + if( me.mTextureCallbackFun!=null ) + me.mTextureCallbackFun( me.mTextureCallbackObj, slot, {mImage:texture.keyboard.mImage,mData:texture.keyboard.mData}, false, false, 4, -1.0 ); + } + texture.keyboard.mImage.src = "/img/keyboard.png"; + + + texture.keyboard.mNewTextureReady = true; + texture.keyboard.mData = new Uint8Array( 256*2 ); + + createKeyboardTexture( gl, texture.globject ); + + for( var j=0; j<(256*2); j++ ) + { + texture.keyboard.mData[j] = 0; + } + + if( me.mTextureCallbackFun!=null ) + me.mTextureCallbackFun( me.mTextureCallbackObj, slot, {mImage:texture.keyboard.mImage,mData:texture.keyboard.mData}, false, false, 4, -1.0 ); + } + else if( url.mType==null ) + { + if( me.mTextureCallbackFun!=null ) + me.mTextureCallbackFun( this.mTextureCallbackObj, slot, null, false, true, 0, -1.0 ); + } + else + { + alert( "texture type error" ); + return; + } + + this.DestroyInput( slot ); + this.mInputs[slot] = texture; + + this.MakeHeader(); +} + +Effect.prototype.SetKeyDown = function( k ) +{ + for( var i=0; i1 ) + { + return { mFailed : true, mError : "ShaderToy only supports one-pass shaders at this momment", mShader:null }; + } + for( var j=0; j x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);", + "vec4 x12 = x0.xyxy + C.xxzz;", + "x12.xy -= i1;", + + "i = mod289(i); // Avoid truncation effects in permutation", + "vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))", + "+ i.x + vec3(0.0, i1.x, 1.0 ));", + + "vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);", + "m = m*m ;", + "m = m*m ;", + + "vec3 x = 2.0 * fract(p * C.www) - 1.0;", + "vec3 h = abs(x) - 0.5;", + "vec3 ox = floor(x + 0.5);", + "vec3 a0 = x - ox;", + + "m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );", + + "vec3 g;", + "g.x = a0.x * x0.x + h.x * x0.y;", + "g.yz = a0.yz * x12.xz + h.yz * x12.yw;", + + "return 130.0 * dot(m, g);", + "}", + + "float fbm(vec2 p) {", + "float f = 0.0;", + "float w = 0.5;", + "for (int i = 0; i < 5; i ++) {", + "f += w * snoise(p);", + "p *= 2.;", + "w *= 0.5;", + "}", + "return f;", + "}", + + + "vec4 tunneliter(vec2 texCoord,vec4 incol,float cx,float cy,float limita,float limitb,vec4 coloz,float tadd)", + "{", + "vec2 texc;", + "vec2 tex;", + "vec4 outCol;", + "float disty;", + + "texc=(texCoord-vec2(cx,cy));", + "disty=distance(texc,vec2(0.0,0.0));", + "tex.x=(abs(atan(texc.x,texc.y)))/6.2830;", + "tex.y=0.5/disty;", + "tex.y+=(iGlobalTime*0.9)+tadd;", + + "float fbmval=abs(fbm(tex));", + + "float bex=mix(fbmval,1.0,smoothstep(limitb,limita,disty))*smoothstep(limitb,limita,disty);", + "outCol=mix(incol,coloz*(1.0-fbmval),bex);", + + "return outCol;", + "}", + + "void main(void)", + "{", + "vec2 uv = gl_FragCoord.xy / iResolution.xy;", + "gl_FragColor = vec4(uv,0.5+0.5*sin(iGlobalTime),1.0);", + + "vec4 finalCol;", + + "float xa=(sin(iGlobalTime)*0.4)+(sin((iGlobalTime*1.3)+0.5)*0.24);", + "float ya=(cos(iGlobalTime)*0.45)+(cos((iGlobalTime*0.6)-0.7)*0.3);", + + "finalCol=vec4(1.0,0.0,1.0,1.0);", + + "finalCol=tunneliter(uv,vec4(1.0,1.0,1.0,1.0),0.5+(xa*0.80),0.5+(ya*0.80),0.04,0.01,vec4(0.9,0.9,1.0,1.0),3.1);", + "finalCol=tunneliter(uv,finalCol,0.5+(xa*0.90),0.5+(ya*0.70),0.08,0.03,vec4(0.7,0.7,0.8,1.0),7.2);", + "finalCol=tunneliter(uv,finalCol,0.5+(xa*0.70),0.5+(ya*0.70),0.14,0.05,vec4(0.6,0.6,0.7,1.0),9.3);", + "finalCol=tunneliter(uv,finalCol,0.5+(xa*0.58),0.5+(ya*0.58),0.18,0.10,vec4(0.5,0.5,0.6,1.0),4.4);", + "finalCol=tunneliter(uv,finalCol,0.5+(xa*0.35),0.5+(ya*0.35),0.24,0.15,vec4(0.4,0.4,0.5,1.0),2.5);", + "finalCol=tunneliter(uv,finalCol,0.5+(xa*0.22),0.5+(ya*0.22),0.30,0.20,vec4(0.4,0.4,0.5,1.0),9.6);", + "finalCol=tunneliter(uv,finalCol,0.5+(xa*0.15),0.5+(ya*0.15),0.40,0.25,vec4(0.3,0.3,0.4,1.0),6.7);", + "finalCol=tunneliter(uv,finalCol,0.5+(xa*0.12),0.5+(ya*0.12),0.50,0.35,vec4(0.3,0.3,0.4,1.0),3.8);", + "finalCol=tunneliter(uv,finalCol,0.5+(xa*0.10),0.5+(ya*0.10),0.60,0.40,vec4(0.3,0.3,0.4,1.0),7.9);", + + "gl_FragColor = vec4(vec3(finalCol.xyz),1.0);", + + "}"]; + +} + +PIXI.SoftTunnelFilter.prototype = Object.create( PIXI.AbstractFilter.prototype ); +PIXI.SoftTunnelFilter.prototype.constructor = PIXI.SoftTunnelFilter; + +Object.defineProperty(PIXI.SoftTunnelFilter.prototype, 'iGlobalTime', { + get: function() { + return this.uniforms.iGlobalTime.value; + }, + set: function(value) { + this.uniforms.iGlobalTime.value = value; + } +}); + +var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('texture', 'wip/tex15.png'); + +} + +var filter; +var sprite; + +function create() { + + sprite = game.add.sprite(0, 0, 'texture'); + sprite.width = 800; + sprite.height = 600; + + filter = new PIXI.SoftTunnelFilter(sprite.width, sprite.height, sprite.texture); + + sprite.filters = [filter]; + +} + +function update() { + + filter.iGlobalTime = game.time.totalElapsedSeconds(); + +} + +function render() { +} diff --git a/examples/wip/starNurseryFilter.js b/examples/wip/starNurseryFilter.js index 712251a6..dc7699fd 100644 --- a/examples/wip/starNurseryFilter.js +++ b/examples/wip/starNurseryFilter.js @@ -17,7 +17,7 @@ PIXI.StarNurseryFilter = function(width, height, texture) iResolution: { type: 'f3', value: { x: width, y: height, z: 0 }}, iGlobalTime: { type: 'f', value: 1 }, iDate: { type: 'f4', value: dates }, - iChannel0: { type: 'sampler2D', value: texture } + iChannel0: { type: 'sampler2D', value: texture, wrap: 'repeat' } }; // Shader by Dave Hoskins (https://www.shadertoy.com/view/XsfGzH) @@ -206,7 +206,7 @@ var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: p function preload() { // game.load.image('texture', 'wip/64x64.png'); - game.load.image('texture', 'wip/tex16.png'); + game.load.image('texture', 'wip/tex12.png'); } diff --git a/examples/wip/starfieldFilter.js b/examples/wip/starfieldFilter.js index 10c851cb..e1d22f80 100644 --- a/examples/wip/starfieldFilter.js +++ b/examples/wip/starfieldFilter.js @@ -17,7 +17,7 @@ PIXI.StarFieldFilter = function(width, height, texture) iResolution: { type: 'f3', value: { x: width, y: height, z: 0 }}, iGlobalTime: { type: 'f', value: 1 }, iDate: { type: 'f4', value: dates }, - iChannel0: { type: 'sampler2D', value: texture } + iChannel0: { type: 'sampler2D', value: texture, wrap: 'repeat' } }; // Shader by Rebb / TRSI (https://www.shadertoy.com/view/XdX3Wn) @@ -125,8 +125,8 @@ var sprite; function create() { sprite = game.add.sprite(0, 0, 'texture'); - sprite.width = 512; - sprite.height = 512; + sprite.width = 800; + sprite.height = 600; filter = new PIXI.StarFieldFilter(sprite.width, sprite.height, sprite.texture); diff --git a/examples/wip/tunnelFilter.js b/examples/wip/tunnelFilter.js new file mode 100644 index 00000000..4d0340e8 --- /dev/null +++ b/examples/wip/tunnelFilter.js @@ -0,0 +1,157 @@ +PIXI.TunnelFilter = function(width, height, texture) +{ + PIXI.AbstractFilter.call( this ); + + this.passes = [this]; + + var d = new Date(); + + var dates = [ + d.getFullYear(), // the year (four digits) + d.getMonth(), // the month (from 0-11) + d.getDate(), // the day of the month (from 1-31) + d.getHours()*60.0*60 + d.getMinutes()*60 + d.getSeconds() + ]; + + this.uniforms = { + iResolution: { type: 'f3', value: { x: width, y: height, z: 0 }}, + iGlobalTime: { type: 'f', value: 1 }, + iDate: { type: 'f4', value: dates }, + iChannel0: { type: 'sampler2D', value: texture, wrap: 'nearest-repeat' } + }; + + // Shader by reiska (https://www.shadertoy.com/view/4sX3z7) + this.fragmentSrc = [ + "precision mediump float;", + "uniform vec3 iResolution;", + "uniform float iGlobalTime;", + "uniform float iChannelTime[4];", + "uniform vec4 iMouse;", + "uniform vec4 iDate;", + "uniform vec3 iChannelResolution[4];", + "uniform sampler2D iChannel0;", + "// add any extra uniforms here", + + "void main(void)", + "{", + "float cameraPinch = 1.0; // values between 0 - 2, this will modify (pinch) the view", + "float cameraZPinch = 1.0; //", + "float cameraZFactor = 1.0; // 0-1", + "float zoomFactor = 1.0; // large values will create a kaleidoscopic effect!", + + "float texCoordUScale = 0.125;", + "float texCoordVScale = 1.0;", + + "float texCoordUMoveSpeed = 0.20;", + "float texCoordVMoveSpeed = -0.125;", + + "float cameraRotationSpeed = 0.5; // 0.0 to switch off rotation (look straight ahead)", + + "float tunnelPinch = 2.0; // 1.0 = round tunnel, change the value to modify the shape", + + "float spikeCount = 5.0;", + "float spikeFactor = sin(iGlobalTime) * 0.1; // 0.0 to switch off spikes", + + "vec3 fogColor = vec3(0.0, 0.0, 0.0);", + "float fogPower = 10.0;", + + "vec2 coord = 2.0 * ((gl_FragCoord.xy / iResolution.xy) - vec2(0.5, 0.5));", + + "float aspectRatio = iResolution.x / iResolution.y;", + + "coord.x *= aspectRatio;", + "coord *= zoomFactor;", + + "coord = vec2(sign(coord.x) * pow(abs(coord.x), cameraPinch), sign(coord.y) * pow(abs(coord.y), cameraPinch));", + + "// camera angles", + "float camAng = iGlobalTime * cameraRotationSpeed;", + + "// camera rotation vectors", + "vec3 cx = vec3(cos(camAng), 0.0, -sin(camAng));", + "vec3 cy = vec3(0.0, 1.0, 0.0);", + "vec3 cz = vec3(sin(camAng), 0.0, cos(camAng));", + + "mat3 cameraRot =", + "mat3(", + "cx.x, cx.y, cx.z,", + "cy.x, cy.y, cy.z,", + "cz.x, cz.y, cz.z);", + + "vec3 cameraDir = normalize(vec3(sin(coord.x), sin(coord.y), cos(coord.x) * cos(coord.y)));", + + "cameraDir = cameraRot * cameraDir;", + + "float angle = atan(cameraDir.x, cameraDir.y);", + "cameraDir.z *= 1.0 + sin(angle * spikeCount) * spikeFactor;", + + "cameraDir.z = cameraZFactor * sign(cameraDir.z) * pow(abs(cameraDir.z), cameraZPinch);", + + + "vec3 cameraOrigin = vec3(0.0, 0.0, 0.0);", + + "float l = sqrt(pow(cameraDir.x * cameraDir.x, tunnelPinch) + pow(cameraDir.y * cameraDir.y, tunnelPinch));", + "float d = 1.0 / l;", + + "vec3 hitPos = cameraOrigin + cameraDir * d;", + + + "vec2 uv = vec2(hitPos.z, angle / 3.14159);", + "uv.x = uv.x * texCoordUScale + iGlobalTime * texCoordUMoveSpeed;", + "uv.y = uv.y * texCoordVScale + iGlobalTime * texCoordVMoveSpeed;", + "vec3 color = texture2D(iChannel0, uv).rgb;", + + "float alpha = 1.0 - pow(min(1.0, abs(cameraDir.z)), fogPower);", + + "color = fogColor * (1.0 - alpha) + color * alpha;", + + "gl_FragColor = vec4(color, 1.0);", + "}"]; + + + +} + +PIXI.TunnelFilter.prototype = Object.create( PIXI.AbstractFilter.prototype ); +PIXI.TunnelFilter.prototype.constructor = PIXI.TunnelFilter; + +Object.defineProperty(PIXI.TunnelFilter.prototype, 'iGlobalTime', { + get: function() { + return this.uniforms.iGlobalTime.value; + }, + set: function(value) { + this.uniforms.iGlobalTime.value = value; + } +}); + +var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('texture', 'wip/tex15.png'); + +} + +var filter; +var sprite; + +function create() { + + sprite = game.add.sprite(0, 0, 'texture'); + sprite.width = 800; + sprite.height = 600; + + filter = new PIXI.TunnelFilter(sprite.width, sprite.height, sprite.texture); + + sprite.filters = [filter]; + +} + +function update() { + + filter.iGlobalTime = game.time.totalElapsedSeconds(); + +} + +function render() { +} diff --git a/examples/wip/vortexFilter.js b/examples/wip/vortexFilter.js new file mode 100644 index 00000000..e8806816 --- /dev/null +++ b/examples/wip/vortexFilter.js @@ -0,0 +1,111 @@ +PIXI.VortexFilter = function(width, height, texture) +{ + PIXI.AbstractFilter.call( this ); + + this.passes = [this]; + + var d = new Date(); + + var dates = [ + d.getFullYear(), // the year (four digits) + d.getMonth(), // the month (from 0-11) + d.getDate(), // the day of the month (from 1-31) + d.getHours()*60.0*60 + d.getMinutes()*60 + d.getSeconds() + ]; + + this.uniforms = { + iResolution: { type: 'f3', value: { x: width, y: height, z: 0 }}, + iGlobalTime: { type: 'f', value: 1 }, + iDate: { type: 'f4', value: dates }, + iChannel0: { type: 'sampler2D', value: texture, wrap: 'repeat' } + }; + + // Shader by GhettoWolf (https://www.shadertoy.com/view/Xdl3WH) + this.fragmentSrc = [ + "precision mediump float;", + "uniform vec3 iResolution;", + "uniform float iGlobalTime;", + "uniform float iChannelTime[4];", + "uniform vec4 iMouse;", + "uniform vec4 iDate;", + "uniform vec3 iChannelResolution[4];", + "uniform sampler2D iChannel0;", + "// add any extra uniforms here", + + "#ifdef GL_ES", + "precision highp float;", + "#endif", + + "#define PI 3.1416", + + "void main(void)", + "{", + "//map the xy pixel co-ordinates to be between -1.0 to +1.0 on x and y axes", + "//and alter the x value according to the aspect ratio so it isn't 'stretched'", + "vec2 p = (2.0 * gl_FragCoord.xy / iResolution.xy - 1.0)", + "* vec2(iResolution.x / iResolution.y, 1.0);", + + "//now, this is the usual part that uses the formula for texture mapping a ray-", + "//traced cylinder using the vector p that describes the position of the pixel", + "//from the centre.", + "vec2 uv = vec2(atan(p.y, p.x) * 1.0/PI, 1.0 / sqrt(dot(p, p))) * vec2(2.0, 1.0);", + + + "//now this just 'warps' the texture read by altering the u coordinate depending on", + "//the val of the v coordinate and the current time", + "uv.x += sin(2.0 * uv.y + iGlobalTime * 0.5);", + + "vec3 c = texture2D(iChannel0, uv).xyz", + + "//this divison makes the color value 'darker' into the distance, otherwise", + "//everything will be a uniform brightness and no sense of depth will be present.", + "/ (uv.y * 0.5 + 1.0);", + + "gl_FragColor = vec4(c, 1.0);", + "}"]; + +} + +PIXI.VortexFilter.prototype = Object.create( PIXI.AbstractFilter.prototype ); +PIXI.VortexFilter.prototype.constructor = PIXI.VortexFilter; + +Object.defineProperty(PIXI.VortexFilter.prototype, 'iGlobalTime', { + get: function() { + return this.uniforms.iGlobalTime.value; + }, + set: function(value) { + this.uniforms.iGlobalTime.value = value; + } +}); + +var game = new Phaser.Game(800, 600, Phaser.AUTO, 'phaser-example', { preload: preload, create: create, update: update, render: render }); + +function preload() { + + game.load.image('texture', 'wip/tex00.jpg'); + +} + +var filter; +var sprite; + +function create() { + + sprite = game.add.sprite(0, 0, 'texture'); + sprite.width = 800; + sprite.height = 600; + + filter = new PIXI.VortexFilter(sprite.width, sprite.height, sprite.texture); + + sprite.filters = [filter]; + +} + +function update() { + + filter.iGlobalTime = game.time.totalElapsedSeconds(); + +} + +function render() { +} diff --git a/src/pixi/renderers/webgl/PixiShader.js b/src/pixi/renderers/webgl/PixiShader.js index c729238b..769edaaf 100644 --- a/src/pixi/renderers/webgl/PixiShader.js +++ b/src/pixi/renderers/webgl/PixiShader.js @@ -107,22 +107,18 @@ PIXI.PixiShader.prototype.syncUniforms = function() } if(type == "f2") { - // console.log(this.program[key]) gl.uniform2f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y); } else if(type == "f3") { - // console.log(this.uniforms[key].value) gl.uniform3f(this.uniforms[key].uniformLocation, this.uniforms[key].value.x, this.uniforms[key].value.y, this.uniforms[key].value.z); } else if(type == "f3v") { - // console.log(this.uniforms[key].value) gl.uniform3fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); } else if(type == "f4") { - // console.log(this.uniforms[key].value) gl.uniform4fv(this.uniforms[key].uniformLocation, this.uniforms[key].value); } else if(type == "mat4") @@ -131,13 +127,50 @@ PIXI.PixiShader.prototype.syncUniforms = function() } else if(type == "sampler2D") { - // first texture... - var texture = this.uniforms[key].value; - - gl.activeTexture(gl.TEXTURE1); - gl.bindTexture(gl.TEXTURE_2D, texture.baseTexture._glTexture); - - gl.uniform1i(this.uniforms[key].uniformLocation, 1); + var texture = this.uniforms[key].value.baseTexture._glTexture; + var image = this.uniforms[key].value.baseTexture.source; + var format = gl.RGBA; + + if (this.uniforms[key].format && this.uniforms[key].format == 'luminance') + { + format = gl.LUMINANCE; + } + + gl.activeTexture(gl.TEXTURE1); + + if (this.uniforms[key].wrap) + { + if (this.uniforms[key].wrap == 'no-repeat' || this.uniforms[key].wrap === false) + { + this.createGLTextureLinear(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'repeat' || this.uniforms[key].wrap === true) + { + this.createGLTexture(gl, image, format, texture); + } + else if (this.uniforms[key].wrap == 'nearest-repeat') + { + this.createGLTextureNearestRepeat(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'nearest') + { + this.createGLTextureNearest(gl, image, texture); + } + else if (this.uniforms[key].wrap == 'audio') + { + this.createAudioTexture(gl, texture); + } + else if (this.uniforms[key].wrap == 'keyboard') + { + this.createKeyboardTexture(gl, texture); + } + } + else + { + this.createGLTextureLinear(gl, image, texture); + } + + gl.uniform1i(this.uniforms[key].uniformLocation, 1); // activate texture.. // gl.uniformMatrix4fv(this.program[key], false, this.uniforms[key].value); @@ -145,6 +178,71 @@ PIXI.PixiShader.prototype.syncUniforms = function() } } +}; + +PIXI.PixiShader.prototype.createGLTexture = function(gl, image, format, texture) +{ + gl.bindTexture( gl.TEXTURE_2D, texture); + gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D( gl.TEXTURE_2D, 0, format, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); + gl.generateMipmap(gl.TEXTURE_2D); +} + +PIXI.PixiShader.prototype.createGLTextureLinear = function(gl, image, texture) +{ + gl.bindTexture( gl.TEXTURE_2D, texture); + gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D( gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); +} + +PIXI.PixiShader.prototype.createGLTextureNearestRepeat = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT); +} + +PIXI.PixiShader.prototype.createGLTextureNearest = function(gl, image, texture) +{ + gl.bindTexture(gl.TEXTURE_2D, texture); + gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false); + gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); + gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); +} + +PIXI.PixiShader.prototype.createAudioTexture = function(gl, texture) +{ + gl.bindTexture( gl.TEXTURE_2D, texture ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) ; + gl.texImage2D( gl.TEXTURE_2D, 0, gl.LUMINANCE, 512, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); +} + +PIXI.PixiShader.prototype.createKeyboardTexture = function(gl, texture) +{ + gl.bindTexture( gl.TEXTURE_2D, texture ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE ); + gl.texParameteri( gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE) ; + gl.texImage2D( gl.TEXTURE_2D, 0, gl.LUMINANCE, 256, 2, 0, gl.LUMINANCE, gl.UNSIGNED_BYTE, null); } PIXI.PixiShader.defaultVertexSrc = [