moved js code to separate file

pull/5/head
Igor Null 2015-09-04 05:40:46 +00:00
rodzic ba7dc2371e
commit fa44ff469e
2 zmienionych plików z 524 dodań i 525 usunięć

507
all.js 100644
Wyświetl plik

@ -0,0 +1,507 @@
'use strict';
let libraryInfo = [
{
file: 'khrang.ogg',
author: 'Jerobeam Fenderson',
title: 'Khrậng',
link: 'https://www.youtube.com/watch?v=vAyCl4IHIz8',
swap: true,
},
{
file: 'oscillofun.ogg',
author: 'ATOM DELTA',
title: 'Oscillofun',
link: 'https://www.youtube.com/watch?v=o4YyI6_y6kw',
invert: true,
},
{
file: 'alpha_molecule.ogg',
author: 'Alexander Taylor',
title: 'The Alpha Molecule',
link: 'https://www.youtube.com/watch?v=XM8kYRS-cNk',
invert: true,
},
];
let libraryDict = {};
for (let e of libraryInfo) {
libraryDict[e.file] = e;
}
let query = parseq(location.search);
if (!query.file) {
query = libraryInfo[0];
}
let file = query.file;
let audioUrl = './' + file;
let swap = query.swap;
let invert = query.invert;
let audioCtx = new AudioContext();
let audioData = null;
let quadIndex = null;
let vertexIndex = null;
let nSamples = 4096;
let scratchBuffer = new Float32Array(nSamples*4);
let doBloom = false;
let frameBuffer = null;
let lineTexture = null;
let blurTexture = null;
let blurTexture2 = null;
let outQuadArray = null;
function axhr(url, callback, progress) {
let request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onprogress = progress;
request.onload = function() {
audioCtx.decodeAudioData(request.response, function(buffer) {
callback(buffer);
});
}
request.send();
}
window.onload = function() {
let canvas = $('c'),
gl = initGl(canvas);
updatePageInfo();
gl.lineShader = CreateShader(gl, getText('vsLine'), getText('fsLine'));
gl.blurShader = CreateShader(gl, getText('vsBlurTranspose'), getText('fsBlurTranspose'));
gl.outputShader = CreateShader(gl, getText('vsOutput'), getText('fsOutput'));
let loop = function() {
draw(gl);
requestAnimationFrame(loop);
}
axhr(audioUrl, function(buffer) {
$('htmlAudio').volume = 0.5;
$('htmlAudio').src = audioUrl;
$('htmlAudio').play();
quadIndex = makeQuadIndex(gl);
vertexIndex = makeVertexIndex(gl);
outQuadArray = makeOutQuad(gl);
{
let tmp = makeFrameBuffer(gl, canvas.width, canvas.height);
frameBuffer = tmp.frameBuffer;
lineTexture = tmp.lineTexture;
blurTexture = tmp.blurTexture;
blurTexture2 = tmp.blurTexture2;
}
audioData = prepareAudioData(gl, buffer);
loop();
}, function(e) {
console.log('progress: ' + e.loaded + ' / ' + e.total);
});
};
function parseq(search) {
search = search.replace(/^\?/, '');
let obj = {};
for (let pair of search.split('&')) {
pair = pair.split('=');
obj[decodeURIComponent(pair[0])] =
pair.length > 1 ? decodeURIComponent(pair[1]) : true;
}
return obj;
}
function dumpq(obj) {
return Object.keys(obj).map(function(key) {
if (obj[key] === true) {
return encodeURIComponent(key);
} else {
return encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]);
}
}).join('&');
}
function updatePageInfo() {
if (file in libraryDict) {
let info = libraryDict[file],
text = document.createTextNode(info.author + ' — ' + info.title + ' '),
songInfo = $('songInfo'),
a = document.createElement('a'),
linkText = document.createTextNode('[link]');
a.appendChild(linkText);
a.href = info.link;
songInfo.innerHTML = '';
songInfo.appendChild(text);
songInfo.appendChild(a);
}
let ul = $('playList');
ul.innerHTML = '';
for (let song of libraryInfo) {
let a = document.createElement('a'),
li = document.createElement('li');
a.appendChild(document.createTextNode(song.title));
let q = {file: song.file};
if (song.swap) { q.swap = true; }
if (song.invert) { q.invert = true; }
a.href = '?' + dumpq(q);
li.appendChild(a);
ul.appendChild(li);
}
}
function initGl(canvas) {
let gl = canvas.getContext('webgl');
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
return gl;
}
function CreateShader(gl, vsSource, fsSource) {
if (typeof WebGLRenderingContext !== 'function' ||
!(gl instanceof WebGLRenderingContext)) {
throw new Error('CreateShader: no WebGL context');
}
let vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, vsSource);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
let infoLog = gl.getShaderInfoLog(vs);
gl.deleteShader(vs);
throw new Error('CreateShader, vertex shader compilation:\n' + infoLog);
}
let fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, fsSource);
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
let infoLog = gl.getShaderInfoLog(fs);
gl.deleteShader(vs);
gl.deleteShader(fs);
throw new Error('CreateShader, fragment shader compilation:\n' + infoLog);
}
let program = gl.createProgram();
gl.attachShader(program, vs);
gl.deleteShader(vs);
gl.attachShader(program, fs);
gl.deleteShader(fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
let infoLog = gl.getProgramInfoLog(program);
gl.deleteProgram(program);
throw new Error('CreateShader, linking:\n' + infoLog);
}
return program;
};
function makeQuadIndex(gl) {
let index = new Int16Array(nSamples*2);
for (let i = index.length; i--; ) {
index[i] = i;
}
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, index, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return vbo;
}
function makeVertexIndex(gl) {
let len = (nSamples-1)*2*3,
index = new Uint16Array(len);
for (let i = 0, pos = 0; i < len; ) {
index[i++] = pos;
index[i++] = pos+2;
index[i++] = pos+1;
index[i++] = pos+1;
index[i++] = pos+2;
index[i++] = pos+3;
pos += 4;
}
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vbo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
return vbo;
}
function makeOutQuad(gl) {
let data = new Int16Array([
-1, -1, 0, 0,
-1, 1, 0, 1,
1, -1, 1, 0,
1, 1, 1, 1,
]);
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return vbo;
}
function makeTargetTexture(gl, width, height) {
let texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;
}
function makeFrameBuffer(gl, width, height) {
let frameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
frameBuffer.width = 1024;
frameBuffer.height = 1024;
gl.renderBuffer = gl.createRenderbuffer();
return {
frameBuffer: frameBuffer,
lineTexture: makeTargetTexture(gl, frameBuffer.width, frameBuffer.height),
blurTexture: makeTargetTexture(gl, frameBuffer.width, frameBuffer.height),
blurTexture2: makeTargetTexture(gl, frameBuffer.width, frameBuffer.height),
};
}
function prepareAudioData(gl, buffer) {
let left = buffer.getChannelData(0),
right = buffer.getChannelData(1);
if (swap) {
let tmp = left;
left = right;
right = tmp;
}
let vbo = gl.createBuffer();
return {
vbo: vbo,
left: left,
right: right,
};
}
function loadWaveAtPosition(gl, position) {
position += 1/120;
position = Math.floor(position*44100);
let end = Math.min(audioData.left.length, position+nSamples) - 1,
len = end - position;
let subArr = scratchBuffer,
left = audioData.left,
right = audioData.right;
for (let i = 0; i < len; i++) {
let t = i*8,
p = i+position;
subArr[t] = subArr[t+2] = subArr[t+4] = subArr[t+6] = left[p];
subArr[t+1] = subArr[t+3] = subArr[t+5] = subArr[t+7] = right[p];
}
gl.bindBuffer(gl.ARRAY_BUFFER, audioData.vbo);
gl.bufferData(gl.ARRAY_BUFFER, subArr, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
}
function $(id) { return document.getElementById(id); }
function getText(id) {
let c = $(id);
return c && c.firstChild && c.firstChild.data;
}
function activateTargetTexture(gl, texture) {
gl.bindRenderbuffer(gl.RENDERBUFFER, gl.renderBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, frameBuffer.width, frameBuffer.height);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, gl.renderBuffer);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
}
function draw(gl) {
loadWaveAtPosition(gl, $('htmlAudio').currentTime);
let width = 800,
height = 800;
if (!doBloom) {
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, width, height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
drawLine(gl, gl.lineShader);
} else {
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
activateTargetTexture(gl, lineTexture);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, width, height);
drawLine(gl, gl.lineShader);
{ // generate mipmap
gl.bindTexture(gl.TEXTURE_2D, lineTexture);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}
// downscale
activateTargetTexture(gl, blurTexture2);
gl.viewport(0, 0, width/2, height/2);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
drawTexture(gl, lineTexture, width, gl.outputShader);
// blur x
activateTargetTexture(gl, blurTexture);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
drawTexture(gl, blurTexture2, width/2, gl.blurShader);
// blur y
activateTargetTexture(gl, blurTexture2);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
drawTexture(gl, blurTexture, width/2, gl.blurShader);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, width, height);
drawTexture(gl, lineTexture, width, gl.outputShader);
drawTexture(gl, blurTexture2, width/2, gl.outputShader, 0.5);
}
}
function drawLine(gl, shader) {
gl.useProgram(shader);
{
let tmpPos = gl.getUniformLocation(shader, 'uInvert');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, (invert) ? -1 : 1);
}
tmpPos = gl.getUniformLocation(shader, 'uSize');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, 0.012);
}
tmpPos = gl.getUniformLocation(shader, 'uIntensity');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, 1);
}
}
let attribs = [];
{
gl.bindBuffer(gl.ARRAY_BUFFER, quadIndex);
let idxAttr = gl.getAttribLocation(shader, 'aIdx');
if (idxAttr > -1) {
gl.enableVertexAttribArray(idxAttr);
gl.vertexAttribPointer(idxAttr, 1, gl.SHORT, false, 2, 0);
attribs.push(idxAttr);
}
}
{
gl.bindBuffer(gl.ARRAY_BUFFER, audioData.vbo);
let tmpPos = gl.getAttribLocation(shader, 'aStart');
if (tmpPos > -1) {
gl.enableVertexAttribArray(tmpPos);
gl.vertexAttribPointer(tmpPos, 2, gl.FLOAT, false, 8, 0);
attribs.push(tmpPos);
}
tmpPos = gl.getAttribLocation(shader, 'aEnd');
if (tmpPos > -1) {
gl.enableVertexAttribArray(tmpPos);
gl.vertexAttribPointer(tmpPos, 2, gl.FLOAT, false, 8, 8*4);
attribs.push(tmpPos);
}
}
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndex);
gl.drawElements(gl.TRIANGLES, (nSamples-1)*2, gl.UNSIGNED_SHORT, 0);
gl.disable(gl.BLEND);
for (let a of attribs) {
gl.disableVertexAttribArray(a);
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.useProgram(null);
}
function drawTexture(gl, texture, size, shader, alpha) {
alpha = alpha || 1;
gl.useProgram(shader);
let attribs = [];
gl.bindBuffer(gl.ARRAY_BUFFER, outQuadArray);
{
let tmpPos = gl.getAttribLocation(shader, 'aPos');
if (tmpPos > -1) {
gl.enableVertexAttribArray(tmpPos);
gl.vertexAttribPointer(tmpPos, 2, gl.SHORT, false, 8, 0);
attribs.push(tmpPos);
}
tmpPos = gl.getAttribLocation(shader, 'aST');
if (tmpPos > -1) {
gl.enableVertexAttribArray(tmpPos);
gl.vertexAttribPointer(tmpPos, 2, gl.SHORT, false, 8, 4);
attribs.push(tmpPos);
}
}
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
{
let tmpPos = gl.getUniformLocation(shader, 'uTexture');
if (tmpPos && tmpPos !== -1) {
gl.uniform1i(tmpPos, 0);
}
tmpPos = gl.getUniformLocation(shader, 'uSize');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, size);
}
tmpPos = gl.getUniformLocation(shader, 'uAlpha');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, alpha);
}
}
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.SRC_ALPHA);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
for (let a of attribs) {
gl.disableVertexAttribArray(a);
}
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.useProgram(null);
}

