vendor: 24,249 bytes, lines 1-894
1/** 2 * jQuery Ripples plugin v0.6.1 / https://github.com/sirxemic/jquery.ripples 3 * MIT License 4 * @author sirxemic / https://sirxemic.com/ 5 */ 6 7(function (global, factory) { 8 typeof exports === 'object' && typeof module !== 'undefined' ? factory(require('jquery')) : 9 typeof define === 'function' && define.amd ? define(['jquery'], factory) : 10 (factory(global.$)); 11}(this, (function ($) { 'use strict'; 12 13$ = $ && $.hasOwnProperty('default') ? $['default'] : $; 14 15var gl; 16var $window = $(window); // There is only one window, so why not cache the jQuery-wrapped window? 17 18function isPercentage(str) { 19 return str[str.length - 1] == '%'; 20} 21 22/** 23 * Load a configuration of GL settings which the browser supports. 24 * For example: 25 * - not all browsers support WebGL 26 * - not all browsers support floating point textures 27 * - not all browsers support linear filtering for floating point textures 28 * - not all browsers support rendering to floating point textures 29 * - some browsers *do* support rendering to half-floating point textures instead. 30 */ 31function loadConfig() { 32 var canvas = document.createElement('canvas'); 33 gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); 34 35 if (!gl) { 36 // Browser does not support WebGL. 37 return null; 38 } 39 40 // Load extensions 41 var extensions = {}; 42 [ 43 'OES_texture_float', 44 'OES_texture_half_float', 45 'OES_texture_float_linear', 46 'OES_texture_half_float_linear' 47 ].forEach(function(name) { 48 var extension = gl.getExtension(name); 49 if (extension) { 50 extensions[name] = extension; 51 } 52 }); 53 54 // If no floating point extensions are supported we can bail out early. 55 if (!extensions.OES_texture_float) { 56 return null; 57 } 58 59 var configs = []; 60 61 function createConfig(type, glType) { 62 var name = 'OES_texture_' + type, 63 nameLinear = name + '_linear', 64 linearSupport = nameLinear in extensions, 65 configExtensions = [name]; 66 67 if (linearSupport) { 68 configExtensions.push(nameLinear); 69 } 70 71 return { 72 type: glType, 73 linearSupport: linearSupport, 74 extensions: configExtensions 75 }; 76 } 77 78 configs.push( 79 createConfig('float', gl.FLOAT) 80 ); 81 82 if (extensions.OES_texture_half_float) { 83 configs.push( 84 createConfig('half_float', extensions.OES_texture_half_float.HALF_FLOAT_OES) 85 ); 86 } 87 88 // Setup the texture and framebuffer 89 var texture = gl.createTexture(); 90 var framebuffer = gl.createFramebuffer(); 91 92 gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); 93 gl.bindTexture(gl.TEXTURE_2D, texture); 94 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 95 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 96 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 97 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 98 99 // Check for each supported texture type if rendering to it is supported 100 var config = null; 101 102 for (var i = 0; i < configs.length; i++) { 103 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 32, 32, 0, gl.RGBA, configs[i].type, null); 104 105 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); 106 if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) === gl.FRAMEBUFFER_COMPLETE) { 107 config = configs[i]; 108 break; 109 } 110 } 111 112 return config; 113} 114 115function createImageData(width, height) { 116 try { 117 return new ImageData(width, height); 118 } 119 catch (e) { 120 // Fallback for IE 121 var canvas = document.createElement('canvas'); 122 return canvas.getContext('2d').createImageData(width, height); 123 } 124} 125 126function translateBackgroundPosition(value) { 127 var parts = value.split(' '); 128 129 if (parts.length === 1) { 130 switch (value) { 131 case 'center': 132 return ['50%', '50%']; 133 case 'top': 134 return ['50%', '0']; 135 case 'bottom': 136 return ['50%', '100%']; 137 case 'left': 138 return ['0', '50%']; 139 case 'right': 140 return ['100%', '50%']; 141 default: 142 return [value, '50%']; 143 } 144 } 145 else { 146 return parts.map(function(part) { 147 switch (value) { 148 case 'center': 149 return '50%'; 150 case 'top': 151 case 'left': 152 return '0'; 153 case 'right': 154 case 'bottom': 155 return '100%'; 156 default: 157 return part; 158 } 159 }); 160 } 161} 162 163function createProgram(vertexSource, fragmentSource, uniformValues) { 164 function compileSource(type, source) { 165 var shader = gl.createShader(type); 166 gl.shaderSource(shader, source); 167 gl.compileShader(shader); 168 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { 169 throw new Error('compile error: ' + gl.getShaderInfoLog(shader)); 170 } 171 return shader; 172 } 173 174 var program = {}; 175 176 program.id = gl.createProgram(); 177 gl.attachShader(program.id, compileSource(gl.VERTEX_SHADER, vertexSource)); 178 gl.attachShader(program.id, compileSource(gl.FRAGMENT_SHADER, fragmentSource)); 179 gl.linkProgram(program.id); 180 if (!gl.getProgramParameter(program.id, gl.LINK_STATUS)) { 181 throw new Error('link error: ' + gl.getProgramInfoLog(program.id)); 182 } 183 184 // Fetch the uniform and attribute locations 185 program.uniforms = {}; 186 program.locations = {}; 187 gl.useProgram(program.id); 188 gl.enableVertexAttribArray(0); 189 var match, name, regex = /uniform (\w+) (\w+)/g, shaderCode = vertexSource + fragmentSource; 190 while ((match = regex.exec(shaderCode)) != null) { 191 name = match[2]; 192 program.locations[name] = gl.getUniformLocation(program.id, name); 193 } 194 195 return program; 196} 197 198function bindTexture(texture, unit) { 199 gl.activeTexture(gl.TEXTURE0 + (unit || 0)); 200 gl.bindTexture(gl.TEXTURE_2D, texture); 201} 202 203function extractUrl(value) { 204 var urlMatch = /url\(["']?([^"']*)["']?\)/.exec(value); 205 if (urlMatch == null) { 206 return null; 207 } 208 209 return urlMatch[1]; 210} 211 212function isDataUri(url) { 213 return url.match(/^data:/); 214} 215 216var config = loadConfig(); 217var transparentPixels = createImageData(32, 32); 218 219// Extend the css 220$('head').prepend('<style>.jquery-ripples { position: relative; z-index: 0; }</style>'); 221 222// RIPPLES CLASS DEFINITION 223// ========================= 224 225var Ripples = function (el, options) { 226 var that = this; 227 228 this.$el = $(el); 229 230 // Init properties from options 231 this.interactive = options.interactive; 232 this.resolution = options.resolution; 233 this.textureDelta = new Float32Array([1 / this.resolution, 1 / this.resolution]); 234 235 this.perturbance = options.perturbance; 236 this.dropRadius = options.dropRadius; 237 238 this.crossOrigin = options.crossOrigin; 239 this.imageUrl = options.imageUrl; 240 241 // Init WebGL canvas 242 var canvas = document.createElement('canvas'); 243 canvas.width = this.$el.innerWidth(); 244 canvas.height = this.$el.innerHeight(); 245 this.canvas = canvas; 246 this.$canvas = $(canvas); 247 this.$canvas.css({ 248 position: 'absolute', 249 left: 0, 250 top: 0, 251 right: 0, 252 bottom: 0, 253 zIndex: -1 254 }); 255 256 this.$el.addClass('jquery-ripples').append(canvas); 257 this.context = gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); 258 259 // Load extensions 260 config.extensions.forEach(function(name) { 261 gl.getExtension(name); 262 }); 263 264 // Auto-resize when window size changes. 265 $(window).on('resize', function() { 266 that.updateSize(); 267 }); 268 269 // Init rendertargets for ripple data. 270 this.textures = []; 271 this.framebuffers = []; 272 this.bufferWriteIndex = 0; 273 this.bufferReadIndex = 1; 274 275 var textureData = new Float32Array(this.resolution * this.resolution * 4); 276 277 for (var i = 0; i < 2; i++) { 278 var texture = gl.createTexture(); 279 var framebuffer = gl.createFramebuffer(); 280 281 gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer); 282 283 gl.bindTexture(gl.TEXTURE_2D, texture); 284 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, config.linearSupport ? gl.LINEAR : gl.NEAREST); 285 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, config.linearSupport ? gl.LINEAR : gl.NEAREST); 286 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 287 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 288 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, this.resolution, this.resolution, 0, gl.RGBA, config.type, textureData); 289 290 gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0); 291 292 this.textures.push(texture); 293 this.framebuffers.push(framebuffer); 294 } 295 296 // Init GL stuff 297 this.quad = gl.createBuffer(); 298 gl.bindBuffer(gl.ARRAY_BUFFER, this.quad); 299 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 300 -1, -1, 301 +1, -1, 302 +1, +1, 303 -1, +1 304 ]), gl.STATIC_DRAW); 305 306 this.initShaders(); 307 this.initTexture(); 308 this.setTransparentTexture(); 309 310 // Load the image either from the options or CSS rules 311 this.loadImage(); 312 313 // Set correct clear color and blend mode (regular alpha blending) 314 gl.clearColor(0, 0, 0, 0); 315 gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); 316 317 // Plugin is successfully initialized! 318 this.visible = true; 319 this.running = true; 320 this.inited = true; 321 this.destroyed = false; 322 323 this.setupPointerEvents(); 324 325 // Init animation 326 function step() { 327 if (!that.destroyed) { 328 that.step(); 329 330 requestAnimationFrame(step); 331 } 332 } 333 334 requestAnimationFrame(step); 335}; 336 337Ripples.DEFAULTS = { 338 imageUrl: null, 339 resolution: 256, 340 dropRadius: 20, 341 perturbance: 0.03, 342 interactive: true, 343 crossOrigin: '' 344}; 345 346Ripples.prototype = { 347 348 // Set up pointer (mouse + touch) events 349 setupPointerEvents: function() { 350 var that = this; 351 352 function pointerEventsEnabled() { 353 return that.visible && that.running && that.interactive; 354 } 355 356 function dropAtPointer(pointer, big) { 357 if (pointerEventsEnabled()) { 358 that.dropAtPointer( 359 pointer, 360 that.dropRadius * (big ? 1.5 : 1), 361 (big ? 0.14 : 0.01) 362 ); 363 } 364 } 365 366 // Start listening to pointer events 367 this.$el 368 369 // Create regular, small ripples for mouse move and touch events... 370 .on('mousemove.ripples', function(e) { 371 dropAtPointer(e); 372 }) 373 .on('touchmove.ripples, touchstart.ripples', function(e) { 374 var touches = e.originalEvent.changedTouches; 375 for (var i = 0; i < touches.length; i++) { 376 dropAtPointer(touches[i]); 377 } 378 }) 379 380 // ...and only a big ripple on mouse down events. 381 .on('mousedown.ripples', function(e) { 382 dropAtPointer(e, true); 383 }); 384 }, 385 386 // Load the image either from the options or the element's CSS rules. 387 loadImage: function() { 388 var that = this; 389 390 gl = this.context; 391 392 var newImageSource = this.imageUrl || 393 extractUrl(this.originalCssBackgroundImage) || 394 extractUrl(this.$el.css('backgroundImage')); 395 396 // If image source is unchanged, don't reload it. 397 if (newImageSource == this.imageSource) { 398 return; 399 } 400 401 this.imageSource = newImageSource; 402 403 // Falsy source means no background. 404 if (!this.imageSource) { 405 this.setTransparentTexture(); 406 return; 407 } 408 409 // Load the texture from a new image. 410 var image = new Image; 411 image.onload = function() { 412 gl = that.context; 413 414 // Only textures with dimensions of powers of two can have repeat wrapping. 415 function isPowerOfTwo(x) { 416 return (x & (x - 1)) == 0; 417 } 418 419 var wrapping = (isPowerOfTwo(image.width) && isPowerOfTwo(image.height)) ? gl.REPEAT : gl.CLAMP_TO_EDGE; 420 421 gl.bindTexture(gl.TEXTURE_2D, that.backgroundTexture); 422 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapping); 423 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapping); 424 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); 425 426 that.backgroundWidth = image.width; 427 that.backgroundHeight = image.height; 428 429 // Hide the background that we're replacing. 430 that.hideCssBackground(); 431 }; 432 433 // Fall back to a transparent texture when loading the image failed. 434 image.onerror = function() { 435 gl = that.context; 436 437 that.setTransparentTexture(); 438 }; 439 440 // Disable CORS when the image source is a data URI. 441 image.crossOrigin = isDataUri(this.imageSource) ? null : this.crossOrigin; 442 443 image.src = this.imageSource; 444 }, 445 446 step: function() { 447 gl = this.context; 448 449 if (!this.visible) { 450 return; 451 } 452 453 this.computeTextureBoundaries(); 454 455 if (this.running) { 456 this.update(); 457 } 458 459 this.render(); 460 }, 461 462 drawQuad: function() { 463 gl.bindBuffer(gl.ARRAY_BUFFER, this.quad); 464 gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0); 465 gl.drawArrays(gl.TRIANGLE_FAN, 0, 4); 466 }, 467 468 render: function() { 469 gl.bindFramebuffer(gl.FRAMEBUFFER, null); 470 471 gl.viewport(0, 0, this.canvas.width, this.canvas.height); 472 473 gl.enable(gl.BLEND); 474 gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); 475 476 gl.useProgram(this.renderProgram.id); 477 478 bindTexture(this.backgroundTexture, 0); 479 bindTexture(this.textures[0], 1); 480 481 gl.uniform1f(this.renderProgram.locations.perturbance, this.perturbance); 482 gl.uniform2fv(this.renderProgram.locations.topLeft, this.renderProgram.uniforms.topLeft); 483 gl.uniform2fv(this.renderProgram.locations.bottomRight, this.renderProgram.uniforms.bottomRight); 484 gl.uniform2fv(this.renderProgram.locations.containerRatio, this.renderProgram.uniforms.containerRatio); 485 gl.uniform1i(this.renderProgram.locations.samplerBackground, 0); 486 gl.uniform1i(this.renderProgram.locations.samplerRipples, 1); 487 488 this.drawQuad(); 489 gl.disable(gl.BLEND); 490 }, 491 492 update: function() { 493 gl.viewport(0, 0, this.resolution, this.resolution); 494 495 gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffers[this.bufferWriteIndex]); 496 bindTexture(this.textures[this.bufferReadIndex]); 497 gl.useProgram(this.updateProgram.id); 498 499 this.drawQuad(); 500 501 this.swapBufferIndices(); 502 }, 503 504 swapBufferIndices: function() { 505 this.bufferWriteIndex = 1 - this.bufferWriteIndex; 506 this.bufferReadIndex = 1 - this.bufferReadIndex; 507 }, 508 509 computeTextureBoundaries: function() { 510 var backgroundSize = this.$el.css('background-size'); 511 var backgroundAttachment = this.$el.css('background-attachment'); 512 var backgroundPosition = translateBackgroundPosition(this.$el.css('background-position')); 513 514 // Here the 'container' is the element which the background adapts to 515 // (either the chrome window or some element, depending on attachment) 516 var container; 517 if (backgroundAttachment == 'fixed') { 518 container = { left: window.pageXOffset, top: window.pageYOffset }; 519 container.width = $window.width(); 520 container.height = $window.height(); 521 } 522 else { 523 container = this.$el.offset(); 524 container.width = this.$el.innerWidth(); 525 container.height = this.$el.innerHeight(); 526 } 527 528 // TODO: background-clip 529 if (backgroundSize == 'cover') { 530 var scale = Math.max(container.width / this.backgroundWidth, container.height / this.backgroundHeight); 531 532 var backgroundWidth = this.backgroundWidth * scale; 533 var backgroundHeight = this.backgroundHeight * scale; 534 } 535 else if (backgroundSize == 'contain') { 536 var scale = Math.min(container.width / this.backgroundWidth, container.height / this.backgroundHeight); 537 538 var backgroundWidth = this.backgroundWidth * scale; 539 var backgroundHeight = this.backgroundHeight * scale; 540 } 541 else { 542 backgroundSize = backgroundSize.split(' '); 543 var backgroundWidth = backgroundSize[0] || ''; 544 var backgroundHeight = backgroundSize[1] || backgroundWidth; 545 546 if (isPercentage(backgroundWidth)) { 547 backgroundWidth = container.width * parseFloat(backgroundWidth) / 100; 548 } 549 else if (backgroundWidth != 'auto') { 550 backgroundWidth = parseFloat(backgroundWidth); 551 } 552 553 if (isPercentage(backgroundHeight)) { 554 backgroundHeight = container.height * parseFloat(backgroundHeight) / 100; 555 } 556 else if (backgroundHeight != 'auto') { 557 backgroundHeight = parseFloat(backgroundHeight); 558 } 559 560 if (backgroundWidth == 'auto' && backgroundHeight == 'auto') { 561 backgroundWidth = this.backgroundWidth; 562 backgroundHeight = this.backgroundHeight; 563 } 564 else { 565 if (backgroundWidth == 'auto') { 566 backgroundWidth = this.backgroundWidth * (backgroundHeight / this.backgroundHeight); 567 } 568 569 if (backgroundHeight == 'auto') { 570 backgroundHeight = this.backgroundHeight * (backgroundWidth / this.backgroundWidth); 571 } 572 } 573 } 574 575 // Compute backgroundX and backgroundY in page coordinates 576 var backgroundX = backgroundPosition[0]; 577 var backgroundY = backgroundPosition[1]; 578 579 if (isPercentage(backgroundX)) { 580 backgroundX = container.left + (container.width - backgroundWidth) * parseFloat(backgroundX) / 100; 581 } 582 else { 583 backgroundX = container.left + parseFloat(backgroundX); 584 } 585 586 if (isPercentage(backgroundY)) { 587 backgroundY = container.top + (container.height - backgroundHeight) * parseFloat(backgroundY) / 100; 588 } 589 else { 590 backgroundY = container.top + parseFloat(backgroundY); 591 } 592 593 var elementOffset = this.$el.offset(); 594 595 this.renderProgram.uniforms.topLeft = new Float32Array([ 596 (elementOffset.left - backgroundX) / backgroundWidth, 597 (elementOffset.top - backgroundY) / backgroundHeight 598 ]); 599 this.renderProgram.uniforms.bottomRight = new Float32Array([ 600 this.renderProgram.uniforms.topLeft[0] + this.$el.innerWidth() / backgroundWidth, 601 this.renderProgram.uniforms.topLeft[1] + this.$el.innerHeight() / backgroundHeight 602 ]); 603 604 var maxSide = Math.max(this.canvas.width, this.canvas.height); 605 606 this.renderProgram.uniforms.containerRatio = new Float32Array([ 607 this.canvas.width / maxSide, 608 this.canvas.height / maxSide 609 ]); 610 }, 611 612 initShaders: function() { 613 var vertexShader = [ 614 'attribute vec2 vertex;', 615 'varying vec2 coord;', 616 'void main() {', 617 'coord = vertex * 0.5 + 0.5;', 618 'gl_Position = vec4(vertex, 0.0, 1.0);', 619 '}' 620 ].join('\n'); 621 622 this.dropProgram = createProgram(vertexShader, [ 623 'precision highp float;', 624 625 'const float PI = 3.141592653589793;', 626 'uniform sampler2D texture;', 627 'uniform vec2 center;', 628 'uniform float radius;', 629 'uniform float strength;', 630 631 'varying vec2 coord;', 632 633 'void main() {', 634 'vec4 info = texture2D(texture, coord);', 635 636 'float drop = max(0.0, 1.0 - length(center * 0.5 + 0.5 - coord) / radius);', 637 'drop = 0.5 - cos(drop * PI) * 0.5;', 638 639 'info.r += drop * strength;', 640 641 'gl_FragColor = info;', 642 '}' 643 ].join('\n')); 644 645 this.updateProgram = createProgram(vertexShader, [ 646 'precision highp float;', 647 648 'uniform sampler2D texture;', 649 'uniform vec2 delta;', 650 651 'varying vec2 coord;', 652 653 'void main() {', 654 'vec4 info = texture2D(texture, coord);', 655 656 'vec2 dx = vec2(delta.x, 0.0);', 657 'vec2 dy = vec2(0.0, delta.y);', 658 659 'float average = (', 660 'texture2D(texture, coord - dx).r +', 661 'texture2D(texture, coord - dy).r +', 662 'texture2D(texture, coord + dx).r +', 663 'texture2D(texture, coord + dy).r', 664 ') * 0.25;', 665 666 'info.g += (average - info.r) * 2.0;', 667 'info.g *= 0.995;', 668 'info.r += info.g;', 669 670 'gl_FragColor = info;', 671 '}' 672 ].join('\n')); 673 gl.uniform2fv(this.updateProgram.locations.delta, this.textureDelta); 674 675 this.renderProgram = createProgram([ 676 'precision highp float;', 677 678 'attribute vec2 vertex;', 679 'uniform vec2 topLeft;', 680 'uniform vec2 bottomRight;', 681 'uniform vec2 containerRatio;', 682 'varying vec2 ripplesCoord;', 683 'varying vec2 backgroundCoord;', 684 'void main() {', 685 'backgroundCoord = mix(topLeft, bottomRight, vertex * 0.5 + 0.5);', 686 'backgroundCoord.y = 1.0 - backgroundCoord.y;', 687 'ripplesCoord = vec2(vertex.x, -vertex.y) * containerRatio * 0.5 + 0.5;', 688 'gl_Position = vec4(vertex.x, -vertex.y, 0.0, 1.0);', 689 '}' 690 ].join('\n'), [ 691 'precision highp float;', 692 693 'uniform sampler2D samplerBackground;', 694 'uniform sampler2D samplerRipples;', 695 'uniform vec2 delta;', 696 697 'uniform float perturbance;', 698 'varying vec2 ripplesCoord;', 699 'varying vec2 backgroundCoord;', 700 701 'void main() {', 702 'float height = texture2D(samplerRipples, ripplesCoord).r;', 703 'float heightX = texture2D(samplerRipples, vec2(ripplesCoord.x + delta.x, ripplesCoord.y)).r;', 704 'float heightY = texture2D(samplerRipples, vec2(ripplesCoord.x, ripplesCoord.y + delta.y)).r;', 705 'vec3 dx = vec3(delta.x, heightX - height, 0.0);', 706 'vec3 dy = vec3(0.0, heightY - height, delta.y);', 707 'vec2 offset = -normalize(cross(dy, dx)).xz;', 708 'float specular = pow(max(0.0, dot(offset, normalize(vec2(-0.6, 1.0)))), 4.0);', 709 'gl_FragColor = texture2D(samplerBackground, backgroundCoord + offset * perturbance) + specular;', 710 '}' 711 ].join('\n')); 712 gl.uniform2fv(this.renderProgram.locations.delta, this.textureDelta); 713 }, 714 715 initTexture: function() { 716 this.backgroundTexture = gl.createTexture(); 717 gl.bindTexture(gl.TEXTURE_2D, this.backgroundTexture); 718 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); 719 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR); 720 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); 721 }, 722 723 setTransparentTexture: function() { 724 gl.bindTexture(gl.TEXTURE_2D, this.backgroundTexture); 725 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, transparentPixels); 726 }, 727 728 hideCssBackground: function() { 729 730 // Check whether we're changing inline CSS or overriding a global CSS rule. 731 var inlineCss = this.$el[0].style.backgroundImage; 732 733 if (inlineCss == 'none') { 734 return; 735 } 736 737 this.originalInlineCss = inlineCss; 738 739 this.originalCssBackgroundImage = this.$el.css('backgroundImage'); 740 this.$el.css('backgroundImage', 'none'); 741 }, 742 743 restoreCssBackground: function() { 744 745 // Restore background by either changing the inline CSS rule to what it was, or 746 // simply remove the inline CSS rule if it never was inlined. 747 this.$el.css('backgroundImage', this.originalInlineCss || ''); 748 }, 749 750 dropAtPointer: function(pointer, radius, strength) { 751 var borderLeft = parseInt(this.$el.css('border-left-width')) || 0, 752 borderTop = parseInt(this.$el.css('border-top-width')) || 0; 753 754 this.drop( 755 pointer.pageX - this.$el.offset().left - borderLeft, 756 pointer.pageY - this.$el.offset().top - borderTop, 757 radius, 758 strength 759 ); 760 }, 761 762 /** 763 * Public methods 764 */ 765 drop: function(x, y, radius, strength) { 766 gl = this.context; 767 768 var elWidth = this.$el.innerWidth(); 769 var elHeight = this.$el.innerHeight(); 770 var longestSide = Math.max(elWidth, elHeight); 771 772 radius = radius / longestSide; 773 774 var dropPosition = new Float32Array([ 775 (2 * x - elWidth) / longestSide, 776 (elHeight - 2 * y) / longestSide 777 ]); 778 779 gl.viewport(0, 0, this.resolution, this.resolution); 780 781 gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffers[this.bufferWriteIndex]); 782 bindTexture(this.textures[this.bufferReadIndex]); 783 784 gl.useProgram(this.dropProgram.id); 785 gl.uniform2fv(this.dropProgram.locations.center, dropPosition); 786 gl.uniform1f(this.dropProgram.locations.radius, radius); 787 gl.uniform1f(this.dropProgram.locations.strength, strength); 788 789 this.drawQuad(); 790 791 this.swapBufferIndices(); 792 }, 793 794 updateSize: function() { 795 var newWidth = this.$el.innerWidth(), 796 newHeight = this.$el.innerHeight(); 797 798 if (newWidth != this.canvas.width || newHeight != this.canvas.height) { 799 this.canvas.width = newWidth; 800 this.canvas.height = newHeight; 801 } 802 }, 803 804 destroy: function() { 805 this.$el 806 .off('.ripples') 807 .removeClass('jquery-ripples') 808 .removeData('ripples'); 809 810 this.$canvas.remove(); 811 this.restoreCssBackground(); 812 813 this.destroyed = true; 814 }, 815 816 show: function() { 817 this.visible = true; 818 819 this.$canvas.show(); 820 this.hideCssBackground(); 821 }, 822 823 hide: function() { 824 this.visible = false; 825 826 this.$canvas.hide(); 827 this.restoreCssBackground(); 828 }, 829 830 pause: function() { 831 this.running = false; 832 }, 833 834 play: function() { 835 this.running = true; 836 }, 837 838 set: function(property, value) { 839 switch (property) { 840 case 'dropRadius': 841 case 'perturbance': 842 case 'interactive': 843 case 'crossOrigin': 844 this[property] = value; 845 break; 846 case 'imageUrl': 847 this.imageUrl = value; 848 this.loadImage(); 849 break; 850 } 851 } 852}; 853 854// RIPPLES PLUGIN DEFINITION 855// ========================== 856 857var old = $.fn.ripples; 858 859$.fn.ripples = function(option) { 860 if (!config) { 861 throw new Error('Your browser does not support WebGL, the OES_texture_float extension or rendering to floating point textures.'); 862 } 863 864 var args = (arguments.length > 1) ? Array.prototype.slice.call(arguments, 1) : undefined; 865 866 return this.each(function() { 867 var $this = $(this), 868 data = $this.data('ripples'), 869 options = $.extend({}, Ripples.DEFAULTS, $this.data(), typeof option == 'object' && option); 870 871 if (!data && typeof option == 'string') { 872 return; 873 } 874 if (!data) { 875 $this.data('ripples', (data = new Ripples(this, options))); 876 } 877 else if (typeof option == 'string') { 878 Ripples.prototype[option].apply(data, args); 879 } 880 }); 881}; 882 883$.fn.ripples.Constructor = Ripples; 884 885 886// RIPPLES NO CONFLICT 887// ==================== 888 889$.fn.ripples.noConflict = function() { 890 $.fn.ripples = old; 891 return this; 892}; 893 894})));
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.