document.write('
Data hosted with ♥ by Pastebin.com - Download Raw - See Original
  1. /**
  2.  * jQuery Ripples plugin v0.1.0 / http://github.com/sirxemic/jquery.ripples
  3.  * MIT License
  4.  * @author sirxemic / http://sirxemic.com/
  5.  * @contribution Metadata Consulting (MDC) / http://metadataconsulting.blogspot.com - IE Fix, edge case
  6.  
  7. + is deliberate - forces the parser to treat the part following the + as an expression. This is usually used for functions that are invoked immediately
  8. **/
  9. +function ($) {
  10.  
  11.     var gl;
  12.     var $window = $(window); // There is only one window, so why not cache the jQuery-wrapped window?
  13.    
  14.     String.prototype.endsWith = function(suffix) {
  15.         return this.indexOf(suffix, this.length - suffix.length) !== -1;
  16.     }; // Stupid Chrome
  17.    
  18.     function hasWebGLSupport() {
  19.         var canvas = document.createElement(\'canvas\');
  20.         var context = canvas.getContext(\'webgl\') || canvas.getContext(\'experimental-webgl\');
  21.         var result = context && context.getExtension(\'OES_texture_float\') && context.getExtension(\'OES_texture_float_linear\');
  22.         return result;
  23.     }
  24.    
  25.     var supportsWebGL = hasWebGLSupport();
  26.  
  27.     function createProgram(vertexSource, fragmentSource, uniformValues)
  28.     {
  29.         function compileSource(type, source) {
  30.             var shader = gl.createShader(type);
  31.             gl.shaderSource(shader, source);
  32.             gl.compileShader(shader);
  33.             if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
  34.                 throw new Error(\'compile error: \' + gl.getShaderInfoLog(shader));
  35.             }
  36.             return shader;
  37.         }
  38.        
  39.         var program = {};
  40.        
  41.         program.id = gl.createProgram();
  42.         gl.attachShader(program.id, compileSource(gl.VERTEX_SHADER, vertexSource));
  43.         gl.attachShader(program.id, compileSource(gl.FRAGMENT_SHADER, fragmentSource));
  44.         gl.linkProgram(program.id);
  45.         if (!gl.getProgramParameter(program.id, gl.LINK_STATUS)) {
  46.             throw new Error(\'link error: \' + gl.getProgramInfoLog(program.id));
  47.         }
  48.  
  49.         // Fetch the uniform and attribute locations
  50.         program.uniforms = {};
  51.         program.locations = {};
  52.         gl.useProgram(program.id);
  53.         gl.enableVertexAttribArray(0);
  54.         var name, type, regex = /uniform (\\w+) (\\w+)/g, shaderCode = vertexSource + fragmentSource;
  55.         while ((match = regex.exec(shaderCode)) != null) {
  56.             name = match[2];
  57.             program.locations[name] = gl.getUniformLocation(program.id, name);
  58.         }
  59.        
  60.         return program;
  61.     }
  62.    
  63.     function bindTexture(texture, unit) {
  64.         gl.activeTexture(gl.TEXTURE0 + (unit || 0));
  65.         gl.bindTexture(gl.TEXTURE_2D, texture);
  66.     }
  67.    
  68.     // Extend the css
  69.     $(\'head\').prepend(\'<style>.jquery-ripples { position: relative; z-index: 0; }</style>\');
  70.  
  71.     // RIPPLES CLASS DEFINITION
  72.     // =========================
  73.  
  74.     var Ripples = function (el, options) {
  75.         var that = this;
  76.        
  77.         this.$el = $(el);
  78.         this.$el.addClass(\'jquery-ripples\');
  79.        
  80.         // If this element doesn\'t have a background image, don\'t apply this effect to it
  81.         var backgroundUrl = (/url\\(["\']?([^"\']*)["\']?\\)/.exec(this.$el.css(\'background-image\')));
  82.         if (backgroundUrl == null) return;
  83.         backgroundUrl = backgroundUrl[1];
  84.        
  85.         this.resolution = options.resolution || 256;
  86.         this.textureDelta = new Float32Array([1 / this.resolution, 1 / this.resolution]);
  87.        
  88.         this.perturbance = options.perturbance;
  89.         this.dropRadius = options.dropRadius;
  90.        
  91.         var canvas = document.createElement(\'canvas\');
  92.         canvas.width = this.$el.innerWidth();
  93.         canvas.height = this.$el.innerHeight();
  94.         this.canvas = canvas;
  95.         this.$canvas = $(canvas);
  96.         this.$canvas.css({
  97.             position: \'absolute\',
  98.             left: 0,
  99.             top: 0,
  100.             right: 0,
  101.             bottom: 0,
  102.             zIndex: -1
  103.         });
  104.        
  105.         this.$el.append(canvas);
  106.         this.context = gl = canvas.getContext(\'webgl\') || canvas.getContext(\'experimental-webgl\');
  107.        
  108.         // Load extensions
  109.         gl.getExtension(\'OES_texture_float\');
  110.         gl.getExtension(\'OES_texture_float_linear\');
  111.        
  112.         // Init events
  113.         $(window).on(\'resize\', function() {
  114.             if (that.$el.innerWidth() != that.canvas.width || that.$el.innerHeight() != that.canvas.height) {
  115.                 canvas.width = that.$el.innerWidth();
  116.                 canvas.height = that.$el.innerHeight();
  117.             }
  118.         });
  119.  
  120.         this.$el.on(\'mousemove.ripples\', function(e) {
  121.             if (that.visible) that.dropAtMouse(e, that.dropRadius, 0.01);
  122.         }).on(\'mousedown.ripples\', function(e) {
  123.             if (that.visible) that.dropAtMouse(e, that.dropRadius * 1.5, 0.14);
  124.         });
  125.        
  126.         this.textures = [];
  127.         this.framebuffers = [];
  128.  
  129.         for (var i = 0; i < 2; i++) {
  130.             var texture = gl.createTexture();
  131.             var framebuffer = gl.createFramebuffer();
  132.            
  133.             gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
  134.             framebuffer.width = this.resolution;
  135.             framebuffer.height = this.resolution;
  136.  
  137.             gl.bindTexture(gl.TEXTURE_2D, texture);
  138.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  139.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  140.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
  141.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
  142.             gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.resolution, this.resolution, 0, gl.RGBA, gl.FLOAT, null);
  143.  
  144.             gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
  145.             if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
  146.                 throw new Error(\'Rendering to this texture is not supported (incomplete framebuffer)\');
  147.             }
  148.            
  149.             gl.bindTexture(gl.TEXTURE_2D, null);
  150.             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  151.            
  152.             this.textures.push(texture);
  153.             this.framebuffers.push(framebuffer);
  154.         }
  155.  
  156.         // Init GL stuff
  157.         this.quad = gl.createBuffer();
  158.         gl.bindBuffer(gl.ARRAY_BUFFER, this.quad);
  159.         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  160.             -1, -1,
  161.             +1, -1,
  162.             +1, +1,
  163.             -1, +1
  164.         ]), gl.STATIC_DRAW);
  165.        
  166.         this.initShaders();
  167.        
  168.         // Init textures
  169.         var image = new Image;
  170.         image.crossOrigin = \'\';
  171.         image.onload = function() {
  172.             gl = that.context;
  173.            
  174.             function isPowerOfTwo(x) {
  175.                 return (x & (x - 1)) == 0;
  176.             }
  177.            
  178.             var wrapping = (isPowerOfTwo(image.width) && isPowerOfTwo(image.height)) ? gl.REPEAT : gl.CLAMP_TO_EDGE;
  179.            
  180.             that.backgroundWidth = image.width;
  181.             that.backgroundHeight = image.height;
  182.            
  183.             var texture = gl.createTexture();
  184.            
  185.             gl.bindTexture(gl.TEXTURE_2D, texture);
  186.             gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
  187.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
  188.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
  189.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapping);
  190.             gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapping);
  191.             gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
  192.            
  193.             that.backgroundTexture = texture;
  194.            
  195.             // Everything loaded successfully - hide the CSS background image
  196.             that.$el.css(\'backgroundImage\', \'none\');
  197.         };
  198.         image.src = backgroundUrl;
  199.        
  200.         this.visible = true;
  201.        
  202.         // Init animation
  203.         function step() {
  204.             that.update();
  205.             requestAnimationFrame(step);
  206.         }
  207.        
  208.         requestAnimationFrame(step);
  209.     };
  210.  
  211.     Ripples.DEFAULTS = {
  212.         resolution: 256,
  213.         dropRadius: 20,
  214.         perturbance: 0.03
  215.     };
  216.    
  217.     Ripples.prototype = {
  218.  
  219.         update: function() {
  220.             gl = this.context;
  221.            
  222.             if (!this.visible || !this.backgroundTexture) return;
  223.            
  224.             this.updateTextures();
  225.             this.render();
  226.         },
  227.        
  228.         drawQuad: function() {
  229.             gl.bindBuffer(gl.ARRAY_BUFFER, this.quad);
  230.             gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
  231.             gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
  232.         },
  233.        
  234.         render: function() {
  235.             gl.viewport(0, 0, this.canvas.width, this.canvas.height);
  236.             gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
  237.  
  238.             gl.useProgram(this.renderProgram.id);
  239.            
  240.             bindTexture(this.backgroundTexture, 0);
  241.             bindTexture(this.textures[0], 1);
  242.            
  243.             gl.uniform2fv(this.renderProgram.locations.topLeft, this.renderProgram.uniforms.topLeft);
  244.             gl.uniform2fv(this.renderProgram.locations.bottomRight, this.renderProgram.uniforms.bottomRight);
  245.             gl.uniform2fv(this.renderProgram.locations.containerRatio, this.renderProgram.uniforms.containerRatio);
  246.             gl.uniform1i(this.renderProgram.locations.samplerBackground, 0);
  247.             gl.uniform1i(this.renderProgram.locations.samplerRipples, 1);
  248.            
  249.             this.drawQuad();
  250.         },
  251.  
  252.         updateTextures: function() {
  253.             this.computeTextureBoundaries();
  254.            
  255.             gl.viewport(0, 0, this.resolution, this.resolution);
  256.            
  257.             for (var i = 0; i < 2; i++) {
  258.                 gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffers[i]);
  259.                 bindTexture(this.textures[1-i]);
  260.                 gl.useProgram(this.updateProgram[i].id);
  261.                
  262.                 this.drawQuad();
  263.             }
  264.  
  265.             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  266.         },
  267.        
  268.         computeTextureBoundaries: function() {
  269.  
  270.             var backgroundSize = this.$el.css(\'background-size\');
  271.             var backgroundAttachment = this.$el.css(\'background-attachment\');
  272.             var backgroundPosition = this.$el.css(\'background-position\').split(\' \');
  273.  
  274.             // Here the \'window\' is the element which the background adapts to
  275.             // (either the chrome window or some element, depending on attachment)
  276.             var parElement = backgroundAttachment == \'fixed\' ? $window : this.$el;
  277.             var winOffset = parElement.offset() || {left: pageXOffset, top: pageYOffset};
  278.             var winWidth = parElement.innerWidth();
  279.             var winHeight = parElement.innerHeight();
  280.  
  281.             // TODO: background-clip
  282.             if (backgroundSize == \'cover\') {
  283.                 var scale = Math.max(winWidth / this.backgroundWidth, winHeight / this.backgroundHeight);
  284.                
  285.                 var backgroundWidth = this.backgroundWidth * scale;
  286.                 var backgroundHeight = this.backgroundHeight * scale;
  287.             }
  288.             else if (backgroundSize == \'contain\') {
  289.                 var scale = Math.min(winWidth / this.backgroundWidth, winHeight / this.backgroundHeight);
  290.                
  291.                 var backgroundWidth = this.backgroundWidth * scale;
  292.                 var backgroundHeight = this.backgroundHeight * scale;
  293.             }
  294.             else {
  295.                 backgroundSize = backgroundSize.split(\' \');
  296.                 var backgroundWidth = backgroundSize[0];
  297.                 var backgroundHeight = backgroundSize[1] || backgroundSize[0];
  298.                
  299.                 if (backgroundWidth.endsWith(\'%\')) backgroundWidth = winWidth * parseFloat(backgroundWidth) / 100;
  300.                 else if (backgroundWidth != \'auto\') backgroundWidth = parseFloat(backgroundWidth);
  301.                
  302.                 if (backgroundHeight.endsWith(\'%\')) backgroundHeight = winHeight * parseFloat(backgroundHeight) / 100;
  303.                 else if (backgroundHeight != \'auto\') backgroundHeight = parseFloat(backgroundHeight);
  304.                
  305.                 if (backgroundWidth == \'auto\' && backgroundHeight == \'auto\') {
  306.                     backgroundWidth = this.backgroundWidth;
  307.                     backgroundHeight = this.backgroundHeight;
  308.                 }
  309.                 else {
  310.                     if (backgroundWidth == \'auto\') backgroundWidth = this.backgroundWidth * (backgroundHeight / this.backgroundHeight);
  311.                     if (backgroundHeight == \'auto\') backgroundHeight = this.backgroundHeight * (backgroundWidth / this.backgroundWidth);
  312.                 }
  313.             }
  314.            
  315.             // Sun 18-Jan-15 MDC - add edge case for IE 11
  316.             var backgroundX = (typeof backgroundPosition[0] == \'undefined\') ? \'\':backgroundPosition[0];
  317.             var backgroundY = (typeof backgroundPosition[1] == \'undefined\') ? \'\':backgroundPosition[1];
  318.            
  319.             if (backgroundX != \'\') {  
  320.                 if (backgroundX == \'left\') backgroundX = winOffset.left;
  321.                 else if (backgroundX == \'center\') backgroundX = winOffset.left + winWidth / 2 - backgroundWidth / 2;
  322.                 else if (backgroundX == \'right\') backgroundX = winOffset.left + winWidth - backgroundWidth;
  323.                 else if (backgroundX.endsWith(\'%\')) {
  324.                     backgroundX = winOffset.left + (winWidth - backgroundWidth) * parseFloat(backgroundX) / 100;
  325.                 }
  326.                 else {
  327.                     backgroundX = parseFloat(backgroundX);
  328.                 }
  329.            }
  330.  
  331.             if (backgroundY != \'\') {  
  332.                 if (backgroundY == \'top\') backgroundY = winOffset.top;
  333.                 else if (backgroundY == \'center\') backgroundY = winOffset.top + winHeight / 2 - backgroundHeight / 2;
  334.                 else if (backgroundY == \'bottom\') backgroundY = winOffset.top + winHeight - backgroundHeight;
  335.                 else if (backgroundY.endsWith(\'%\')) {
  336.                     backgroundY = winOffset.top + (winHeight - backgroundHeight) * parseFloat(backgroundY) / 100;
  337.                 }
  338.                 else {
  339.                     backgroundY = parseFloat(backgroundY);
  340.                 }
  341.             }
  342.             var elementOffset = this.$el.offset();
  343.            
  344.             this.renderProgram.uniforms.topLeft = new Float32Array([
  345.                 (elementOffset.left - backgroundX) / backgroundWidth,
  346.                 (elementOffset.top - backgroundY) / backgroundHeight
  347.             ]);
  348.             this.renderProgram.uniforms.bottomRight = new Float32Array([
  349.                 this.renderProgram.uniforms.topLeft[0] + this.$el.innerWidth() / backgroundWidth,
  350.                 this.renderProgram.uniforms.topLeft[1] + this.$el.innerHeight() / backgroundHeight
  351.             ]);
  352.            
  353.             var maxSide = Math.max(this.canvas.width, this.canvas.height);
  354.            
  355.             this.renderProgram.uniforms.containerRatio = new Float32Array([
  356.                 this.canvas.width / maxSide,
  357.                 this.canvas.height / maxSide
  358.             ]);
  359.         },
  360.        
  361.         initShaders: function() {
  362.             var vertexShader = [
  363.                 \'attribute vec2 vertex;\',
  364.                 \'varying vec2 coord;\',
  365.                 \'void main() {\',
  366.                     \'coord = vertex * 0.5 + 0.5;\',
  367.                     \'gl_Position = vec4(vertex, 0.0, 1.0);\',
  368.                 \'}\'
  369.             ].join(\'\\n\');
  370.            
  371.             this.dropProgram = createProgram(vertexShader, [
  372.                 \'precision highp float;\',
  373.                
  374.                 \'const float PI = 3.141592653589793;\',
  375.                 \'uniform sampler2D texture;\',
  376.                 \'uniform vec2 center;\',
  377.                 \'uniform float radius;\',
  378.                 \'uniform float strength;\',
  379.                
  380.                 \'varying vec2 coord;\',
  381.                
  382.                 \'void main() {\',
  383.                     \'vec4 info = texture2D(texture, coord);\',
  384.                    
  385.                     \'float drop = max(0.0, 1.0 - length(center * 0.5 + 0.5 - coord) / radius);\',
  386.                     \'drop = 0.5 - cos(drop * PI) * 0.5;\',
  387.                    
  388.                     \'info.r += drop * strength;\',
  389.                    
  390.                     \'gl_FragColor = info;\',
  391.                 \'}\'
  392.             ].join(\'\\n\'));
  393.            
  394.             this.updateProgram = [0,0];
  395.             this.updateProgram[0] = createProgram(vertexShader, [
  396.                 \'precision highp float;\',
  397.                
  398.                 \'uniform sampler2D texture;\',
  399.                 \'uniform vec2 delta;\',
  400.                
  401.                 \'varying vec2 coord;\',
  402.                
  403.                 \'void main() {\',
  404.                     \'vec4 info = texture2D(texture, coord);\',
  405.                    
  406.                     \'vec2 dx = vec2(delta.x, 0.0);\',
  407.                     \'vec2 dy = vec2(0.0, delta.y);\',
  408.                    
  409.                     \'float average = (\',
  410.                         \'texture2D(texture, coord - dx).r +\',
  411.                         \'texture2D(texture, coord - dy).r +\',
  412.                         \'texture2D(texture, coord + dx).r +\',
  413.                         \'texture2D(texture, coord + dy).r\',
  414.                     \') * 0.25;\',
  415.                    
  416.                     \'info.g += (average - info.r) * 2.0;\',
  417.                     \'info.g *= 0.995;\',
  418.                     \'info.r += info.g;\',
  419.                    
  420.                     \'gl_FragColor = info;\',
  421.                 \'}\'
  422.             ].join(\'\\n\'));
  423.             gl.uniform2fv(this.updateProgram[0].locations.delta, this.textureDelta);
  424.            
  425.             this.updateProgram[1] = createProgram(vertexShader, [
  426.                 \'precision highp float;\',
  427.                
  428.                 \'uniform sampler2D texture;\',
  429.                 \'uniform vec2 delta;\',
  430.                
  431.                 \'varying vec2 coord;\',
  432.                
  433.                 \'void main() {\',
  434.                     \'vec4 info = texture2D(texture, coord);\',
  435.                    
  436.                     \'vec3 dx = vec3(delta.x, texture2D(texture, vec2(coord.x + delta.x, coord.y)).r - info.r, 0.0);\',
  437.                     \'vec3 dy = vec3(0.0, texture2D(texture, vec2(coord.x, coord.y + delta.y)).r - info.r, delta.y);\',
  438.                     \'info.ba = normalize(cross(dy, dx)).xz;\',
  439.                    
  440.                     \'gl_FragColor = info;\',
  441.                 \'}\'
  442.             ].join(\'\\n\'));
  443.             gl.uniform2fv(this.updateProgram[1].locations.delta, this.textureDelta);
  444.            
  445.             this.renderProgram = createProgram([
  446.                 \'precision highp float;\',
  447.                
  448.                 \'attribute vec2 vertex;\',
  449.                 \'uniform vec2 topLeft;\',
  450.                 \'uniform vec2 bottomRight;\',
  451.                 \'uniform vec2 containerRatio;\',
  452.                 \'varying vec2 ripplesCoord;\',
  453.                 \'varying vec2 backgroundCoord;\',
  454.                 \'void main() {\',
  455.                     \'backgroundCoord = mix(topLeft, bottomRight, vertex * 0.5 + 0.5);\',
  456.                     \'backgroundCoord.y = 1.0 - backgroundCoord.y;\',
  457.                     \'ripplesCoord = vec2(vertex.x, -vertex.y) * containerRatio * 0.5 + 0.5;\',
  458.                     \'gl_Position = vec4(vertex.x, -vertex.y, 0.0, 1.0);\',
  459.                 \'}\'
  460.             ].join(\'\\n\'), [
  461.                 \'precision highp float;\',
  462.                
  463.                 \'uniform sampler2D samplerBackground;\',
  464.                 \'uniform sampler2D samplerRipples;\',
  465.                 \'uniform float perturbance;\',
  466.                 \'varying vec2 ripplesCoord;\',
  467.                 \'varying vec2 backgroundCoord;\',
  468.                
  469.                 \'void main() {\',
  470.                     \'vec2 offset = -texture2D(samplerRipples, ripplesCoord).ba;\',
  471.                     \'float specular = pow(max(0.0, dot(offset, normalize(vec2(-0.6, 1.0)))), 4.0);\',
  472.                     \'gl_FragColor = texture2D(samplerBackground, backgroundCoord + offset * perturbance) + specular;\',
  473.                 \'}\'
  474.             ].join(\'\\n\'));
  475.             gl.uniform1f(this.renderProgram.locations.perturbance, this.perturbance);
  476.         },
  477.        
  478.         dropAtMouse: function(e, radius, strength) {
  479.             this.drop(
  480.                 e.offsetX || (e.pageX - this.$el.offset().left),
  481.                 e.offsetY || (e.pageY - this.$el.offset().top),
  482.                 radius,
  483.                 strength
  484.             );
  485.         },
  486.        
  487.         drop: function(x, y, radius, strength) {
  488.             var that = this;
  489.  
  490.             gl = this.context;
  491.  
  492.             var elWidth = this.$el.outerWidth();
  493.             var elHeight = this.$el.outerHeight();
  494.             var longestSide = Math.max(elWidth, elHeight);
  495.            
  496.             radius = radius / longestSide;
  497.            
  498.             var dropPosition = new Float32Array([
  499.                 (2 * x - elWidth) / longestSide,
  500.                 (elHeight - 2 * y) / longestSide
  501.             ]);
  502.  
  503.             gl.viewport(0, 0, this.resolution, this.resolution);
  504.            
  505.             // Render onto texture/framebuffer 0
  506.             gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffers[0]);
  507.            
  508.             // Using texture 1
  509.             bindTexture(this.textures[1]);
  510.  
  511.             gl.useProgram(this.dropProgram.id);
  512.             gl.uniform2fv(this.dropProgram.locations.center, dropPosition);
  513.             gl.uniform1f(this.dropProgram.locations.radius, radius);
  514.             gl.uniform1f(this.dropProgram.locations.strength, strength);
  515.            
  516.             this.drawQuad();
  517.            
  518.             // Switch textures
  519.             var t = this.framebuffers[0]; this.framebuffers[0] = this.framebuffers[1]; this.framebuffers[1] = t;
  520.             t = this.textures[0]; this.textures[0] = this.textures[1]; this.textures[1] = t;
  521.            
  522.             gl.bindFramebuffer(gl.FRAMEBUFFER, null);
  523.         },
  524.        
  525.         // Actions
  526.         destroy: function() {
  527.             this.canvas.remove();
  528.             this.$el.off(\'.ripples\');
  529.             this.$el.css(\'backgroundImage\', \'\');
  530.             this.$el.removeClass(\'jquery-ripples\').data(\'ripples\', undefined);
  531.         },
  532.        
  533.         show: function() {
  534.             this.$canvas.show();
  535.             this.$el.css(\'backgroundImage\', \'none\');
  536.             this.visible = true;
  537.         },
  538.        
  539.         hide: function() {
  540.             this.$canvas.hide();
  541.             this.$el.css(\'backgroundImage\', \'\');
  542.             this.visible = false;
  543.         }
  544.     };
  545.  
  546.     // RIPPLES PLUGIN DEFINITION
  547.     // ==========================
  548.  
  549.     var old = $.fn.ripples;
  550.  
  551.     $.fn.ripples = function(option) {
  552.         if (!supportsWebGL) throw new Error(\'Your browser does not support at least one of the following: WebGL, OES_texture_float extension, OES_texture_float_linear extension.\');
  553.  
  554.         var args = (arguments.length > 1) ? Array.prototype.slice.call(arguments, 1) : undefined;
  555.  
  556.         return this.each(function() {
  557.             var $this   = $(this);
  558.             var data    = $this.data(\'ripples\');
  559.             var options = $.extend({}, Ripples.DEFAULTS, $this.data(), typeof option == \'object\' && option);
  560.            
  561.             if (!data && typeof option == \'string\' && option == \'destroy\') return;
  562.             if (!data) $this.data(\'ripples\', (data = new Ripples(this, options)));
  563.             else if (typeof option == \'string\') Ripples.prototype[option].apply(data, args);
  564.         });
  565.     }
  566.  
  567.     $.fn.ripples.Constructor = Ripples;
  568.  
  569.  
  570.     // RIPPLES NO CONFLICT
  571.     // ====================
  572.  
  573.     $.fn.ripples.noConflict = function() {
  574.         $.fn.ripples = old;
  575.         return this;
  576.     }
  577.  
  578. }(window.jQuery);
');