effects/seriously.hue-saturation.js (93 lines of code) (raw):
/* 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';
//inspired by Evan Wallace (https://github.com/evanw/glfx.js)
Seriously.plugin('hue-saturation', {
commonShader: true,
shader: function (inputs, shaderSource) {
shaderSource.vertex = [
'precision mediump float;',
'attribute vec4 position;',
'attribute vec2 texCoord;',
'uniform vec2 resolution;',
'uniform mat4 projection;',
'uniform mat4 transform;',
'uniform float hue;',
'uniform float saturation;',
'varying vec2 vTexCoord;',
'varying vec3 weights;',
'void main(void) {',
' float angle = hue * 3.14159265358979323846264;',
' float s = sin(angle);',
' float c = cos(angle);',
' weights = (vec3(2.0 * c, -sqrt(3.0) * s - c, sqrt(3.0) * s - c) + 1.0) / 3.0;',
// 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 = screenPosition;',
' gl_Position.xy = screenPosition.xy * 2.0 / resolution;',
' gl_Position.z = screenPosition.z * 2.0 / (resolution.x / resolution.y);',
' vTexCoord = texCoord;',
'}'
].join('\n');
shaderSource.fragment = [
'precision mediump float;',
'varying vec2 vTexCoord;',
'varying vec3 weights;',
'uniform sampler2D source;',
'uniform float hue;',
'uniform float saturation;',
'void main(void) {',
' vec4 color = texture2D(source, vTexCoord);',
//adjust hue
' float len = length(color.rgb);',
' color.rgb = vec3(' +
'dot(color.rgb, weights.xyz), ' +
'dot(color.rgb, weights.zxy), ' +
'dot(color.rgb, weights.yzx) ' +
');',
//adjust saturation
' vec3 adjustment = (color.r + color.g + color.b) / 3.0 - color.rgb;',
' if (saturation > 0.0) {',
' adjustment *= (1.0 - 1.0 / (1.0 - saturation));',
' } else {',
' adjustment *= (-saturation);',
' }',
' color.rgb += adjustment;',
' gl_FragColor = color;',
'}'
].join('\n');
return shaderSource;
},
inPlace: true,
inputs: {
source: {
type: 'image',
uniform: 'source'
},
hue: {
type: 'number',
uniform: 'hue',
defaultValue: 0.4,
min: -1,
max: 1
},
saturation: {
type: 'number',
uniform: 'saturation',
defaultValue: 0,
min: -1,
max: 1
}
},
title: 'Hue/Saturation',
description: 'Rotate hue and multiply saturation.'
});
}));