mirror of
https://github.com/greggman/twgl.js.git
synced 2025-12-08 19:26:07 +00:00
224 lines
6.8 KiB
HTML
224 lines
6.8 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf8">
|
|
<!--
|
|
|
|
@license twgl.js Copyright (c) 2015, Gregg Tavares All Rights Reserved.
|
|
Available via the MIT license.
|
|
see: http://github.com/greggman/twgl.js for details
|
|
|
|
-->
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
|
|
<meta property="og:title" content="TWGL.js - dynamic-buffers" />
|
|
<meta property="og:type" content="website" />
|
|
<meta property="og:image" content="http://twgljs.org/examples/screenshots/dynamic-buffers.png" />
|
|
<meta property="og:description" content="TWGL.js - dynamic-buffers" />
|
|
<meta property="og:url" content="http://twgljs.org" />
|
|
|
|
<meta name="twitter:card" content="summary_large_image">
|
|
<meta name="twitter:site" content="@greggman">
|
|
<meta name="twitter:creator" content="@greggman">
|
|
<meta name="twitter:domain" content="twgljs.org">
|
|
<meta name="twitter:title" content="TWGL.js - dynamic-buffers">
|
|
<meta name="twitter:url" content="http://twgljs.org/examples/dynamic-buffers.html">
|
|
<meta name="twitter:description" content="TWGL.js - dynamic-buffers">
|
|
<meta name="twitter:image:src" content="http://twgljs.org/examples/screenshots/dynamic-buffers.png">
|
|
|
|
<link href="/resources/images/twgljs-icon.png" rel="shortcut icon" type="image/png">
|
|
|
|
<title>twgl.js - dynamic-buffers</title>
|
|
<style>
|
|
html, body {
|
|
margin: 0;
|
|
font-family: monospace;
|
|
height: 100%;
|
|
}
|
|
canvas {
|
|
display: block;
|
|
width: 100%;
|
|
height: 100%;
|
|
}
|
|
#b {
|
|
position: absolute;
|
|
top: 10px;
|
|
width: 100%;
|
|
text-align: center;
|
|
z-index: 2;
|
|
color: white;
|
|
}
|
|
a:visited, a:link, a:active {
|
|
color: white;
|
|
}
|
|
audio {
|
|
display: none;
|
|
}
|
|
#click, #load {
|
|
font-family: sans-serif;
|
|
position: absolute;
|
|
left: 0;
|
|
top: 0;
|
|
z-index: 2;
|
|
background-color: rgba(0,0,0,0.8);
|
|
width: 100%;
|
|
height: 100%;
|
|
display: flex;
|
|
display: -webkit-flex;
|
|
flex-flow: column;
|
|
-webkit-flex-flow: column;
|
|
justify-content: center;
|
|
align-content: center;
|
|
align-items: center;
|
|
-webkit-justify-content: center;
|
|
-webkit-align-content: center;
|
|
-webkit-align-items: center;
|
|
min-height: auto;
|
|
}
|
|
#click>div, #load>div {
|
|
font-size: 24pt;
|
|
color: white;
|
|
background-color: blue;
|
|
border-radius: 1em;
|
|
padding: 1em;
|
|
}
|
|
#load {
|
|
z-index: 3;
|
|
}
|
|
#load>div {
|
|
color: black;
|
|
background-color: red;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<canvas id="c"></canvas>
|
|
<div id="b">
|
|
<div><a href="http://twgljs.org">twgl.js - dynamic-buffers</a></div>
|
|
<div>music: <a href="http://youtu.be/eUX39M_0MJ8">DOCTOR VOX - Level Up</a></div>
|
|
</div>
|
|
<div id="click">
|
|
<div>tap to play</div>
|
|
</div>
|
|
<div id="load">
|
|
<div>loading...</div>
|
|
</div>
|
|
</body>
|
|
<script src="../3rdparty/audiostreamsource.min.js"></script>
|
|
<script type="module">
|
|
import * as twgl from '../dist/7.x/twgl-full.module.js';
|
|
|
|
/* global audioStreamSource */
|
|
|
|
// There's really no good way to tell which browsers fail.
|
|
// Right now Safari doesn't expose AudioContext (it's still webkitAudioContext)
|
|
// so my hope is whenever they get around to actually supporting the 3+ year old
|
|
// standard that things will actually work.
|
|
const shittyBrowser = window.AudioContext === undefined && /iPhone|iPad|iPod/.test(navigator.userAgent);
|
|
const context = new (window.AudioContext || window.webkitAudioContext)();
|
|
const analyser = context.createAnalyser();
|
|
|
|
twgl.setDefaults({attribPrefix: "a_"});
|
|
const gl = document.querySelector("#c").getContext("webgl");
|
|
|
|
const vs = `
|
|
attribute float a_spread;
|
|
attribute float a_height;
|
|
|
|
varying vec4 v_color;
|
|
|
|
vec3 hsv2rgb(vec3 c) {
|
|
c = vec3(c.x, clamp(c.yz, 0.0, 1.0));
|
|
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
|
|
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
|
|
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
|
}
|
|
|
|
void main() {
|
|
gl_Position = vec4(a_spread, a_height * 2.0 - 1.0, 0, 1);
|
|
v_color = vec4(hsv2rgb(vec3(a_spread * 0.5 + 0.5, a_height, 1)), 1);
|
|
}
|
|
`;
|
|
const fs = `
|
|
precision mediump float;
|
|
|
|
varying vec4 v_color;
|
|
void main() {
|
|
gl_FragColor = v_color;
|
|
}
|
|
`;
|
|
|
|
const programInfo = twgl.createProgramInfo(gl, [vs, fs]);
|
|
|
|
// If it's a shitty browser (like Safari) then we can't stream so we load
|
|
// a very lo-fi version of the song that has no frequencies above 11.5k
|
|
const numPoints = analyser.frequencyBinCount * (shittyBrowser ? 0.25 : 1) | 0;
|
|
const spreadArray = new Float32Array(numPoints);
|
|
const heightArray = new Uint8Array(numPoints);
|
|
for (let ii = 0; ii < numPoints; ++ii) {
|
|
spreadArray[ii] = ii / numPoints * 2 - 1; // make clip space positions
|
|
}
|
|
const arrays = {
|
|
spread: { data: spreadArray, numComponents: 1 },
|
|
height: { data: heightArray, numComponents: 1, drawType: gl.DYNAMIC_DRAW },
|
|
};
|
|
const bufferInfo = twgl.createBufferInfoFromArrays(gl, arrays);
|
|
|
|
function render() {
|
|
twgl.resizeCanvasToDisplaySize(gl.canvas);
|
|
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
|
|
|
|
gl.clearColor(0, 0, 0, 1);
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
|
|
gl.lineWidth(2);
|
|
|
|
gl.useProgram(programInfo.program);
|
|
|
|
analyser.getByteFrequencyData(heightArray);
|
|
twgl.setAttribInfoBufferFromArray(gl, bufferInfo.attribs.a_height, heightArray);
|
|
|
|
twgl.setBuffersAndAttributes(gl, programInfo, bufferInfo);
|
|
twgl.drawBufferInfo(gl, bufferInfo, gl.LINE_STRIP);
|
|
|
|
requestAnimationFrame(render);
|
|
}
|
|
requestAnimationFrame(render);
|
|
|
|
const clickElem = document.querySelector("#click");
|
|
const loadElem = document.querySelector("#load");
|
|
|
|
const streamSource = audioStreamSource.create({
|
|
context: context,
|
|
loop: true,
|
|
});
|
|
|
|
function startMusic() {
|
|
clickElem.style.display = "none";
|
|
streamSource.play();
|
|
context.resume().then(() => {
|
|
streamSource.play();
|
|
streamSource.getSource().connect(analyser);
|
|
analyser.connect(context.destination);
|
|
});
|
|
}
|
|
|
|
streamSource.on('error', function(e) {
|
|
console.error("audio error:", e); // eslint-disable-line
|
|
});
|
|
|
|
streamSource.on('newSource', function(/* source */) {
|
|
loadElem.style.display = "none";
|
|
clickElem.addEventListener('click', startMusic);
|
|
});
|
|
|
|
streamSource.setSource(
|
|
'sounds/DOCTOR VOX - Level Up.mp3',
|
|
'sounds/DOCTOR VOX - Level Up - for shitty browsers.mp3' // for shitty browsers like Safari on iOS
|
|
);
|
|
</script>
|
|
</html>
|
|
|
|
|
|
|
|
|