211 lines
6.7 KiB
JavaScript
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};
|
|
} |