354 lines
11 KiB
JavaScript
354 lines
11 KiB
JavaScript
'use strict';
|
|
|
|
const cColors = new Float32Array([
|
|
0, 0, 0, 0, // 0:
|
|
0, 0, 1, 1, // 1: (Z) high impedance
|
|
|
|
0, 1, 0, 1, // 2: strong 0
|
|
0, 1, 1, 1, // 3: strong 1
|
|
1, 0, 0, 1, // 4: (x X) strong unknown
|
|
|
|
.5, 1, 1, 1, // 5: vec
|
|
1, 1, 0, 1, // 6: yellow
|
|
1, 0, 1, 1, // 7: strange purple
|
|
|
|
0, 1, 0, .5, // 8: (l L) weak 0
|
|
0, 1, 1, .5, // 9: (h H) weak 1
|
|
1, 0, 0, .5, // 10: (w W) weak unknown
|
|
|
|
0, 0, 0, 0, // 11:
|
|
0, 0, 0, 0, // 12:
|
|
0, 0, 0, 0, // 13:
|
|
0, 0, 0, 0, // 14:
|
|
0, 0, 0, 0 // 15:
|
|
]);
|
|
|
|
const cTilts = new Float32Array([ // 14
|
|
0, 0, // 0
|
|
1, -1, // 1
|
|
1, 0, // 2
|
|
1, 1, // 3
|
|
-1, -1, // 4
|
|
-1, 0, // 5
|
|
-1, 1 // 6
|
|
]);
|
|
|
|
const shaderer = (kind, src) => gl => {
|
|
const vShader = gl.createShader(gl[kind]);
|
|
gl.shaderSource(vShader, src);
|
|
gl.compileShader(vShader);
|
|
return vShader;
|
|
};
|
|
|
|
const vertexShaderScalar = shaderer('VERTEX_SHADER', `#version 300 es
|
|
in uvec3 pos;
|
|
out vec4 v_color;
|
|
uniform vec2 scale;
|
|
uniform vec2 offset;
|
|
uniform vec4 colors[16];
|
|
uniform vec2 tilts[7];
|
|
uniform float tilt;
|
|
void main() {
|
|
v_color = colors[pos.z];
|
|
vec2 node = tilts[pos.y];
|
|
gl_Position = vec4(
|
|
float(pos.x) * scale.x + offset.x + node[1] * tilt,
|
|
float(node[0]) * scale.y + offset.y,
|
|
1, 1
|
|
);
|
|
}
|
|
`);
|
|
|
|
const fragmentShader = shaderer('FRAGMENT_SHADER', `#version 300 es
|
|
precision mediump float;
|
|
in vec4 v_color;
|
|
out vec4 myOutputColor;
|
|
void main() {
|
|
myOutputColor = v_color;
|
|
}
|
|
`);
|
|
|
|
const initProgram = gl => {
|
|
const program = gl.createProgram();
|
|
gl.attachShader(program, vertexShaderScalar(gl));
|
|
gl.attachShader(program, fragmentShader(gl));
|
|
gl.linkProgram(program);
|
|
gl.useProgram(program);
|
|
|
|
return 'colors tilts scale offset tilt'
|
|
.split(/\s+/)
|
|
.reduce((res, name) => Object.assign(res, {
|
|
[name]: gl.getUniformLocation(program, name)
|
|
}), {
|
|
pos: gl.getAttribLocation(program, 'pos'),
|
|
gl
|
|
});
|
|
};
|
|
|
|
const bar = [
|
|
(f, t, a, b, c0, c1) => [].concat( // 0
|
|
(f === 1) ? [a, 2, c1] : [],
|
|
[a, 5, c0],
|
|
[b, 5, c0],
|
|
(t > 1) ? [b, 0, c0] : []
|
|
),
|
|
(f, t, a, b, c0, c1) => [].concat( // 1
|
|
(f === 0) ? [a, 5, c0] :
|
|
(f > 1) ? [a, 0, c0] : [],
|
|
[a, 2, c1],
|
|
[b, 2, c1],
|
|
(t > 1) ? [b, 0, c0] : []
|
|
),
|
|
(f, t, a, b, c0, c1) => [a, 0, c0, b, 0, c1] // 2 = Z
|
|
];
|
|
|
|
const brick = [
|
|
(f, t, a, b, c0, c1) => [].concat( // 0
|
|
(f === 0) ? [a, 5, c0] :
|
|
(f === 1) ? [a, 1, c1] : [],
|
|
[a, 6, c0],
|
|
(t === 0) ? [b, 5, c0] :
|
|
[b, 4, c0],
|
|
(t === 3) ? [b, 0, c0] : []
|
|
),
|
|
(f, t, a, b, c0, c1) => [].concat( // 1
|
|
(f === 0) ? [a, 4, c0, a, 3, c1] :
|
|
(f === 1) ? [a, 2, c1] :
|
|
(f === 2) ? [a, 3, c1] :
|
|
[a, 0, c0, a, 3, c1],
|
|
(t === 1) ? [b, 3, c1] :
|
|
[b, 1, c1],
|
|
(t === 3) ? [b, 0, c0] : []
|
|
),
|
|
(f, t, a, b, c0, c1) => [].concat( // 2
|
|
(f === 0) ? [a, 4, 0] :
|
|
(f === 1) ? [a, 1, 0] :
|
|
[a, 0, 0],
|
|
(t === 0) ? [b, 6, 0, b, 6, c0] :
|
|
(t === 1) ? [b, 3, 0, b, 3, c1, b, 4, c0] :
|
|
[b, 0, 0, b, 0, c0, b, 4, c0],
|
|
(f === 0) ? [a, 4, c0, a, 3, c1] :
|
|
(f === 1) ? [a, 6, c0, a, 1, c1] :
|
|
[a, 6, c0, a, 0, c0, a, 3, c1],
|
|
(t === 0) ? [b, 1, c1, b, 6, c0] :
|
|
(t === 1) ? [b, 3, c1] :
|
|
[b, 1, c1, b, 0, c0]
|
|
)
|
|
];
|
|
|
|
const wave2vertex = desc => {
|
|
Object.keys(desc.chango).map(ref => {
|
|
|
|
const chang = desc.chango[ref];
|
|
const { kind, wave } = chang;
|
|
|
|
// desc.view.map(lane => {
|
|
// if (!lane || lane.ref === undefined) { return; }
|
|
// const chang = desc.chango[lane.ref];
|
|
// if (chang === undefined) { return; }
|
|
// const {kind, wave} = chang;
|
|
// lane.kind = kind;
|
|
// lane.wave = wave;
|
|
|
|
if (kind === 'bit') {
|
|
const vertices = [];
|
|
const ilen = wave.length;
|
|
for (let i = 0; i < ilen; i++) {
|
|
const f = wave[(i === 0) ? 0 : (i - 1)];
|
|
const [tim, val] = wave[i];
|
|
const t = wave[(i === (ilen - 1)) ? i : (i + 1)];
|
|
const tt = (i === (ilen - 1)) ? desc.time : wave[i + 1][0];
|
|
|
|
switch (val) {
|
|
case 0: case 1: // 0 1
|
|
vertices.push(...bar[val](f[1], t[1], tim, tt, 2, 3));
|
|
break;
|
|
case 2: case 3: // x X
|
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 4, 4));
|
|
break;
|
|
case 4: case 5: // z Z
|
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 1, 1));
|
|
break;
|
|
case 6: case 7: // u U uninitialized
|
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 6, 6));
|
|
break;
|
|
case 8: case 9: // w W weak unknown
|
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 10, 10));
|
|
break;
|
|
case 10: case 11: // l L
|
|
vertices.push(...bar[0](f[1], t[1], tim, tt, 8, 9));
|
|
break;
|
|
case 12: case 13: // h H
|
|
vertices.push(...bar[1](f[1], t[1], tim, tt, 8, 9));
|
|
break;
|
|
default:
|
|
vertices.push(...bar[2](f[1], t[1], tim, tt, 7, 7));
|
|
// throw new Error('val is: ' + val);
|
|
}
|
|
}
|
|
|
|
chang.vertices = new Uint32Array(vertices); // Uint16Array // 16bit
|
|
|
|
// lane.vertices = new Uint16Array(vertices);
|
|
|
|
}
|
|
if (kind === 'vec') {
|
|
const vertices = [];
|
|
const ilen = wave.length;
|
|
for (let i = 0; i < ilen; i++) {
|
|
// const f = wave[(i === 0) ? 0 : (i - 1)];
|
|
const [tim, val, msk] = wave[i];
|
|
// const t = wave[(i === (ilen - 1)) ? i : (i + 1)];
|
|
const tt = (i === (ilen - 1)) ? desc.time : wave[i + 1][0];
|
|
|
|
if (val) {
|
|
if (msk) {
|
|
vertices.push(...brick[2](2, 2, tim, tt, 4, 4)); // x,z?
|
|
} else {
|
|
// vertices.push(...brick[2](2, 2, tim, tt, 5, 5)); // 2
|
|
vertices.push(
|
|
tim, 0, 0,
|
|
tt, 0, 0, tt, 0, 5, tt, 4, 5,
|
|
tim, 6, 5, tim, 0, 5, tim, 3, 5,
|
|
tt, 1, 5, tt, 0, 5
|
|
);
|
|
}
|
|
} else {
|
|
if (msk) {
|
|
vertices.push(...brick[2](2, 2, tim, tt, 4, 4)); // x
|
|
} else {
|
|
// vertices.push(...brick[0](2, 2, tim, tt, 2, 3)); // 0
|
|
vertices.push(tim, 6, 2, tt, 4, 2);
|
|
}
|
|
}
|
|
}
|
|
|
|
chang.vertices = new Uint32Array(vertices); // Uint16Array // 16bit
|
|
|
|
// lane.vertices = new Uint16Array(vertices);
|
|
|
|
}
|
|
});
|
|
};
|
|
|
|
const initData = (loco, desc) => {
|
|
|
|
Object.keys(desc.chango).map(ref => {
|
|
|
|
const chang = desc.chango[ref];
|
|
const { vertices } = chang;
|
|
|
|
// desc.view.map(lane => {
|
|
// if (!lane) {
|
|
// return;
|
|
// }
|
|
// const vertices = desc.chango[lane.ref].vertices;
|
|
//
|
|
// if (!vertices) {
|
|
// return;
|
|
// }
|
|
|
|
// if (!lane || lane.vertices === undefined) {
|
|
// return;
|
|
// }
|
|
// const vertices = lane.vertices;
|
|
|
|
const gl = loco.gl;
|
|
const vertexBuffer = gl.createBuffer();
|
|
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
|
|
|
|
// 将初始化的顶点数据复制到 buffer 区域
|
|
gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW);
|
|
|
|
chang.vao = gl.createVertexArray();
|
|
gl.bindVertexArray(chang.vao);
|
|
gl.vertexAttribIPointer(
|
|
loco.pos,
|
|
3, // number of conponents (x, y, z)
|
|
gl.UNSIGNED_INT, // UNSIGNED_SHORT, // 16bit
|
|
0 /* stride */, 0 /* offset */
|
|
);
|
|
gl.enableVertexAttribArray(loco.pos);
|
|
|
|
gl.uniform4fv(loco.colors, cColors);
|
|
gl.uniform2fv(loco.tilts, cTilts);
|
|
});
|
|
};
|
|
|
|
const genRenderWavesGL = (els) => {
|
|
|
|
const canvas = document.createElement('canvas');
|
|
els.view0.replaceChildren(canvas);
|
|
// canvas.width = 1024;
|
|
// canvas.height = 1024;
|
|
// canvas.style = 'background-color: #111;';
|
|
const glProps = {
|
|
premultipliedAlpha: false,
|
|
alpha: true,
|
|
antialias: false,
|
|
depth: false
|
|
};
|
|
const gl = canvas.getContext('webgl2', glProps);
|
|
const loco = initProgram(gl);
|
|
|
|
return desc => {
|
|
wave2vertex(desc);
|
|
initData(loco, desc);
|
|
|
|
return (pstate, plugins) => {
|
|
let aReq;
|
|
return () => {
|
|
console.log('[wave render] render');
|
|
if (aReq !== undefined) {
|
|
cancelAnimationFrame(aReq);
|
|
}
|
|
aReq = window.requestAnimationFrame(() => {
|
|
const { width, height, xScale, xOffset, yOffset, yStep, yDuty } = pstate;
|
|
const cHeight = height - 40; // FIXME 40
|
|
// console.log(pstate);
|
|
canvas.width = width;
|
|
canvas.height = cHeight;
|
|
// const xs = pstate.scale;
|
|
// const xo = -1;
|
|
gl.uniform1f(loco.tilt, 3 / width);
|
|
gl.uniform2f(loco.scale, 2 * xScale / width, yStep * yDuty / cHeight); // FIXME 40
|
|
gl.viewport(0, 0, width, cHeight);
|
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
desc.view.map((lane, idx) => {
|
|
// console.log(lane, idx);
|
|
if (!lane) { // || lane.vertices === undefined) {
|
|
return;
|
|
}
|
|
const ref = lane.ref;
|
|
if (ref === undefined) {
|
|
return;
|
|
}
|
|
const chang = desc.chango[ref];
|
|
if (chang === undefined) {
|
|
return;
|
|
}
|
|
// console.log(chang);
|
|
gl.bindVertexArray(chang.vao);
|
|
gl.uniform2f(loco.offset,
|
|
(2 * xOffset / width) - 1,
|
|
(2 * yOffset - 2 * yStep * (idx + .7)) / cHeight + 1
|
|
);
|
|
gl.drawArrays(
|
|
gl.LINE_STRIP, // mode
|
|
0, // first
|
|
chang.vertices.length / 3 // count
|
|
);
|
|
});
|
|
plugins.map(fn => fn(desc, pstate, els));
|
|
aReq = undefined;
|
|
});
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
module.exports = genRenderWavesGL;
|
|
|
|
/* eslint-env browser */
|
|
/* eslint complexity: [1, 30] */
|