diff --git a/README.md b/README.md index 9910a25..e26a04f 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,7 @@ Full documentation is in progress at the [wiki](https://github.com/brianchirls/S - Color Generator - [Color Cube](http://www.youtube.com/watch?v=rfQ8rKGTVlg&t=24m30s) - Color Select +- Crop - [Daltonize](http://www.daltonize.org/p/about.html) - Directional Blur - Displacement Map @@ -59,6 +60,7 @@ Full documentation is in progress at the [wiki](https://github.com/brianchirls/S - Mirror - Night Vision - Panorama +- Pixelate - Polar Coordinates - Ripple - Scanlines diff --git a/effects/seriously.blend.js b/effects/seriously.blend.js index f0db0b8..d6ed228 100644 --- a/effects/seriously.blend.js +++ b/effects/seriously.blend.js @@ -83,6 +83,7 @@ nativeBlendModes = { normal: ['FUNC_ADD', 'SRC_ALPHA', 'ONE_MINUS_SRC_ALPHA', 'SRC_ALPHA', 'DST_ALPHA']/*, add: ['FUNC_ADD', 'SRC_ALPHA', 'ONE_MINUS_SRC_ALPHA', 'SRC_ALPHA', 'DST_ALPHA']*/ + //todo: multiply, screen }, identity = new Float32Array([ 1, 0, 0, 0, diff --git a/effects/seriously.blur.js b/effects/seriously.blur.js index 60492f1..10142e6 100644 --- a/effects/seriously.blur.js +++ b/effects/seriously.blur.js @@ -46,13 +46,7 @@ http://v002.info/plugins/v002-blurs/ inputScale: 1, resolution: [this.width, this.height], transform: identity, - direction: null, - projection: new Float32Array([ - 1, 0, 0, 0, - 0, 1, 0, 0, - 0, 0, 1, 0, - 0, 0, 0, 1 - ]) + direction: null }; return { @@ -90,16 +84,16 @@ http://v002.info/plugins/v002-blurs/ 'attribute vec2 texCoord;', 'uniform vec2 resolution;', - 'uniform mat4 projection;', 'uniform mat4 transform;', - 'varying vec2 vTexCoord;', - 'uniform vec2 direction;', 'uniform float amount;', 'uniform float inputScale;', 'const vec2 zero = vec2(0.0, 0.0);', + + 'varying vec2 vTexCoord;', + '#ifdef USE_VARYINGS', 'vec2 one;', 'vec2 amount1;', @@ -131,7 +125,7 @@ http://v002.info/plugins/v002-blurs/ ' if (inputScale < 1.0) {', ' one -= 1.0 / resolution;', ' }', - //' one *= inputScale;', + ' vTexCoord = max(zero, min(one, texCoord.st * inputScale));', ' amount1 = direction * (inputScale * amount * 5.0 / resolution);', @@ -162,9 +156,6 @@ http://v002.info/plugins/v002-blurs/ 'varying vec2 vTexCoord;', 'uniform sampler2D source;', - 'uniform float angle;', - 'uniform float amount;', - 'uniform float inputScale;', '#ifdef USE_VARYINGS', 'varying vec2 vTexCoord1;', @@ -235,14 +226,13 @@ http://v002.info/plugins/v002-blurs/ //vertical pass uniforms.direction = vertical; - uniforms.source = fbVertical.texture; + uniforms.source = fbHorizontal.texture; parent(shader, model, uniforms, frameBuffer); return; } loopUniforms.amount = amount; loopUniforms.source = this.inputs.source.texture; - loopUniforms.projection[0] = this.height / this.width; for (i = 0; i < passes.length; i++) { pass = Math.min(1, passes[i] / amount); diff --git a/effects/seriously.chroma.js b/effects/seriously.chroma.js index 6f6945c..3d09481 100644 --- a/effects/seriously.chroma.js +++ b/effects/seriously.chroma.js @@ -17,15 +17,13 @@ }(this, function (Seriously) { 'use strict'; - /* experimental chroma key algorithm - todo: see if we can minimize branching - todo: calculate HSL of screen color outside shader + /* + experimental chroma key algorithm todo: try allowing some color despill on opaque pixels todo: add different modes? - todo: rename parameters */ + Seriously.plugin('chroma', { - commonShader: true, shader: function (inputs, shaderSource) { shaderSource.vertex = [ 'precision mediump float;', @@ -44,12 +42,10 @@ 'varying vec3 screenPrimary;', 'void main(void) {', - ' float fmin = min(min(screen.r, screen.g), screen.b); //Min. value of RGB', - ' float fmax = max(max(screen.r, screen.g), screen.b); //Max. value of RGB', + ' float fmin = min(min(screen.r, screen.g), screen.b);', //Min. value of RGB + ' float fmax = max(max(screen.r, screen.g), screen.b);', //Max. value of RGB ' float secondaryComponents;', - //' luminance = (fmax + fmin) / 2.0; // Luminance', - //' screenSat = fmax - fmin; // Saturation', ' screenPrimary = step(fmax, screen.rgb);', ' secondaryComponents = dot(1.0 - screenPrimary, screen.rgb);', ' screenSat = fmax - mix(secondaryComponents - fmin, secondaryComponents / 2.0, balance);', @@ -66,6 +62,7 @@ '}' ].join('\n'); shaderSource.fragment = [ + this.inputs.mask ? '#define MASK' : '', 'precision mediump float;', 'varying vec2 vTexCoord;', @@ -81,52 +78,51 @@ 'varying float screenSat;', 'varying vec3 screenPrimary;', - 'vec4 sourcePixel;', + 'void main(void) {', + ' float pixelSat, secondaryComponents;', + ' vec4 sourcePixel = texture2D(source, vTexCoord);', - 'const mat3 yuv = mat3(', - ' 54.213, 182.376, 18.411,', - ' -54.213, -182.376, 236.589,', - ' 200.787, -182.376, -18.411', - ');', + ' float fmin = min(min(sourcePixel.r, sourcePixel.g), sourcePixel.b);', //Min. value of RGB + ' float fmax = max(max(sourcePixel.r, sourcePixel.g), sourcePixel.b);', //Max. value of RGB + // luminance = fmax - 'float round(float n) {', - ' return floor(n) + step(0.5, fract(n));', - '}', + ' vec3 pixelPrimary = step(fmax, sourcePixel.rgb);', - 'void main(void) {', - ' float pixelSat, luminance, secondaryComponents;', - ' vec3 pixelPrimary;', - ' vec4 pixel = vec4(0.0);', - ' sourcePixel = texture2D(source, vTexCoord);', - - ' float fmin = min(min(sourcePixel.r, sourcePixel.g), sourcePixel.b); //Min. value of RGB', - ' float fmax = max(max(sourcePixel.r, sourcePixel.g), sourcePixel.b); //Max. value of RGB', - //' float delta = fmax - fmin; //Delta RGB value', - - //' luminance = (fmax + fmin) / 2.0; // Luminance', - //' luminance = dot(vec3(0.3, 0.59, 0.11), sourcePixel.rgb); // Luminance', - ' luminance = fmax; // Luminance', - ' pixelPrimary = step(fmax, sourcePixel.rgb);', - //' pixelSat = delta; // Saturation', ' secondaryComponents = dot(1.0 - pixelPrimary, sourcePixel.rgb);', ' pixelSat = fmax - mix(secondaryComponents - fmin, secondaryComponents / 2.0, balance);', // Saturation - ' if (pixelSat < 0.1 || luminance < 0.1 || any(notEqual(pixelPrimary, screenPrimary))) {', + + // solid pixel if primary color component is not the same as the screen color + ' float diffPrimary = dot(abs(pixelPrimary - screenPrimary), vec3(1.0));', + ' float solid = step(1.0, step(pixelSat, 0.1) + step(fmax, 0.1) + diffPrimary);', + + /* + Semi-transparent pixel if the primary component matches but if saturation is less + than that of screen color. Otherwise totally transparent + */ + ' float alpha = max(0.0, 1.0 - pixelSat / screenSat);', + ' alpha = smoothstep(clipBlack, clipWhite, alpha);', + ' vec4 semiTransparentPixel = vec4((sourcePixel.rgb - (1.0 - alpha) * screen.rgb * screenWeight) / alpha, alpha);', + + ' vec4 pixel = mix(semiTransparentPixel, sourcePixel, solid);', + + /* + Old branching code + ' if (pixelSat < 0.1 || fmax < 0.1 || any(notEqual(pixelPrimary, screenPrimary))) {', ' pixel = sourcePixel;', - //' pixel = vec4(1.0);', ' } else if (pixelSat < screenSat) {', - ' float alpha = 1.0 - pixelSat / screenSat;', + ' float alpha = max(0.0, 1.0 - pixelSat / screenSat);', ' alpha = smoothstep(clipBlack, clipWhite, alpha);', - //' float despill = alpha / screenWeight;', ' pixel = vec4((sourcePixel.rgb - (1.0 - alpha) * screen.rgb * screenWeight) / alpha, alpha);', - //' pixel = vec4(vec3(alpha), 1.0);', ' }', + //*/ - ' if (mask) {', - ' gl_FragColor = vec4(vec3(pixel.a), 1.0);', - ' } else {', - ' gl_FragColor = pixel;', - ' }', + + '#ifdef MASK', + ' gl_FragColor = vec4(vec3(pixel.a), 1.0);', + '#else', + ' gl_FragColor = pixel;', + '#endif', '}' ].join('\n'); return shaderSource; @@ -172,9 +168,9 @@ mask: { type: 'boolean', defaultValue: false, - uniform: 'mask' + uniform: 'mask', + shaderDirty: true } - }, title: 'Chroma Key', description: '' diff --git a/effects/seriously.crop.js b/effects/seriously.crop.js new file mode 100755 index 0000000..246e2dc --- /dev/null +++ b/effects/seriously.crop.js @@ -0,0 +1,158 @@ +/* global define, require */ +(function (root, factory) { + 'use strict'; + + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['seriously'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS + factory(require('seriously')); + } else { + if (!root.Seriously) { + root.Seriously = { plugin: function (name, opt) { this[name] = opt; } }; + } + factory(root.Seriously); + } +}(this, function (Seriously) { + 'use strict'; + + Seriously.plugin('crop', function () { + var me = this; + + // custom resize method + function resize() { + var width = 1, + height = 1, + source = me.inputs.source, + target, + i; + + if (me.source) { + width = me.source.width; + height = me.source.height; + } else if (me.sources && me.sources.source) { + width = me.sources.source.width; + height = me.sources.source.height; + } + + width = width - me.inputs.left - me.inputs.right; + height = height - me.inputs.top - me.inputs.bottom; + + width = Math.max(1, Math.floor(width)); + height = Math.max(1, Math.floor(height)); + + + if (me.width !== width || me.height !== height) { + me.width = width; + me.height = height; + + me.uniforms.resolution[0] = width; + me.uniforms.resolution[1] = height; + + if (me.frameBuffer) { + me.frameBuffer.resize(me.width, me.height); + } + + me.emit('resize'); + me.setDirty(); + } + + for (i = 0; i < me.targets.length; i++) { + target = me.targets[i]; + target.resize(); + if (target.setTransformDirty) { + target.setTransformDirty(); + } + } + } + + me.resize = resize; + + return { + commonShader: true, + shader: function (inputs, shaderSource) { + shaderSource.vertex = [ + 'precision mediump float;', + + 'attribute vec4 position;', + 'attribute vec2 texCoord;', + + 'uniform vec2 resolution;', + 'uniform mat4 transform;', + + 'uniform float top;', + 'uniform float left;', + 'uniform float bottom;', + 'uniform float right;', + + 'varying vec2 vTexCoord;', + + 'const vec2 ZERO = vec2(0.0);', + 'const vec2 ONE = vec2(1.0);', + + 'void main(void) {', + // first convert to screen space + ' vec4 screenPosition = vec4(position.xy * resolution / 2.0, position.z, position.w);', + ' screenPosition = transform * screenPosition;', + + // convert back to OpenGL coords + ' gl_Position.xy = screenPosition.xy * 2.0 / resolution;', + ' gl_Position.z = screenPosition.z * 2.0 / (resolution.x / resolution.y);', + ' gl_Position.w = screenPosition.w;', + + ' vec2 dim = resolution + vec2(right + left, bottom + top);', + ' vec2 scale = dim / resolution;', + ' vec2 offset = vec2(left, bottom) / resolution;', + + ' vTexCoord = max(ZERO, (texCoord + offset) / scale);', + '}\n' + ].join('\n'); + return shaderSource; + }, + inputs: { + source: { + type: 'image', + uniform: 'source', + update: resize + }, + top: { + type: 'number', + uniform: 'top', + min: 0, + step: 1, + update: resize, + defaultValue: 0 + }, + left: { + type: 'number', + uniform: 'left', + min: 0, + step: 1, + update: resize, + defaultValue: 0 + }, + bottom: { + type: 'number', + uniform: 'bottom', + min: 0, + step: 1, + update: resize, + defaultValue: 0 + }, + right: { + type: 'number', + uniform: 'right', + min: 0, + step: 1, + update: resize, + defaultValue: 0 + } + } + }; + }, + { + inPlace: true, + title: 'Crop' + }); +})); diff --git a/effects/seriously.emboss.js b/effects/seriously.emboss.js index 126cf52..1df1ec5 100644 --- a/effects/seriously.emboss.js +++ b/effects/seriously.emboss.js @@ -20,39 +20,57 @@ Seriously.plugin('emboss', { commonShader: true, shader: function (inputs, shaderSource) { + shaderSource.vertex = [ + 'precision mediump float;', + + 'attribute vec4 position;', + 'attribute vec2 texCoord;', + + 'uniform vec2 resolution;', + 'uniform mat4 transform;', + + 'varying vec2 vTexCoord1;', + 'varying vec2 vTexCoord2;', + + 'void main(void) {', + // first convert to screen space + ' vec4 screenPosition = vec4(position.xy * resolution / 2.0, position.z, position.w);', + ' screenPosition = transform * screenPosition;', + + // convert back to OpenGL coords + ' gl_Position.xy = screenPosition.xy * 2.0 / resolution;', + ' gl_Position.z = screenPosition.z * 2.0 / (resolution.x / resolution.y);', + ' gl_Position.w = screenPosition.w;', + + ' vec2 offset = 1.0 / resolution;', + ' vTexCoord1 = texCoord - offset;', + ' vTexCoord2 = texCoord + offset;', + '}' + ].join('\n'); + shaderSource.fragment = [ 'precision mediump float;', - 'varying vec2 vTexCoord;', + 'varying vec2 vTexCoord1;', + 'varying vec2 vTexCoord2;', 'uniform sampler2D source;', 'uniform float amount;', - 'uniform vec2 dim;', - - //'const vec4 weight = vec4(2.0, 2.0, 2.0, 0.5);', 'const vec3 average = vec3(1.0 / 3.0);', 'void main (void) {', - ' vec2 offset = 1.0 / dim;', ' vec4 pixel = vec4(0.5, 0.5, 0.5, 1.0);', - ' pixel -= texture2D(source, vTexCoord - offset) * amount;', - ' pixel += texture2D(source, vTexCoord + offset) * amount;', - ' float val = dot(pixel.rgb, average);', - ' pixel.rgb = vec3(val);', + + ' pixel -= texture2D(source, vTexCoord1) * amount;', + ' pixel += texture2D(source, vTexCoord2) * amount;', + ' pixel.rgb = vec3(dot(pixel.rgb, average));', + ' gl_FragColor = pixel;', '}' ].join('\n'); return shaderSource; }, - draw: function (shader, model, uniforms, frameBuffer, parent) { - if (!uniforms.dim) { - uniforms.dim = []; - } - uniforms.dim[0] = this.width; - uniforms.dim[1] = this.height; - parent(shader, model, uniforms, frameBuffer); - }, inputs: { source: { type: 'image', @@ -61,7 +79,9 @@ amount: { type: 'number', uniform: 'amount', - defaultValue: 1 + defaultValue: 1, + min: -255 / 3, + max: 255 / 3 } }, title: 'Emboss', diff --git a/effects/seriously.expression.js b/effects/seriously.expression.js index 392c7bb..83c0029 100644 --- a/effects/seriously.expression.js +++ b/effects/seriously.expression.js @@ -260,13 +260,6 @@ } } - function resize() { - if (me.inputs.source) { - me.width = me.inputs.width = me.inputs.source.width; - me.height = me.inputs.height = me.inputs.source.height; - } - } - return { shader: function (inputs, shaderSource) { var expressions = {}, @@ -484,7 +477,6 @@ source: { type: 'image', uniform: 'source', - update: resize, shaderDirty: true }, a: { @@ -533,20 +525,6 @@ alpha: { type: 'string', shaderDirty: true - }, - width: { - type: 'number', - min: 0, - step: 1, - update: resize, - defaultValue: 0 - }, - height: { - type: 'number', - min: 0, - step: 1, - update: resize, - defaultValue: 0 } } }; diff --git a/effects/seriously.layers.js b/effects/seriously.layers.js index 3b4dff5..93e4326 100644 --- a/effects/seriously.layers.js +++ b/effects/seriously.layers.js @@ -120,13 +120,10 @@ n = Math.min(parseInt(a[0], 10), n); } - for (i = 0; i <= n; i++) { - source = this.inputs['source' + i]; - if (source) { - width = source.width; - height = source.height; - break; - } + source = this.inputs['source' + n]; + if (source) { + width = source.width; + height = source.height; } } @@ -143,10 +140,10 @@ this.emit('resize'); this.setDirty(); - } - for (i = 0; i < this.targets.length; i++) { - this.targets[i].resize(); + for (i = 0; i < this.targets.length; i++) { + this.targets[i].resize(); + } } }; diff --git a/effects/seriously.mirror.js b/effects/seriously.mirror.js index b2de740..d78ae80 100644 --- a/effects/seriously.mirror.js +++ b/effects/seriously.mirror.js @@ -26,9 +26,10 @@ 'uniform vec2 resolution;', 'uniform sampler2D source;', + 'varying vec2 vTexCoord;', + 'void main(void) {', - ' vec2 uv = gl_FragCoord.xy / resolution.xy;', - ' gl_FragColor = texture2D(source, vec2(0.5 - abs(0.5 - uv.x), uv.y));', + ' gl_FragColor = texture2D(source, vec2(0.5 - abs(0.5 - vTexCoord.x), vTexCoord.y));', '}' ].join('\n'); return shaderSource; diff --git a/effects/seriously.pixelate.js b/effects/seriously.pixelate.js new file mode 100644 index 0000000..3db971c --- /dev/null +++ b/effects/seriously.pixelate.js @@ -0,0 +1,56 @@ +/* global define, require */ +(function (root, factory) { + 'use strict'; + + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(['seriously'], factory); + } else if (typeof exports === 'object') { + // Node/CommonJS + factory(require('seriously')); + } else { + if (!root.Seriously) { + root.Seriously = { plugin: function (name, opt) { this[name] = opt; } }; + } + factory(root.Seriously); + } +}(this, function (Seriously) { + 'use strict'; + + Seriously.plugin('pixelate', { + commonShader: true, + shader: function (inputs, shaderSource) { + shaderSource.fragment = [ + 'precision mediump float;', + + 'varying vec2 vTexCoord;', + + 'uniform sampler2D source;', + 'uniform vec2 resolution;', + 'uniform vec2 pixelSize;', + + 'void main(void) {', + ' vec2 delta = pixelSize / resolution;', + ' gl_FragColor = texture2D(source, delta * floor(vTexCoord / delta));', + '}' + ].join('\n'); + return shaderSource; + }, + inPlace: true, + inputs: { + source: { + type: 'image', + uniform: 'source', + shaderDirty: false + }, + pixelSize: { + type: 'vector', + dimensions: 2, + defaultValue: [8, 8], + min: 0, + uniform: 'pixelSize' + } + }, + title: 'Pixelate' + }); +})); diff --git a/effects/seriously.split.js b/effects/seriously.split.js index ebdb2e2..b022d6d 100644 --- a/effects/seriously.split.js +++ b/effects/seriously.split.js @@ -166,6 +166,8 @@ '}', 'void main(void) {', + ' vec4 pixel1 = textureLookup(sourceA, vTexCoordA);', + ' vec4 pixel2 = textureLookup(sourceB, vTexCoordB);', ' float mn = (split - fuzzy * (1.0 - split));', ' float mx = (split + fuzzy * split);;', ' vec2 coords = vTexCoord - vec2(0.5);', @@ -174,16 +176,6 @@ ' coords /= scale;', ' coords += vec2(0.5);', ' float x = coords.x;;', - ' if (x <= mn) {', - ' gl_FragColor = textureLookup(sourceB, vTexCoordB);', - ' return;', - ' }', - ' if (x >= mx) {', - ' gl_FragColor = textureLookup(sourceA, vTexCoordA);', - ' return;', - ' }', - ' vec4 pixel1 = textureLookup(sourceA, vTexCoordA);', - ' vec4 pixel2 = textureLookup(sourceB, vTexCoordB);', ' gl_FragColor = mix(pixel2, pixel1, smoothstep(mn, mx, x));', '}' ].join('\n'); diff --git a/effects/seriously.tvglitch.js b/effects/seriously.tvglitch.js index 744e44b..333383a 100644 --- a/effects/seriously.tvglitch.js +++ b/effects/seriously.tvglitch.js @@ -103,7 +103,6 @@ shaderSource.fragment = [ 'precision mediump float;', - //'#define HardLight(top, bottom) (top < 0.5 ? (2.0 * top * bottom) : (1.0 - 2.0 * (1.0 - top) * (1.0 - bottom)))', '#define HardLight(top, bottom) (1.0 - 2.0 * (1.0 - top) * (1.0 - bottom))', 'varying vec2 vTexCoord;', @@ -137,8 +136,6 @@ ' distortAmount -= lineSync * (2.0 * particleOffset.a - 0.5);', ' texCoord.x -= distortAmount;', - //' texCoord.x = max(0.0, texCoord.x);', - //' texCoord.x = min(1.0, texCoord.x);', ' texCoord.x = mod(texCoord.x, 1.0);', //vertical sync @@ -153,12 +150,6 @@ //horizontal bars ' float barsAmount = particleOffset.r;', ' if (barsAmount > 0.0) {', - /* - ' pixel = vec4(HardLight(pixel.r * bars, barsAmount),' + - 'HardLight(pixel.g * bars, barsAmount),' + - 'HardLight(pixel.b * bars, barsAmount),' + - 'pixel.a);', - */ ' pixel = vec4(pixel.r + bars * barsAmount,' + 'pixel.g + bars * barsAmount,' + 'pixel.b + bars * barsAmount,' + @@ -172,11 +163,7 @@ ' float f = (1.0 - gl_FragCoord.x * gl_FragCoord.x) * (1.0 - gl_FragCoord.y * gl_FragCoord.y);', ' float frame = clamp( frameSharpness * (pow(f, frameShape) - frameLimit), 0.0, 1.0);', - //' gl_FragColor.r = vec4(1.0);', - - ' gl_FragColor = mix(frameColor, pixel, frame);', //vec4(vec3(particleOffset), 1.0); - //' gl_FragColor = vec4(particleOffset);', - //' gl_FragColor.a = 1.0;', + ' gl_FragColor = mix(frameColor, pixel, frame);', '}' ].join('\n'); diff --git a/examples/color/linear-transfer.html b/examples/color/linear-transfer.html index 5f767ce..a669c19 100644 --- a/examples/color/linear-transfer.html +++ b/examples/color/linear-transfer.html @@ -69,12 +69,18 @@ ['slope', 'intercept'].forEach(function (prop) { ['red', 'green', 'blue', 'alpha'].forEach(function (channel, channelIndex) { - var id = prop; - id = channel + id[0].toUpperCase() + prop.substr(1); - document.getElementById(id).addEventListener('input', function () { - props[prop][channelIndex] = parseFloat(this.value); + var id = prop, + input; + + function update() { + props[prop][channelIndex] = parseFloat(input.value); effect[prop] = props[prop]; - }, false); + } + + id = channel + id[0].toUpperCase() + prop.substr(1); + input = document.getElementById(id); + input.addEventListener('input', update, false); + input.addEventListener('change', update, false); }); }); }); diff --git a/examples/crop.html b/examples/crop.html new file mode 100644 index 0000000..4cd1003 --- /dev/null +++ b/examples/crop.html @@ -0,0 +1,80 @@ + + +
+