1/*************************************************************************** 2 * shaderback.js 3 * Shader-generated backgrounds for the web 4 * http://www.flypig.co.uk/shaderback 5 * 6 * David Llewellyn-Jones <[email protected]> 7 * Version 0.03 8 * 29th March 2015 9 * 10 * Copyright (c) 2015 David Llewellyn-Jones 11 * Released under the MIT license 12 * 13***************************************************************************/ 14 15/*************************************************************************** 16 * To use, just add the following uncommented code to your HTML header 17 * 18 * <script type="text/javascript" src="shaderback.js"></script> 19 * <script type="text/javascript"> 20 * window.onload = shaderback.loadURL("shader.txt")); 21 * </script> 22 * 23 * Where shader.txt is the URL of your fragment shader 24 * 25 * You can also use loaddiv and loadtext rather than loadURL if your shader 26 * code is contained inside a script element or text variable respectively. 27 * 28***************************************************************************/ 29 30var shaderback = (function () { 31 "use strict"; 32 33 var canvas; 34 var gl; 35 var shaderProgram; 36 var squareVertexPositionBuffer; 37 var squareVertexTextureCoordBuffer; 38 var pixelScale = 2.0; 39 var running = false; 40 var debug = false; 41 42 // Vertex shader code 43 var vsCode = "\n" 44 + " precision highp float;\n" 45 + "\n" 46 + " attribute vec3 aVertexPosition;\n" 47 + " attribute vec2 aTextureCoord;\n" 48 + "\n" 49 + " uniform vec3 iResolution;\n" 50 + " varying vec2 fragCoord;\n" 51 + "\n" 52 + " void main(void) {\n" 53 + " fragCoord = aTextureCoord * iResolution.xy;\n"
54 + " gl_Position = vec4(aVertexPosition, 1.0);\n" 55 + " }\n" 56 + "\n"; 57 var fsCode; 58 59 // Fragment shader head for use with ShaderToy.com shaders 60 var vsShadertoyHead = "\n" 61 + " precision highp float;\n" 62 + "\n" 63 + " varying vec2 fragCoord;\n" 64 + " uniform vec3 iResolution;\n" 65 + " uniform float iGlobalTime;\n" 66 + " const vec2 iMouse = vec2(0.0, 0.0);\n" 67 + "\n" 68 + " void mainImage (out vec4 fragColor, in vec2 fragCoord);\n" 69 + "\n" 70 + " void main () {\n" 71 + " mainImage(gl_FragColor, fragCoord);\n" 72 + " gl_FragColor.a = 1.0;\n" 73 + " }\n" 74 + "\n"; 75 76 // Update dimensions on a resize event 77 function resize() { 78 var width = canvas.clientWidth / pixelScale; 79 var height = canvas.clientHeight / pixelScale; 80 if (canvas.width !== width || canvas.height !== height) { 81 canvas.width = width; 82 canvas.height = height; 83 canvas.style.height = window.innerHeight + "px"; 84 } 85 } 86 87 // Add the canvas covering the body element background 88 function ready() { 89 var success = true; 90 var div = document.createElement('div'); 91 div.innerHTML = '<canvas class="shaderback" id="shaderback" width="500px" height="500px" style="width: 100%; height: 100%; position: fixed; top: 0px; left: 0px; z-index: -1;"></canvas>'; 92 var elements = div.childNodes[0]; 93 document.getElementsByTagName('body')[0].appendChild(elements); 94 canvas = document.getElementById("shaderback"); 95 96 if (!canvas) { 97 success = false; 98 if (debug) { 99 alert("Canvas creation failed"); 100 } 101 } 102 103 return success; 104 } 105 106 // Initialise the OpenGL/WebGL canvas 107 function initGL(canvas) { 108 var success = true; 109 try { 110 gl = canvas.getContext("experimental-webgl"); 111 gl.getExtension("OES_standard_derivatives"); 112 gl.viewportWidth = canvas.width; 113 gl.viewportHeight = canvas.height; 114 } catch (ignore) { 115 if (debug) { 116 alert("No WebGL context"); 117 } 118 success = false; 119 } 120 121 return success; 122 } 123 124 // Compile the shader with the give text 125 // Type should be either gl.FRAGMENT_SHADER or gl.VERTEX_SHADER 126 function compileShader(str, type) { 127 var shader = gl.createShader(type); 128 129 gl.shaderSource(shader, str); 130 gl.compileShader(shader); 131 132 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { 133 if (debug) { 134 alert(gl.getShaderInfoLog(shader)); 135 } 136 shader = null; 137 } 138 139 return shader; 140 } 141 142 // Compile and link the shader and setup CPU accessible GPU variables 143 function initShaders() { 144 var success = true; 145 var fragmentShader = compileShader(fsCode, gl.FRAGMENT_SHADER); 146 var vertexShader = compileShader(vsCode, gl.VERTEX_SHADER); 147 148 if (fragmentShader) { 149 shaderProgram = gl.createProgram(); 150 gl.attachShader(shaderProgram, vertexShader); 151 gl.attachShader(shaderProgram, fragmentShader); 152 gl.linkProgram(shaderProgram); 153 } 154 155 if (fragmentShader && gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { 156 gl.useProgram(shaderProgram); 157 158 shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition"); 159 gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); 160 161 shaderProgram.textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord"); 162 gl.enableVertexAttribArray(shaderProgram.textureCoordAttribute); 163 164 shaderProgram.iGlobalTime = gl.getUniformLocation(shaderProgram, "iGlobalTime"); 165 shaderProgram.iResolution = gl.getUniformLocation(shaderProgram, "iResolution"); 166 167 shaderProgram.iScroll = gl.getUniformLocation(shaderProgram, "iScroll"); 168 } 169 else { 170 if (debug) { 171 alert("Could not initialise shaders"); 172 } 173 success = false; 174 } 175 176 return success; 177 } 178 179 // Initialise the OpenGL vertex and index buffers for the fullscreen rectangle 180 function initBuffers() { 181 var success = true; 182 squareVertexPositionBuffer = gl.createBuffer(); 183 gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); 184 var vertices = [ 185 1.0, 1.0, 0.0, 186 -1.0, 1.0, 0.0, 187 1.0, -1.0, 0.0, 188 -1.0, -1.0, 0.0 189 ]; 190 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); 191 squareVertexPositionBuffer.itemSize = 3; 192 squareVertexPositionBuffer.numItems = 4; 193 194 squareVertexTextureCoordBuffer = gl.createBuffer(); 195 gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexTextureCoordBuffer); 196 var textureCoords = [ 197 1.0, 1.0, 198 0.0, 1.0, 199 1.0, 0.0, 200 0.0, 0.0 201 ]; 202 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoords), gl.STATIC_DRAW); 203 squareVertexTextureCoordBuffer.itemSize = 2; 204 squareVertexTextureCoordBuffer.numItems = 4; 205 206 return success; 207 } 208 209 // Set a callback for window update events 210 window.requestAnimFrame = (function () { 211 return window.requestAnimationFrame || 212 window.webkitRequestAnimationFrame || 213 window.mozRequestAnimationFrame || 214 window.oRequestAnimationFrame || 215 window.msRequestAnimationFrame || 216 function (callback, element) { 217 window.setTimeout(callback, 1000 / 60); 218 }; 219 })(); 220 221 // Render the scene, to be called every frame update 222 function drawScene() { 223 var timeNow = new Date().valueOf() / 1000.0;
224 requestAnimFrame(drawScene); 225 226 gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); 227 gl.uniform1f(shaderProgram.iGlobalTime, timeNow % 18000); 228 229 gl.uniform3f(shaderProgram.iResolution, canvas.clientWidth, canvas.clientHeight, 1.0); 230 231 gl.uniform2f(shaderProgram.iScroll, window.scrollX / document.body.scrollWidth, window.scrollY / document.body.scrollHeight); 232 233 gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexPositionBuffer); 234 gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, squareVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); 235 236 gl.bindBuffer(gl.ARRAY_BUFFER, squareVertexTextureCoordBuffer); 237 gl.vertexAttribPointer(shaderProgram.textureCoordAttribute, squareVertexTextureCoordBuffer.itemSize, gl.FLOAT, false, 0, 0); 238 239 gl.drawArrays(gl.TRIANGLE_STRIP, 0, squareVertexPositionBuffer.numItems); 240 } 241 242 // Initialise the event listerners for window resizing 243 function initEvents() { 244 window.addEventListener('resize', function(event) { 245 resize(); 246 }); 247 248 return true; 249 } 250 251 // Set up the shader background 252 function start() { 253 if (!running) { 254 running = ready(); 255 resize(); 256 if (running) running = initGL(canvas); 257 if (running) running = initShaders(); 258 if (running) running = initBuffers(); 259 if (running) running = initEvents(); 260 if (running) drawScene(); 261 } 262 else { 263 running = initShaders(); 264 } 265 } 266 267 // Get the shader text from the script tag with the given ID 268 function getShaderScript(id) { 269 var shaderScript = document.getElementById(id); 270 if (!shaderScript) { 271 return null; 272 } 273 274 var str = ""; 275 var k = shaderScript.firstChild; 276 while (k) { 277 if (k.nodeType === 3) { 278 str += k.textContent; 279 } 280 k = k.nextSibling; 281 } 282 return str; 283 } 284 285 // Set whether or not to generate alerts on errors 286 // active - true to generate alerts, false otherwise 287 function setDebug(active) { 288 debug = active; 289 } 290 291 // Load a shader from a as the page background 292 // url - URI of shader code 293 function loadURL(url) { 294 if (url) { 295 var client = new XMLHttpRequest(); 296 client.open('GET', url); 297 client.overrideMimeType("text/plain; charset=x-user-defined"); 298 client.onloadend = function () { 299 fsCode = client.responseText; 300 start(); 301 }; 302 client.send(); 303 } 304 } 305 306 // Load the shader stored in a script tag as the page background 307 // id - id of the script tag containing the shader code 308 function loaddiv(id) { 309 fsCode = getShaderScript(id); 310 start(); 311 } 312 313 // Load the shader with code text as the page background 314 // text - shader code 315 function loadtext(text) { 316 fsCode = text; 317 start(); 318 } 319 320 // Load the ShaderToy.com shader as the page background 321 // shaderID - ShaderToy.com ID 322 function loadshadertoy(shaderID) { 323 if (shaderID) { 324 var client = new XMLHttpRequest(); 325 client.open('GET', "https://www.shadertoy.com/api/v1/shaders/" + shaderID + "?key=rdHKwN"); 326 client.onloadend = function () { 327 var obj = JSON.parse (client.responseText); 328 if (obj.Shader) { 329 fsCode = vsShadertoyHead + obj.Shader.renderpass[0].code; 330 start(); 331 } 332 else if (debug) { 333 alert ("Shadertoy error: " + (obj.Error ? obj.Error : "Unknown response")); 334 } 335 }; 336 client.send(); 337 } 338 } 339 340 // Externally exposed functions 341 return { 342 loadURL : loadURL, 343 loaddiv : loaddiv, 344 loadtext : loadtext, 345 loadshadertoy : loadshadertoy, 346 setDebug : setDebug 347 }; 348}()); 349
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.