audio-vis/js/sphere.js
VersusTune d1ae2059f7 WIP
2020-04-07 21:44:46 +02:00

211 lines
6.7 KiB
JavaScript

let sphereData = [];
Math.HALF_PI = Math.PI / 2;
Math.TWO_PI = Math.PI * 2;
let sphereObject = {
rotationRaw: [0, 0, 0], // degrees
rotation: [0, 0, 0], //radians
rotateInc: [0.0, 0.0, 0.0], //degreesInc
rotateByBeat: true,
translate: [0, 0, 0],
total: 50,
radius: 500,
color: {r: 0, g: 0, b: 0},
colorByBeat: true,
drawMode: 5,
sphereMode: 0,
lightPos: [0, 0, 0],
pointSize: 2,
steps: 512,
dirtyMode: false,
light: 0.3
}
function readDataBar() {
let items = sphereObject.steps;
let dataArray = new Uint8Array(items);
analyser.getByteFrequencyData(dataArray);
let arr = [];
let sum = 0;
for (let i = 0; i < items; i++) {
let data = dataArray[i] / 255;
arr.push(data * .5);
sum += dataArray[i];
}
return [arr, (sum / items) / 255];
}
let sphereDataVectors = [], lastTotal = 0;
// avoid garbage collection each run
function prepareData() {
let total = sphereObject.total;
if (lastTotal !== total) {
sphereDataVectors = [];
for (let i = 0; i <= total; i++) {
sphereDataVectors[i] = [];
for (let j = 0; j <= total; j++) {
sphereDataVectors[i][j] = new VTVector();
}
}
lastTotal = total;
}
}
function setupSphere() {
sphereData = [];
let data = readDataBar(),
radData = data[0],
map = VTUtils.map,
total = sphereObject.total,
cTotal = (total + 1) * (total + 1),
radius = sphereObject.radius,
rx = radius / c.width,
ry = radius / c.height,
counter = 0;
prepareData();
for (let i = 0; i <= total; i++) {
let lat = map(i, 0, total, 0, Math.PI, false);
for (let j = 0; j <= total; j++) {
let lon = map(j, 0, total, 0, Math.TWO_PI, false);
let rAdd = getAddRad(counter, radData, cTotal);
let realRX = rx + rAdd;
let realRY = ry + rAdd;
let {x, y, z} = sphereMode(lat, lon, i, counter, realRX, realRY);
if (sphereObject.drawMode < 2 || sphereObject.dirtyMode) {
sphereData.push(x, y, z);
} else {
sphereDataVectors[i][j].setXYZ(x, y, z);
}
counter++;
}
}
if (sphereObject.drawMode > 1 && !sphereObject.dirtyMode) {
for (let i = 0; i < total; i++) {
for (let j = 0; j <= total; j++) {
let cur = sphereDataVectors[i][j];
sphereData.push(cur.x, cur.y, cur.z);
cur = sphereDataVectors[i + 1][j];
sphereData.push(cur.x, cur.y, cur.z);
}
}
}
return [VTUtils.peakRGB(data[1] * 2), data[1]];
}
function getAddRad(counter, data, total) {
let mapping, rAdd, map = VTUtils.map;
let h = total / 2;
if (sphereObject.sphereMode === 3) {
if (counter > h) {
mapping = map(counter, h, total, data.length - 1, 0);
} else {
mapping = map(counter, 0, h, 0, data.length - 1);
}
rAdd = data[Math.round(mapping)] || 0;
} else if (sphereObject.sphereMode === 4) {
if (counter > h) {
mapping = map(counter, h, total, 0, data.length - 1);
} else {
mapping = map(counter, 0, h, data.length - 1, 0);
}
rAdd = data[Math.round(mapping)] || 0;
} else {
mapping = map(counter, 0, total, 0, data.length - 1);
rAdd = data[Math.round(mapping)] || 0;
}
return rAdd;
}
let position, color, rotate, light, lightPos;
function prepare(program) {
position = gl.getAttribLocation(program, "a_position");
color = gl.getUniformLocation(program, "u_color");
light = gl.getUniformLocation(program, "u_light");
rotate = gl.getUniformLocation(program, "u_matrix");
lightPos = gl.getUniformLocation(program, "u_lightPos");
let pointSize = gl.getUniformLocation(program, "u_pointSize");
gl.uniform3fv(light, [sphereObject.light, 0, 0]);
gl.uniform3fv(lightPos, sphereObject.lightPos);
gl.uniform1f(pointSize, sphereObject.pointSize);
}
function draw() {
c.width = window.innerWidth;
c.height = window.innerHeight;
let aspect = c.height / c.width;
let d = setupSphere();
let newColor = d[0];
let program = shaderHandler.getProgram("sphere");
gl.useProgram(program);
prepare(program);
let matrix = [
1 / aspect, 0, 0, 0,
0, 1, 0, 0,
0, 0, 1, 0,
sphereObject.translate[0], sphereObject.translate[1], sphereObject.translate[2], 1
]
matrix = TDUtils.multiply(matrix, TDUtils.xRotation(sphereObject.rotation[0]));
matrix = TDUtils.multiply(matrix, TDUtils.yRotation(sphereObject.rotation[1]));
matrix = TDUtils.multiply(matrix, TDUtils.zRotation(sphereObject.rotation[2]));
gl.uniformMatrix4fv(rotate, false, matrix);
let positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(sphereData), gl.DYNAMIC_DRAW);
let vao = gl.createVertexArray();
gl.bindVertexArray(vao);
gl.enableVertexAttribArray(position);
gl.vertexAttribPointer(position, 3, gl.FLOAT, true, 0, 0);
gl.clearColor(0, 0, 0, 1);
gl.enable(gl.DEPTH_TEST);
gl.depthFunc(gl.LEQUAL);
gl.clearDepth(2.0)
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
if (sphereObject.colorByBeat) {
gl.uniform4f(color, newColor.r, newColor.g, 0, 1);
} else {
let cx = sphereObject.color;
gl.uniform4f(color, cx.r, cx.g, cx.b, 1);
}
gl.drawArrays(sphereObject.drawMode || gl.POINTS, 0, sphereData.length / 3);
if (sphereObject.rotateByBeat) {
sphereObject.rotationRaw[1] += d[1];
sphereObject.rotationRaw[0] += newColor.r;
} else {
for (let i = 0; i < 3; i++) {
sphereObject.rotationRaw[i] += sphereObject.rotateInc[i];
}
}
for (let i = 0; i < 3; i++) {
sphereObject.rotation[i] = TDUtils.degToRad(sphereObject.rotationRaw[i])
}
requestAnimationFrame(draw);
}
function sphereMode(lat, lon, i, counter, rx, ry) {
let x, y, z,
sin = Math.sin,
cos = Math.cos;
switch (sphereObject.sphereMode) {
case 1:
x = rx * sin(lon) * cos(lat);
y = ry * sin(lon) * sin(lat);
z = ry * cos(lat);
break;
case 2:
x = rx * sin(lat) * cos(lat);
y = ry * sin(lat) * sin(lat);
z = ry * cos(lon);
break;
default:
x = rx * sin(lat) * cos(lon);
y = ry * sin(lat) * sin(lon);
z = ry * cos(lat);
break;
}
return {x: x, y: y, z: z};
}