Wyświetl plik

@ -12,513 +12,25 @@ ul { text-align: center; font-size: 20px; }
li { display: inline; margin: 0 10px 0 10px; }
a { color: #2d2; }
</style>
<script data-fix-firefox=true>
'use strict';
let libraryInfo = [
{
file: 'khrang.ogg',
author: 'Jerobeam Fenderson',
title: 'Khrậng',
link: 'https://www.youtube.com/watch?v=vAyCl4IHIz8',
swap: true,
},
{
file: 'oscillofun.ogg',
author: 'ATOM DELTA',
title: 'Oscillofun',
link: 'https://www.youtube.com/watch?v=o4YyI6_y6kw',
invert: true,
},
{
file: 'alpha_molecule.ogg',
author: 'Alexander Taylor',
title: 'The Alpha Molecule',
link: 'https://www.youtube.com/watch?v=XM8kYRS-cNk',
invert: true,
},
];
let libraryDict = {};
for (let e of libraryInfo) {
libraryDict[e.file] = e;
}
let query = parseq(location.search);
if (!query.file) {
query = libraryInfo[0];
}
let file = query.file;
let audioUrl = './' + file;
let swap = query.swap;
let invert = query.invert;
let audioCtx = new AudioContext();
let audioData = null;
let quadIndex = null;
let vertexIndex = null;
let nSamples = 4096;
let scratchBuffer = new Float32Array(nSamples*4);
let doBloom = false;
let frameBuffer = null;
let lineTexture = null;
let blurTexture = null;
let blurTexture2 = null;
let outQuadArray = null;
function axhr(url, callback, progress) {
let request = new XMLHttpRequest();
request.open('GET', url, true);
request.responseType = 'arraybuffer';
request.onprogress = progress;
request.onload = function() {
audioCtx.decodeAudioData(request.response, function(buffer) {
callback(buffer);
<script src="all.js" data-fix-firefox=true> </script>
<script>
// I refuse to replace `let` with `var`s
if (!('audioCtx' in window) && navigator.userAgent.match(/Firefox/)) {
document.addEventListener('DOMContentLoaded', function() {
console.log('Trying to re-evaluate scripts with js ver1.7 attribute')
var scripts = document.querySelectorAll('script[data-fix-firefox]');
[].forEach.call(scripts, function(s) {
document.head.removeChild(s);
var copy = document.createElement('script');
if (s.src) {
copy.src = s.src;
} else {
copy.innerHTML = s.innerHTML;
}
copy.setAttribute('type', 'application/javascript;version=1.7');
document.head.appendChild(copy);
});
}
request.send();
}
window.onload = function() {
let canvas = $('c'),
gl = initGl(canvas);
updatePageInfo();
gl.lineShader = CreateShader(gl, getText('vsLine'), getText('fsLine'));
gl.blurShader = CreateShader(gl, getText('vsBlurTranspose'), getText('fsBlurTranspose'));
gl.outputShader = CreateShader(gl, getText('vsOutput'), getText('fsOutput'));
let loop = function() {
draw(gl);
requestAnimationFrame(loop);
}
axhr(audioUrl, function(buffer) {
$('htmlAudio').volume = 0.5;
$('htmlAudio').src = audioUrl;
$('htmlAudio').play();
quadIndex = makeQuadIndex(gl);
vertexIndex = makeVertexIndex(gl);
outQuadArray = makeOutQuad(gl);
{
let tmp = makeFrameBuffer(gl, canvas.width, canvas.height);
frameBuffer = tmp.frameBuffer;
lineTexture = tmp.lineTexture;
blurTexture = tmp.blurTexture;
blurTexture2 = tmp.blurTexture2;
}
audioData = prepareAudioData(gl, buffer);
loop();
}, function(e) {
console.log('progress: ' + e.loaded + ' / ' + e.total);
});
};
function parseq(search) {
search = search.replace(/^\?/, '');
let obj = {};
for (let pair of search.split('&')) {
pair = pair.split('=');
obj[decodeURIComponent(pair[0])] =
pair.length > 1 ? decodeURIComponent(pair[1]) : true;
}
return obj;
}
function dumpq(obj) {
return Object.keys(obj).map(function(key) {
if (obj[key] === true) {
return encodeURIComponent(key);
} else {
return encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]);
}
}).join('&');
}
function updatePageInfo() {
if (file in libraryDict) {
let info = libraryDict[file],
text = document.createTextNode(info.author + ' — ' + info.title + ' '),
songInfo = $('songInfo'),
a = document.createElement('a'),
linkText = document.createTextNode('[link]');
a.appendChild(linkText);
a.href = info.link;
songInfo.innerHTML = '';
songInfo.appendChild(text);
songInfo.appendChild(a);
}
let ul = $('playList');
ul.innerHTML = '';
for (let song of libraryInfo) {
let a = document.createElement('a'),
li = document.createElement('li');
a.appendChild(document.createTextNode(song.title));
let q = {file: song.file};
if (song.swap) { q.swap = true; }
if (song.invert) { q.invert = true; }
a.href = '?' + dumpq(q);
li.appendChild(a);
ul.appendChild(li);
}
}
function initGl(canvas) {
let gl = canvas.getContext('webgl');
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
return gl;
}
function CreateShader(gl, vsSource, fsSource) {
if (typeof WebGLRenderingContext !== 'function' ||
!(gl instanceof WebGLRenderingContext)) {
throw new Error('CreateShader: no WebGL context');
}
let vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, vsSource);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
let infoLog = gl.getShaderInfoLog(vs);
gl.deleteShader(vs);
throw new Error('CreateShader, vertex shader compilation:\n' + infoLog);
}
let fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, fsSource);
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
let infoLog = gl.getShaderInfoLog(fs);
gl.deleteShader(vs);
gl.deleteShader(fs);
throw new Error('CreateShader, fragment shader compilation:\n' + infoLog);
}
let program = gl.createProgram();
gl.attachShader(program, vs);
gl.deleteShader(vs);
gl.attachShader(program, fs);
gl.deleteShader(fs);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
let infoLog = gl.getProgramInfoLog(program);
gl.deleteProgram(program);
throw new Error('CreateShader, linking:\n' + infoLog);
}
return program;
};
function makeQuadIndex(gl) {
let index = new Int16Array(nSamples*2);
for (let i = index.length; i--; ) {
index[i] = i;
}
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, index, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return vbo;
}
function makeVertexIndex(gl) {
let len = (nSamples-1)*2*3,
index = new Uint16Array(len);
for (let i = 0, pos = 0; i < len; ) {
index[i++] = pos;
index[i++] = pos+2;
index[i++] = pos+1;
index[i++] = pos+1;
index[i++] = pos+2;
index[i++] = pos+3;
pos += 4;
}
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vbo);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, index, gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
return vbo;
}
function makeOutQuad(gl) {
let data = new Int16Array([
-1, -1, 0, 0,
-1, 1, 0, 1,
1, -1, 1, 0,
1, 1, 1, 1,
]);
let vbo = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
return vbo;
}
function makeTargetTexture(gl, width, height) {
let texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.MIRRORED_REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.MIRRORED_REPEAT);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
return texture;
}
function makeFrameBuffer(gl, width, height) {
let frameBuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
frameBuffer.width = 1024;
frameBuffer.height = 1024;
gl.renderBuffer = gl.createRenderbuffer();
return {
frameBuffer: frameBuffer,
lineTexture: makeTargetTexture(gl, frameBuffer.width, frameBuffer.height),
blurTexture: makeTargetTexture(gl, frameBuffer.width, frameBuffer.height),
blurTexture2: makeTargetTexture(gl, frameBuffer.width, frameBuffer.height),
};
}
function prepareAudioData(gl, buffer) {
let left = buffer.getChannelData(0),
right = buffer.getChannelData(1);
if (swap) {
let tmp = left;
left = right;
right = tmp;
}
let vbo = gl.createBuffer();
return {
vbo: vbo,
left: left,
right: right,
};
}
function loadWaveAtPosition(gl, position) {
position += 1/120;
position = Math.floor(position*44100);
let end = Math.min(audioData.left.length, position+nSamples) - 1,
len = end - position;
let subArr = scratchBuffer,
left = audioData.left,
right = audioData.right;
for (let i = 0; i < len; i++) {
let t = i*8,
p = i+position;
subArr[t] = subArr[t+2] = subArr[t+4] = subArr[t+6] = left[p];
subArr[t+1] = subArr[t+3] = subArr[t+5] = subArr[t+7] = right[p];
}
gl.bindBuffer(gl.ARRAY_BUFFER, audioData.vbo);
gl.bufferData(gl.ARRAY_BUFFER, subArr, gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
}
function $(id) { return document.getElementById(id); }
function getText(id) {
let c = $(id);
return c && c.firstChild && c.firstChild.data;
}
function activateTargetTexture(gl, texture) {
gl.bindRenderbuffer(gl.RENDERBUFFER, gl.renderBuffer);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, frameBuffer.width, frameBuffer.height);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, gl.renderBuffer);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
}
function draw(gl) {
loadWaveAtPosition(gl, $('htmlAudio').currentTime);
let width = 800,
height = 800;
if (!doBloom) {
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, width, height);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
drawLine(gl, gl.lineShader);
} else {
gl.bindFramebuffer(gl.FRAMEBUFFER, frameBuffer);
activateTargetTexture(gl, lineTexture);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, width, height);
drawLine(gl, gl.lineShader);
{ // generate mipmap
gl.bindTexture(gl.TEXTURE_2D, lineTexture);
gl.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}
// downscale
activateTargetTexture(gl, blurTexture2);
gl.viewport(0, 0, width/2, height/2);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
drawTexture(gl, lineTexture, width, gl.outputShader);
// blur x
activateTargetTexture(gl, blurTexture);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
drawTexture(gl, blurTexture2, width/2, gl.blurShader);
// blur y
activateTargetTexture(gl, blurTexture2);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
drawTexture(gl, blurTexture, width/2, gl.blurShader);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, width, height);
drawTexture(gl, lineTexture, width, gl.outputShader);
drawTexture(gl, blurTexture2, width/2, gl.outputShader, 0.5);
}
}
function drawLine(gl, shader) {
gl.useProgram(shader);
{
let tmpPos = gl.getUniformLocation(shader, 'uInvert');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, (invert) ? -1 : 1);
}
tmpPos = gl.getUniformLocation(shader, 'uSize');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, 0.012);
}
tmpPos = gl.getUniformLocation(shader, 'uIntensity');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, 1);
}
}
let attribs = [];
{
gl.bindBuffer(gl.ARRAY_BUFFER, quadIndex);
let idxAttr = gl.getAttribLocation(shader, 'aIdx');
if (idxAttr > -1) {
gl.enableVertexAttribArray(idxAttr);
gl.vertexAttribPointer(idxAttr, 1, gl.SHORT, false, 2, 0);
attribs.push(idxAttr);
}
}
{
gl.bindBuffer(gl.ARRAY_BUFFER, audioData.vbo);
let tmpPos = gl.getAttribLocation(shader, 'aStart');
if (tmpPos > -1) {
gl.enableVertexAttribArray(tmpPos);
gl.vertexAttribPointer(tmpPos, 2, gl.FLOAT, false, 8, 0);
attribs.push(tmpPos);
}
tmpPos = gl.getAttribLocation(shader, 'aEnd');
if (tmpPos > -1) {
gl.enableVertexAttribArray(tmpPos);
gl.vertexAttribPointer(tmpPos, 2, gl.FLOAT, false, 8, 8*4);
attribs.push(tmpPos);
}
}
gl.enable(gl.BLEND);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, vertexIndex);
gl.drawElements(gl.TRIANGLES, (nSamples-1)*2, gl.UNSIGNED_SHORT, 0);
gl.disable(gl.BLEND);
for (let a of attribs) {
gl.disableVertexAttribArray(a);
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.useProgram(null);
}
function drawTexture(gl, texture, size, shader, alpha) {
alpha = alpha || 1;
gl.useProgram(shader);
let attribs = [];
gl.bindBuffer(gl.ARRAY_BUFFER, outQuadArray);
{
let tmpPos = gl.getAttribLocation(shader, 'aPos');
if (tmpPos > -1) {
gl.enableVertexAttribArray(tmpPos);
gl.vertexAttribPointer(tmpPos, 2, gl.SHORT, false, 8, 0);
attribs.push(tmpPos);
}
tmpPos = gl.getAttribLocation(shader, 'aST');
if (tmpPos > -1) {
gl.enableVertexAttribArray(tmpPos);
gl.vertexAttribPointer(tmpPos, 2, gl.SHORT, false, 8, 4);
attribs.push(tmpPos);
}
}
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture);
{
let tmpPos = gl.getUniformLocation(shader, 'uTexture');
if (tmpPos && tmpPos !== -1) {
gl.uniform1i(tmpPos, 0);
}
tmpPos = gl.getUniformLocation(shader, 'uSize');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, size);
}
tmpPos = gl.getUniformLocation(shader, 'uAlpha');
if (tmpPos && tmpPos !== -1) {
gl.uniform1f(tmpPos, alpha);
}
}
gl.enable(gl.BLEND);
gl.blendFunc(gl.ONE, gl.SRC_ALPHA);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
for (let a of attribs) {
gl.disableVertexAttribArray(a);
}
gl.bindBuffer(gl.ARRAY_BUFFER, null);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.useProgram(null);
}
</script>
<script language="x-shader/x-vertex" id="vsLine">
@ -595,26 +107,6 @@ void main (void)
float afterglow = smoothstep(0.0, 0.33, uvl.w/2048.0);
alpha *= afterglow * uIntensity;
gl_FragColor = vec4(1./32., 1.0, 1./32., alpha);
}
</script>
<script>
// I refuse to replace `let` with `var`s
if (!('audioCtx' in window) && navigator.userAgent.match(/Firefox/)) {
document.addEventListener('DOMContentLoaded', function() {
console.log('Trying to re-evaluate scripts with js ver1.7 attribute')
var scripts = document.querySelectorAll('script[data-fix-firefox]');
[].forEach.call(scripts, function(s) {
document.head.removeChild(s);
var copy = document.createElement('script');
if (s.src) {
copy.src = s.src;
} else {
copy.innerHTML = s.innerHTML;
}
copy.setAttribute('type', 'application/javascript;version=1.7');
document.head.appendChild(copy);
});
});
}
</script>
<script type="x-shader/x-vertex" id="vsOutput">