Skip to content

Instantly share code, notes, and snippets.

@seleb
Last active November 27, 2020 08:46
Show Gist options
  • Save seleb/147c065ab3dcbb294f83b9018240f972 to your computer and use it in GitHub Desktop.
Save seleb/147c065ab3dcbb294f83b9018240f972 to your computer and use it in GitHub Desktop.
🐦 gb webglazy snippet
const img = document.querySelector('img');
const size = [img.width, img.height];
const options = {
background: 'black',
scaleMode: 'MULTIPLES',
allowDownscaling: true,
disableFeedbackTexture: false,
scaleMultiplier: 8,
fragment: `
precision mediump float;
uniform sampler2D tex0;
uniform sampler2D tex1;
uniform float time;
uniform vec2 resolution;
const float PI = 3.14159;
vec2 uBufferSize = vec2(${size[0]}, ${size[1]});
//https://stackoverflow.com/questions/12964279/whats-the-origin-of-this-glsl-rand-one-liner
float rand(vec2 co){
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
vec3 tex(vec2 uv){
return texture2D(tex0, uv).rgb;
}
float vignette(vec2 uv, float amount){
uv*=2.0;
uv -= 1.0;
return clamp((1.0-uv.y*uv.y)*(1.0-uv.x*uv.x)/amount, 0.0, 1.0);
}
float grille(vec2 uv, vec2 amount){
vec2 g = mod(uv*uBufferSize,vec2(1.0));
g *= 2.0;
g -= 1.0;
g = abs(g);
g.x = 1.0 - g.x*amount.y;
g.y = 1.0 - g.y*amount.x;
return 1.0-pow(1.0-g.y*g.x,2.0);
}
void main(void){
vec2 uv = gl_FragCoord.xy / resolution;
vec2 puv = floor(uv * uBufferSize + vec2(.5)) / uBufferSize;
vec3 fg = tex(uv);
fg += rand(uv) * 0.05; // noise
// shade
vec2 uv2 = uv + vec2(-1.0, 1.0)/uBufferSize/3.0;
vec3 shade = vec3(0.0);//(fg - tex(uv2);
shade += (fg - tex(uv2 + vec2(-.0,1.0)/uBufferSize/4.0));
shade += (fg - tex(uv2 + vec2(1.0,-.0)/uBufferSize/4.0));
shade += (fg - tex(uv2 + vec2(-.0,-.0)/uBufferSize/4.0));
shade += (fg - tex(uv2 + vec2(1.0,1.0)/uBufferSize/4.0));
shade /= 4.0;
fg = fg - max(vec3(0.0), shade) * 0.5;
fg *= vec3(241.0,255.0,184.0)/255.0; // tint
fg = mix(fg, vec3(1.0), step(grille(uv, vec2(0.5,0.5)), 0.8)*0.1 * (1.0 - fg.g)); // grid
fg += rand(puv + 1.0 / 128.0) * 0.01; // grid noise
// burn
fg *= pow(vignette(uv,0.01), 3.0);
fg *= mix(vec3(0.9, 0.4, 0.1), vec3(1.0), pow(vignette(uv,0.14), 0.5)*0.5 + 0.5);
fg *= mix(vec3(0.4, 0.7, 0.1), vec3(1.0), pow(vignette(uv,0.18), 0.5)*0.5 + 0.5);
fg *= mix(vec3(1.0), vec3(0.3, 0.4, 0.1), vignette(uv,1.0)*0.3);
fg = mix(fg, texture2D(tex1, uv).rgb, fg.g*0.8);
gl_FragColor = vec4(fg.rgb, 1.0);
}`,
};
var WebGLazy=function(){"use strict";function t(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function e(t,e){for(var i=0;i<e.length;i++){var s=e[i];s.enumerable=s.enumerable||!1,s.configurable=!0,"value"in s&&(s.writable=!0),Object.defineProperty(t,s.key,s)}}function i(t,i,s){return i&&e(t.prototype,i),s&&e(t,s),t}function s(t){if(!s.context&&(s.context=t.getContext("webgl")||t.getContext("experimental-webgl"),!s.context))throw"No WebGL support";return s.context}var n=function(){function e(i,n){t(this,e),this.gl=new s,this.vertSource=i,this.fragSource=n,this.program=this.gl.createProgram();try{this.vertShader=this.compileShader(this.vertSource,this.gl.VERTEX_SHADER),this.fragShader=this.compileShader(this.fragSource,this.gl.FRAGMENT_SHADER)}catch(t){throw this.gl.deleteProgram(this.program),delete this.program,console.error("Couldn't create shader: ",t),t}this.gl.attachShader(this.program,this.vertShader),this.gl.deleteShader(this.vertShader),delete this.vertShader,this.gl.attachShader(this.program,this.fragShader),this.gl.deleteShader(this.fragShader),delete this.fragShader,this.gl.linkProgram(this.program)}return i(e,[{key:"compileShader",value:function(t,e){try{var i=this.gl.createShader(e);if(this.gl.shaderSource(i,t),this.gl.compileShader(i),!this.gl.getShaderParameter(i,this.gl.COMPILE_STATUS))throw this.gl.getShaderInfoLog(i);return i}catch(i){throw console.error("Couldn't compile shader (".concat(e,"): "),t,i),i}}},{key:"useProgram",value:function(){this.gl.useProgram(this.program)}}]),e}(),r=function(){function e(i,n,r){t(this,e),this.gl=new s,this.source=i,this.texture=this.gl.createTexture(),this.bind(n),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,this.source),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,!0),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MAG_FILTER,r?this.gl.NEAREST:this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_MIN_FILTER,r?this.gl.NEAREST:this.gl.LINEAR),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_S,this.gl.CLAMP_TO_EDGE),this.gl.texParameteri(this.gl.TEXTURE_2D,this.gl.TEXTURE_WRAP_T,this.gl.CLAMP_TO_EDGE),this.gl.bindTexture(this.gl.TEXTURE_2D,null)}return i(e,[{key:"update",value:function(){this.bind(),this.gl.pixelStorei(this.gl.UNPACK_FLIP_Y_WEBGL,!0),this.gl.texImage2D(this.gl.TEXTURE_2D,0,this.gl.RGBA,this.gl.RGBA,this.gl.UNSIGNED_BYTE,this.source),this.gl.bindTexture(this.gl.TEXTURE_2D,null)}},{key:"bind",value:function(t){var e=t||this.lastBoundId||0;this.gl.activeTexture(this.gl.TEXTURE0+e),this.gl.bindTexture(this.gl.TEXTURE_2D,this.texture),this.lastBoundId=e}}]),e}(),o=function(){function e(i){var s=this,n=i.source,r=i.sources,o=void 0===r?["canvas","video","img"]:r,a=i.hideSource,h=void 0===a||a,c=i.background,l=void 0===c?"black":c,u=i.scaleMultiplier,d=void 0===u?1:u,g=i.scaleMode,m=void 0===g?e.SCALE_MODES.FIT:g,v=i.allowDownscaling,f=void 0!==v&&v,p=i.timestep,E=void 0===p?1/60*1e3:p,T=i.disableFeedbackTexture,b=void 0!==T&&T,x=i.disableMouseEvents,y=void 0!==x&&x,w=i.pixelate,S=void 0===w||w,L=i.autoInit,_=void 0===L||L,A=i.vertex,R=void 0===A?"// default vertex shader\nattribute vec4 position;\nvoid main() {\n\tgl_Position = position;\n}":A,M=i.fragment,C=void 0===M?"// default fragment shader\nprecision mediump float;\nuniform sampler2D tex0;\nuniform sampler2D tex1;\nuniform vec2 resolution;\n\nvoid main() {\n\tvec2 coord = gl_FragCoord.xy;\n\tvec2 uv = coord.xy / resolution.xy;\n\tgl_FragColor = vec4(texture2D(tex0, uv).rgb, 1.0);\n}":M;t(this,e),this.main=function(t){s.lastTime=s.curTime,s.curTime=(t||s.now())-s.startTime,s.deltaTime=s.curTime-s.lastTime,s.accumulator+=s.deltaTime,s.accumulator>s.timestep&&(s.render(),s.accumulator-=s.timestep),s.requestAnimationFrame(s.main)},this.sources=o,this.source=n||this.getSource(),this.hideSource=h,this.background=l,this.scaleMultiplier=d,this._scale=d,this.scaleMode=m,this.allowDownscaling=f,this.timestep=E,this.disableFeedbackTexture=!!b,this.disableMouseEvents=!!y,this.pixelate=S,this.vertex=R,this.fragment=C,_&&this.init()}return i(e,[{key:"getSource",value:function(){var t,e=[];for(t=0;t<this.sources.length;++t)e.push(Array.prototype.slice.call(document.getElementsByTagName(this.sources[t])));if(0===(e=Array.prototype.concat.apply([],e)).length)throw"Couldn't find an element from "+this.sources+" to use as a source";return e[0]}},{key:"insertStylesheet",value:function(){this.style=document.createElement("style"),document.head.appendChild(this.style),this.style.innerHTML="\nhtml,body,div#canvasContainer{\n\tpadding:0;\n\tmargin:0;\n\n\twidth:100%;\n\theight:100%;\n\n\ttop:0;\n\tleft:0;\n\tright:0;\n\tbottom:0;\n\n\tbackground: ".concat(this.background,";\n\tcolor:#FFFFFF;\n\n\toverflow:hidden;\n\n\t").concat(this.hideSource?"visibility: hidden!important;":"","\n}\n\ncanvas#outputCanvas{\n").concat(this.pixelate?"\n\timage-rendering: optimizeSpeed;\n\timage-rendering: -webkit-crisp-edges;\n\timage-rendering: -moz-crisp-edges;\n\timage-rendering: -o-crisp-edges; \n\timage-rendering: crisp-edges;\n\timage-rendering: -webkit-optimize-contrast;\n\timage-rendering: optimize-contrast;\n\timage-rendering: pixelated;\n\t-ms-interpolation-mode: nearest-neighbor;\n":"","\n\n\tposition:absolute;\n\tmargin:auto;\n\ttop:0;\n\tleft:-1000%;\n\tright:-1000%;\n\tbottom:0;\n\n\t\t\t").concat(this.hideSource?" visibility: visible!important;":"","\n\t\t\t").concat(this.scaleMode===this.constructor.SCALE_MODES.MULTIPLES?"\n\ttransition:\n\t\twidth 0.2s cubic-bezier(0.22, 1.84, 0.88, 0.77),\n\t\theight 0.2s cubic-bezier(0.22, 1.84, 0.88, 0.77);":"","\n};")}},{key:"init",value:function(){this.size={x:this.source.width||this.source.style.width,y:this.source.height||this.source.style.height},this.size.x*=this.scaleMultiplier||1,this.size.y*=this.scaleMultiplier||1,this.ratio=this.size.x/this.size.y,this.insertStylesheet(),this.canvasContainer=document.createElement("div"),this.canvasContainer.id="canvasContainer",this.allowDownscaling||(this.canvasContainer.style.minWidth=this.size.x+"px",this.canvasContainer.style.minHeight=this.size.y+"px"),this.canvas=document.createElement("canvas"),this.canvas.id="outputCanvas",this.canvas.width=this.size.x,this.canvas.height=this.size.y,this.canvas.style.width=this.canvas.style.height=0,this.canvasContainer.appendChild(this.canvas),document.body.appendChild(this.canvasContainer);try{this.gl=new s(this.canvas),this.render=this.renderGL}catch(t){console.warn("Falling back to canvas rendering: ",t),this.render=this.renderCanvas,this.canvas2d=this.canvas.getContext("2d")}this.gl&&(this.shader=new n(this.vertex,this.fragment),this.vertices=new Float32Array([-1,-1,1,-1,-1,1,1,-1,1,1,-1,1]),this.vertexBuffer=this.gl.createBuffer(),this.gl.bindBuffer(this.gl.ARRAY_BUFFER,this.vertexBuffer),this.gl.bufferData(this.gl.ARRAY_BUFFER,this.vertices,this.gl.STATIC_DRAW),this.textureSource=new r(this.source,0,this.pixelate),this.disableFeedbackTexture||(this.textureFeedback=new r(this.canvas,1,this.pixelate)),this.glLocations={position:this.gl.getAttribLocation(this.shader.program,"position"),tex0:this.gl.getUniformLocation(this.shader.program,"tex0"),tex1:this.gl.getUniformLocation(this.shader.program,"tex1"),time:this.gl.getUniformLocation(this.shader.program,"time"),resolution:this.gl.getUniformLocation(this.shader.program,"resolution")},this.gl.enableVertexAttribArray(this.glLocations.position),this.gl.viewport(0,0,this.size.x,this.size.y),this.shader.useProgram(),this.gl.vertexAttribPointer(this.glLocations.position,2,this.gl.FLOAT,!1,0,0),this.gl.clearColor(0,0,0,1),this.gl.uniform1i(this.glLocations.tex0,0),this.gl.uniform1i(this.glLocations.tex1,1),this.gl.uniform2f(this.glLocations.resolution,this.size.x,this.size.y)),window.onresize=this.onResize.bind(this),window.onresize(),this.disableMouseEvents||(this.canvas.onmousedown=this.onMouseEvent.bind(this),this.canvas.onmouseup=this.onMouseEvent.bind(this),this.canvas.onmousemove=this.onMouseEvent.bind(this),this.canvas.onmouseenter=this.onMouseEvent.bind(this),this.canvas.onmouseexit=this.onMouseEvent.bind(this),this.canvas.onmouseover=this.onMouseEvent.bind(this),this.canvas.onmouseout=this.onMouseEvent.bind(this),this.canvas.onmouseleave=this.onMouseEvent.bind(this),this.canvas.onclick=this.onMouseEvent.bind(this),this.canvas.ondblclick=this.onMouseEvent.bind(this),this.canvas.oncontextmenu=this.onMouseEvent.bind(this),this.canvas.ontouchstart=this.onTouchEvent.bind(this),this.canvas.ontouchend=this.onTouchEvent.bind(this),this.canvas.ontouchmove=this.onTouchEvent.bind(this),this.canvas.touchcancel=this.onTouchEvent.bind(this)),this.accumulator=0,"performance"in window?this.now=function(){return window.performance.now()}:this.now=function(){return window.Date.now()},"requestAnimationFrame"in window?this.requestAnimationFrame=function(t){window.requestAnimationFrame(t)}:this.requestAnimationFrame=function(t){setTimeout(t,-1)},this.startTime=this.now(),this.curTime=this.lastTime=0,this.main(this.curTime)}},{key:"renderCanvas",value:function(){this.canvas2d.clearRect(0,0,this.size.x,this.size.y),this.canvas2d.drawImage(this.source,0,0)}},{key:"renderGL",value:function(){this.textureSource.update(),this.gl.uniform1f(this.glLocations.time,this.curTime),this.gl.clear(this.gl.COLOR_BUFFER_BIT|this.gl.DEPTH_BUFFER_BIT),this.shader.useProgram(),this.textureSource.bind(),this.disableFeedbackTexture||this.textureFeedback.bind(),this.gl.drawArrays(this.gl.TRIANGLES,0,this.vertices.length/2),this.disableFeedbackTexture||this.textureFeedback.update()}},{key:"onResize",value:function(){var t,e,i=this.canvasContainer.offsetWidth,s=this.canvasContainer.offsetHeight,n=i/s,r=this.constructor.SCALE_MODES,o=1;switch(n<this.ratio?s=Math.round(i/this.ratio):i=Math.round(s*this.ratio),this.scaleMode){case r.MULTIPLES:for(o=1,t=this.size.x,e=this.size.y;t+this.size.x<=i||e+this.size.y<=s;)t+=this.size.x,e+=this.size.y,o+=1;break;case r.FIT:t=i,e=s,o=i/this.size.x;break;case r.COVER:i=this.canvasContainer.offsetWidth,s=this.canvasContainer.offsetHeight,n<this.ratio?i=Math.round(s*this.ratio):s=Math.round(i/this.ratio),t=i,e=s,o=i/this.size.x;break;case r.NONE:o=1,t=this.size.x,e=this.size.y}this._scale=this.scaleMultiplier*o,this.canvas.style.width=t+"px",this.canvas.style.height=e+"px"}},{key:"onMouseEvent",value:function(t){var e=this.canvas,i=this.source,s=e.offsetLeft+e.scrollLeft,n=e.offsetTop+e.scrollTop,r=i.offsetLeft+i.scrollLeft,o=i.offsetTop+i.scrollTop,a=1/this._scale,h=new MouseEvent(t.type,{screenX:(t.screenX-s)*a+r,screenY:(t.screenY-n)*a+o,clientX:(t.clientX-s)*a+r,clientY:(t.clientY-n)*a+o,altKey:t.altKey,shiftKey:t.shiftKey,metaKey:t.metaKey,button:t.button,buttons:t.buttons,relatedTarget:t.relatedTarget,region:t.region});i.dispatchEvent(h)}},{key:"onTouchEvent",value:function(t){var e=this.canvas,i=this.source,s=e.offsetLeft+e.scrollLeft,n=e.offsetTop+e.scrollTop,r=i.offsetLeft+i.scrollLeft,o=i.offsetTop+i.scrollTop,a=1/this._scale,h=function(t){return new Touch({identifier:t.identifier,force:t.force,rotationAngle:t.rotationAngle,target:t.target,radiusX:t.radiusX,radiusY:t.radiusY,pageX:(t.pageX-s)*a+r,pageY:(t.pageY-s)*a+r,screenX:(t.screenX-s)*a+r,screenY:(t.screenY-n)*a+o,clientX:(t.clientX-s)*a+r,clientY:(t.clientY-n)*a+o})},c=Array.from(t.touches).map(h),l=Array.from(t.targetTouches).map(h),u=Array.from(t.changedTouches).map(h),d=new t.constructor(t.type,{touches:c,targetTouches:l,changedTouches:u,ctrlKey:t.ctrlKey,shiftKey:t.shiftKey,altKey:t.altKey,metaKey:t.metaKey});i.dispatchEvent(d)}}]),e}();return o.SCALE_MODES=Object.freeze({FIT:"FIT",COVER:"COVER",MULTIPLES:"MULTIPLES",NONE:"NONE"}),o}();
new WebGLazy(options);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment