diff --git a/backup/drawline.js b/backup/drawline.js new file mode 100644 index 0000000..a0de98d --- /dev/null +++ b/backup/drawline.js @@ -0,0 +1,93 @@ +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] + ) +]; + + +// switch (val) { +// case 0: +// if (i === 0) { +// if (y1 === y2) { +// vertices.push( +// t1, y1ShiftIndex, renderParam1.color, 0, +// t1, y1ShiftIndex, renderParam1.color, 4 +// ); +// } +// } + +// break; +// case 1: // 0 1 +// vertices.push(...bar[val](f[1], t[1], t1, t2, 2, 3)); +// break; +// case 2: case 3: // x X +// vertices.push(...bar[2](f[1], t[1], t1, t2, 4, 4)); +// break; +// case 4: case 5: // z Z +// vertices.push(...bar[2](f[1], t[1], t1, t2, 1, 1)); +// break; +// case 6: case 7: // u U uninitialized +// vertices.push(...bar[2](f[1], t[1], t1, t2, 6, 6)); +// break; +// case 8: case 9: // w W weak unknown +// vertices.push(...bar[2](f[1], t[1], t1, t2, 10, 10)); +// break; +// case 10: case 11: // l L +// vertices.push(...bar[0](f[1], t[1], t1, t2, 8, 9)); +// break; +// case 12: case 13: // h H +// vertices.push(...bar[1](f[1], t[1], t1, t2, 8, 9)); +// break; +// default: +// vertices.push(...bar[2](f[1], t[1], t1, t2, 7, 7)); +// } \ No newline at end of file diff --git a/public/vcd.css b/public/vcd.css index 2fbc8d9..8bd3c58 100644 --- a/public/vcd.css +++ b/public/vcd.css @@ -7,6 +7,9 @@ --sidebar-width: 280px; --right-nav-width: 60px; --time-scale-height: 50px; + --sidebar-padding: 10px; + --vcd-render-padding: 24px; + /* 需要满足如下公式 --time-scale-height + --sidebar-padding = --vcd-render-padding + canvas预留 高度 */ --render-scale-x: 1; } diff --git a/src/App.vue b/src/App.vue index e62f431..3dd30de 100644 --- a/src/App.vue +++ b/src/App.vue @@ -57,7 +57,11 @@ export default { document.body.style.setProperty('--el-color-info-light-8', 'var(--vscode-focusBorder)'); document.body.style.setProperty('--el-bg-color-overlay', 'transplant'); // document.body.style.setProperty('--el-color-white', 'var(--background)'); - + + // 设置全局宏 + document.body.style.setProperty('--time-scale-height', '50px'); + document.body.style.setProperty('--sidebar-padding', '10px'); + document.body.style.setProperty('--vcd-render-padding', '24px'); // signal height document.body.style.setProperty('--display-signal-info-height', globalSetting.displaySignalHeight + 'px'); diff --git a/src/components/render/cursor.vue b/src/components/render/cursor.vue index 4046632..a00050f 100644 --- a/src/components/render/cursor.vue +++ b/src/components/render/cursor.vue @@ -59,7 +59,7 @@ export default { * @param { PointerEvent } event */ function makeCursor(event) { - console.log(event.x); + // console.log(event.x); showFixedOne.value = true; fixedLeft.value = event.x - boxShift; globalLookup.view.currentX = event.x - boxShift; diff --git a/src/components/render/index.vue b/src/components/render/index.vue index d7ca9a5..b20a5de 100644 --- a/src/components/render/index.vue +++ b/src/components/render/index.vue @@ -60,20 +60,20 @@ export default { .vcd-view { position: absolute; - top: 24px; - bottom: 24px; + top: var(--vcd-render-padding); + bottom: var(--vcd-render-padding); } .vcd-values { position: absolute; - top: 24px; - bottom: 24px; + top: var(--vcd-render-padding); + bottom: var(--vcd-render-padding); } .wd-waveql { position: absolute; - top: 24px; - bottom: 24px; + top: var(--vcd-render-padding); + bottom: var(--vcd-render-padding); width: 100%; transition: width .3s ease-out; } diff --git a/src/components/right-nav.vue b/src/components/right-nav.vue index cfcd1a3..03fe5dd 100644 --- a/src/components/right-nav.vue +++ b/src/components/right-nav.vue @@ -18,7 +18,7 @@
+ >
>} wave * @param {number} time */ -function findCurrentSignalValue(wave, time) { +function findCurrentSignalValue(kind, wave, time) { const times = wave.map(p => p[0]); // 二分查找,并将结果存入 i @@ -185,7 +195,7 @@ function findCurrentSignalValue(wave, time) { if (times[i] === time) { break; } - if (times[j] === time) { + if (times[j] <= time) { i = j; break; } @@ -200,8 +210,7 @@ function findCurrentSignalValue(wave, time) { } } - const value = getWireValueCaption(wave[i][1], wave[i][2]); - console.log(wave[i][1], wave[i][2]); + const value = getWireValueCaption(kind, wave[i][1], wave[i][2]); return value; } diff --git a/src/hook/wave-view/dom-container.js b/src/hook/wave-view/dom-container.js index 5334fe8..9d5b384 100644 --- a/src/hook/wave-view/dom-container.js +++ b/src/hook/wave-view/dom-container.js @@ -31,7 +31,7 @@ const mouseMoveHandler = (cursor, content, pstate /* , render */) => { const getFullView = desc => { - console.log(desc); + // console.log(desc); if (desc.waveql) { return; } diff --git a/src/hook/wave-view/gen-on-wheel.js b/src/hook/wave-view/gen-on-wheel.js index b4c9190..eb1e9f2 100644 --- a/src/hook/wave-view/gen-on-wheel.js +++ b/src/hook/wave-view/gen-on-wheel.js @@ -1,30 +1,38 @@ 'use strict'; const genOnWheel = (element, pstate, deso, keyBindo, plugins) => - event => { - const {deltaY} = event; - if (event.ctrlKey) { - const key = (deltaY < 0) - ? 'Ctrl+icon:scrollUp' - : ((deltaY > 0) ? 'Ctrl+icon:scrollDown' : 'nop'); - if (keyBindo[key].fn(pstate)) { - if (plugins != undefined) { - plugins.map(fn => fn(key, event)); + event => { + const { deltaX, deltaY } = event; + if (event.ctrlKey) { + const key = (deltaY < 0) + ? 'Ctrl+icon:scrollUp' + : ((deltaY > 0) ? 'Ctrl+icon:scrollDown' : 'nop'); + if (keyBindo[key].fn(pstate)) { + if (plugins != undefined) { + plugins.map(fn => fn(key, event)); + } + deso.render(); + } + event.preventDefault(); + } else if (event.shiftKey) { + const key = (deltaY < 0) ? 'Shift+icon:scrollUp' : ((deltaY > 0) ? 'Shift+icon:scrollDown' : 'nop'); + if (keyBindo[key].fn(pstate)) { + if (plugins != undefined) { + plugins.map(fn => fn(key, event)); + } + deso.render(); + } + event.preventDefault(); + } else if (deltaX !== 0 && deltaY === 0) { + const key = (deltaX < 0) ? 'icon:scrollLeft': 'icon:scrollRight'; + if (keyBindo[key].fn(pstate)) { + if (plugins != undefined) { + plugins.map(fn => fn(key, event)); + } + deso.render(); + } + event.preventDefault(); } - deso.render(); - } - event.preventDefault(); - } else - if (event.shiftKey) { - const key = (deltaY < 0) ? 'Shift+icon:scrollUp' : ((deltaY > 0) ? 'Shift+icon:scrollDown' : 'nop'); - if (keyBindo[key].fn(pstate)) { - if (plugins != undefined) { - plugins.map(fn => fn(key, event)); - } - deso.render(); - } - event.preventDefault(); - } - }; + }; module.exports = genOnWheel; diff --git a/src/hook/wave-view/gen-render-waves-gl.js b/src/hook/wave-view/gen-render-waves-gl.js index 239edbb..8a09552 100644 --- a/src/hook/wave-view/gen-render-waves-gl.js +++ b/src/hook/wave-view/gen-render-waves-gl.js @@ -1,29 +1,32 @@ 'use strict'; -const cColors = new Float32Array([ - 0, 0, 0, 0, // 0: - 0, 0, 1, 1, // 1: (Z) high impedance +// 控制颜色 +const gl_Colors = new Float32Array([ + 0, 0, 0, 0, // 0: 空 - 0.2, 0.847, 0.1, 1, // 2: strong 0 - 0.2, 0.847, 0.1, 1, // 3: strong 1 - 0.9, 0.2, 0.2, 1, // 4: (x X) strong unknown + 0, 0, 1, 1, // 1: 高阻态 Z + 0.2, 0.847, 0.1, 1, // 2: value = 0 用于 width = 1 的信号 + 0.2, 0.847, 0.1, 1, // 3: value = 1 用于 width = 1 的信号 + 0.9, 0.2, 0.2, 1, // 4: 未知态 X + .5, 1, 1, 1, // 5: vec 用于 width > 1 的信号 + + 1, 1, 0, 1, // 6: yellow + 1, 0, 1, 1, // 7: strange purple - .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, 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: + 0, 0, 1, 0.1, // 11: 高阻态 Z 遮罩 + 0.2, 0.847, 0.1, 0.1, // 12: value = 0 遮罩 + 0.2, 0.847, 0.1, 0.1, // 13: value = 1 遮罩 + 0.9, 0.2, 0.2, 0.1, // 14: 未知态 X 遮罩 + .5, 1, 1, 0.1 // 15: vec 遮罩 ]); -const cTilts = new Float32Array([ // 14 + +// 控制方向 +const gl_Shifts = new Float32Array([ // 14 0, 0, // 0 1, -1, // 1 1, 0, // 2 @@ -33,92 +36,79 @@ const cTilts = new Float32Array([ // 14 -1, 1 // 6 ]); -const shaderer = (kind, src) => webgl2 => { - const vShader = webgl2.createShader(webgl2[kind]); - webgl2.shaderSource(vShader, src); - webgl2.compileShader(vShader); - return vShader; -}; +const gl_Shifts_map = new Map(); +gl_Shifts_map.set(-1, 4); +gl_Shifts_map.set(0, 0); +gl_Shifts_map.set(1, 1); -const vertexShaderScalar = shaderer('VERTEX_SHADER', `#version 300 es -in uvec3 pos; +const lineWidth = 0.004; // 不能写为 0.0045 这样会因为插值造成不同线段的宽度不一致的问题 +const widthShift = lineWidth / 2; +const gl_WidthShifts = new Float32Array([ + 0, widthShift, // 0 + - widthShift, widthShift, // 1 + - widthShift, 0, // 2 + - widthShift, - widthShift, // 3 + 0, - widthShift, // 4 + widthShift, - widthShift, // 5 + widthShift, 0, // 6 + widthShift, widthShift // 7 +]); + + +class ShaderMaker { + /** + * + * @param {'VERTEX_SHADER' | 'FRAGMENT_SHADER'} type + * @param {string} source + */ + constructor(type, source) { + this.type = type; + this.source = source; + } + + /** + * @param {WebGL2RenderingContext} gl + * @return {WebGLShader} + */ + make(gl) { + const shader = gl.createShader(gl[this.type]); + gl.shaderSource(shader, this.source); + gl.compileShader(shader); + const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS); + if (!ok) { + console.log('创建类型为 ' + type + ' 的着色器失败!'); + } + return shader; + } +} + +const vertexShaderScalar = new ShaderMaker('VERTEX_SHADER', `#version 300 es +in uvec4 pos; out vec4 v_color; uniform vec2 scale; uniform vec2 offset; uniform vec4 colors[16]; -uniform vec2 tilts[7]; -uniform float tilt; +uniform vec2 shifts[7]; // 基础八位图偏移量,为了性能,pos 只传入整数,需要的坐标负数由该值提供 +uniform vec2 widthShifts[8]; // 用于构造线宽的偏移 + void main() { v_color = colors[pos.z]; - vec2 node = tilts[pos.y]; + vec2 shift = shifts[pos.y]; + vec2 widthShift = widthShifts[pos.w]; gl_Position = vec4( - float(pos.x) * scale.x + offset.x + node[1] * tilt, - float(node[0]) * scale.y + offset.y, + float(pos.x) * scale.x + offset.x + float(widthShift.x), + float(shift.x) * scale.y + offset.y + float(widthShift.y), 1, 1 ); -} -`); +}`); -const fragmentShader = shaderer('FRAGMENT_SHADER', `#version 300 es +const fragmentShader = new ShaderMaker('FRAGMENT_SHADER', `#version 300 es precision mediump float; in vec4 v_color; -out vec4 myOutputColor; +out vec4 outColor; void main() { - myOutputColor = v_color; -} -`); - - -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] - ) -]; + outColor = v_color; +}`); class WebGL2WaveRender { @@ -133,7 +123,8 @@ class WebGL2WaveRender { * chango: Record, - * vao: WebGLVertexArrayObject + * lineVao: WebGLVertexArrayObject + * maskVao: WebGLVertexArrayObject * }> * view: Array<{ ref: string }>, * currentWires: Set<{ @@ -167,47 +158,49 @@ class WebGL2WaveRender { this.pstate = pstate; this.plugins = plugins; - const webgl2 = canvas.getContext('webgl2', { + const gl = canvas.getContext('webgl2', { premultipliedAlpha: false, alpha: true, antialias: false, depth: false }); - this.webglLocation = this.initProgram(webgl2); - this.verticesMap = this.makeVertex(); - this.initData(); + this.webglLocation = this.initProgram(gl); + const { lineVerticesMap, maskVerticesMap } = this.makeVertex(); + this.lineVerticesMap = lineVerticesMap; + this.maskVerticesMap = maskVerticesMap; + this.initData(); this.animationHandler = undefined; } /** * - * @param {WebGL2RenderingContext} webgl2 + * @param {WebGL2RenderingContext} gl * @returns {{ * colors: WebGLUniformLocation, - * tilts: WebGLUniformLocation, + * shifts: WebGLUniformLocation, * scale: WebGLUniformLocation, * offset: WebGLUniformLocation, - * tilt: WebGLUniformLocation, * pos: number, - * webgl2: WebGL2RenderingContext + * widthShifts: WebGLUniformLocation, + * gl: WebGL2RenderingContext * }} */ - initProgram(webgl2) { - const program = webgl2.createProgram(); - webgl2.attachShader(program, vertexShaderScalar(webgl2)); - webgl2.attachShader(program, fragmentShader(webgl2)); - webgl2.linkProgram(program); - webgl2.useProgram(program); + initProgram(gl) { + const program = gl.createProgram(); + gl.attachShader(program, vertexShaderScalar.make(gl)); + gl.attachShader(program, fragmentShader.make(gl)); + gl.linkProgram(program); + gl.useProgram(program); const webglLocation = { - colors: webgl2.getUniformLocation(program, 'colors'), - tilts: webgl2.getUniformLocation(program, 'tilts'), - scale: webgl2.getUniformLocation(program, 'scale'), - offset: webgl2.getUniformLocation(program, 'offset'), - tilt: webgl2.getUniformLocation(program, 'tilt'), - pos: webgl2.getAttribLocation(program, 'pos'), - webgl2 + colors: gl.getUniformLocation(program, 'colors'), + shifts: gl.getUniformLocation(program, 'shifts'), + scale: gl.getUniformLocation(program, 'scale'), + offset: gl.getUniformLocation(program, 'offset'), + pos: gl.getAttribLocation(program, 'pos'), + widthShifts: gl.getUniformLocation(program, 'widthShifts'), + gl }; return webglLocation; @@ -215,68 +208,215 @@ class WebGL2WaveRender { /** * - * @returns {Map} + * @returns {{ + * lineVerticesMap: Map, + * maskVerticesMap: Map + * }} */ makeVertex() { const globalLookup = this.globalLookup; const time = globalLookup.time; - const verticesMap = new Map(); + const lineVerticesMap = new Map(); + const maskVerticesMap = new Map(); for (const id of Reflect.ownKeys(globalLookup.chango)) { const signalItem = globalLookup.chango[id]; const { kind, wave } = signalItem; if (kind === 'bit') { - const vertices = this.makeBitVertex(wave, time); - verticesMap.set(id, vertices); + const { lineVertices, maskVertices } = this.makeBitVertex(wave, time); + lineVerticesMap.set(id, lineVertices); + maskVerticesMap.set(id, maskVertices); } else if (kind === 'vec') { - const vertices = this.makeVecVertex(wave, time); - verticesMap.set(id, vertices); + // const vertices = this.makeVecVertex(wave, time); + // lineVerticesMap.set(id, vertices); + } + } + return { lineVerticesMap, maskVerticesMap }; + } + + + /** + * @description 将wave 的值转化为渲染需要用到的值 + * @param {*} value + * @return {{ + * y: number // 裁剪空间的纵坐标 + * color: number // 颜色的索引 颜色rgb = gl_Colors[color] + * }} + */ + translateValue2RenderParameter(value) { + switch (value) { + case 0: return { y: -1, color: 2 }; // 0 value + case 1: return { y: 1, color: 3 }; // 1 value + case 2: case 3: return { y: -1, color: 4 }; // 不定态 x + case 4: case 5: return { y: 0, color: 2 }; // 高阻态 z + default: return { y: -1, color: 7 }; // 其他,我也不知道还有啥 + } + } + + /** + * + * @param {{x: number, y: number, color: number} | undefined} p0 前一个点 + * @param {{x: number, y: number, color: number} | undefined} p1 当前的点 + * @param {{x: number, y: number, color: number} | undefined} p2 后一个点 + * @returns {number} 这是 widthshift 的索引,只需要 + 4 再 % 8 就能得到另一个 + */ + makeWidthShiftIndexByPoints(p0, p1, p2) { + if (p0 === undefined) { + if (p1.y === p2.y) { + return 0; + } else if (p1.x === p2.x) { + return 6; + } + } else if (p2 === undefined) { + if (p1.y === p0.y) { + return 0; + } else if (p1.x === p0.x) { + return 6; + } + } else { + if (p0.x !== p1.x && p0.y === p1.y && p1.x === p2.x && p1.y !== p2.y) { + if (p2.y > p1.y) { + return 1; + } else { + return 7; + } + } else if (p0.x === p1.x && p0.y !== p1.y && p1.x !== p2.x && p1.y === p2.y) { + if (p1.y > p0.y) { + return 1; + } else { + return 7; + } } } - return verticesMap; } /** * * @param {Array} wave * @param { number } time - * @returns {Uint32Array} + * @returns {{ + * lineVertices: Uint32Array + * maskVertices: Uint32Array + * }} */ - makeBitVertex(wave, time) { - 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)) ? 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)); + makeBitVertex(wave, time, debug = false) { + const length = wave.length; + // 先将节点数据转化为裁剪空间的坐标 + const perspectivePoints = []; + + for (let i = 0; i < length; ++ i) { + // const currentWave = wave[(i === 0) ? 0 : (i - 1)]; + const currentWave = wave[i]; + const nextWave = (i === (length - 1)) ? wave[i] : wave[i + 1]; + + const t1 = currentWave[0]; + const t2 = (i === (length - 1)) ? time : wave[i + 1][0]; + const value1 = currentWave[1]; + const value2 = nextWave[1]; + + const renderParam1 = this.translateValue2RenderParameter(value1); + const renderParam2 = this.translateValue2RenderParameter(value2); + + if (i === 0) { + perspectivePoints.push({ x: t1, y: renderParam1.y, color: renderParam1.color }); + perspectivePoints.push({ x: t2, y: renderParam1.y, color: renderParam1.color }); + } else { + const lastPoint = perspectivePoints.at(-1); + if ((lastPoint.y !== renderParam1.y) || (lastPoint.color !== renderParam1.color)) { + perspectivePoints.push({ x: t1, y: renderParam1.y, color: renderParam1.color }); + } + if ((renderParam1.y !== renderParam2.y) || (renderParam1.color !== renderParam2.color)) { + perspectivePoints.push({ x: t2, y: renderParam1.y, color: renderParam1.color }); + } } } - return new Uint32Array(vertices); + // 确保最后一个点延申到了 time + const lastPoint = perspectivePoints.at(-1); + if (lastPoint.x < time) { + perspectivePoints.push({ x: time, y: lastPoint.y, color: lastPoint.color }); + } + + // 计算出传入 shader 四元组数组 + // 四元组: (x, yshift_index, color_index, width_shift_index) + const pointNum = perspectivePoints.length; + const lineVertices = []; + const maskVertices = []; + + // const lineVertices = [ + // 0, 0, 2, 0, + // 10, 0, 2, 0, + // 10, 4, 2, 0, + // 20, 4, 2, 0, + // 20, 0, 2, 0, + // 30, 0, 2, 0, + // 30, 4, 2, 0 + // ]; + // return new Uint32Array(lineVertices); + + + // 制作 lineVertices + for (let i = 0; i < pointNum; ++ i) { + // p0: 上一个点 + // p1: 当前的点 + // p2: 下一个点 + const p0 = perspectivePoints[i - 1]; + const p1 = perspectivePoints[i]; + const p2 = perspectivePoints[i + 1]; + // p1.x, y1Index, p1.color, 0, + const y1Index = gl_Shifts_map.get(p1.y); + + const wsIndex = this.makeWidthShiftIndexByPoints(p0, p1, p2); + lineVertices.push( + p1.x, y1Index, p1.color, wsIndex, + p1.x, y1Index, p1.color, (wsIndex + 4) % 8 + ); + + // 防止颜色不同导致单个图元内出现两个颜色,这会引发shader的渐变 + if (p2 !== undefined && p1.color !== p2.color) { + lineVertices.push( + p1.x, y1Index, p2.color, wsIndex, + p1.x, y1Index, p2.color, (wsIndex + 4) % 8 + ); + } + } + + // 制作 maskVertices + for (let i = 0; i < pointNum; ++ i) { + const p1 = perspectivePoints[i]; + const p2 = perspectivePoints[i + 1]; + const p3 = perspectivePoints[i + 2]; + if (p1 === undefined || p2 === undefined || p3 === undefined) { + continue; + } + if (p2.y > p1.y) { + // 矩形的四个点 + // 四元组: (x, yshift_index, color_index, width_shift_index) + const r1 = [p1.x, gl_Shifts_map.get(p1.y), p2.color + 10, 4]; + const r2 = [p2.x, gl_Shifts_map.get(p2.y), p2.color + 10, 4]; + const r3 = [p3.x, gl_Shifts_map.get(p3.y), p2.color + 10, 4]; + const r4 = [p3.x, gl_Shifts_map.get(p1.y), p2.color + 10, 4]; + // 三角图元画矩形 + maskVertices.push( + ...r1, ...r2, ...r3, + ...r1, ...r3, ...r4, + ); + } + } + + + if (debug) { + console.log(perspectivePoints); + console.log(pointNum); + console.log(lineVertices); + } + + const Uint32lineVertices = new Uint32Array(lineVertices); + const Uint32maskVertices = new Uint32Array(maskVertices); + + return { + lineVertices : Uint32lineVertices, + maskVertices : Uint32maskVertices + }; } /** @@ -287,13 +427,24 @@ class WebGL2WaveRender { */ makeVecVertex(wave, time) { const vertices = []; - const ilen = wave.length; - for (let i = 0; i < ilen; i++) { + const length = wave.length; + for (let i = 0; i < length; ++ i) { const [t1, val, msk] = wave[i]; - const t2 = (i === (ilen - 1)) ? time : wave[i + 1][0]; + const t2 = (i === (length - 1)) ? time : wave[i + 1][0]; + // t1(val) --- t2(val) if (msk) { - vertices.push(...brick[2](2, 2, t1, t2, 4, 4)); // x,z? + vertices.push( + t1, 0, 0, + t2, 0, 0, + t2, 0, 4, + t2, 4, 4, + t1, 6, 4, + t1, 0, 4, + t1, 3, 4, + t2, 1, 4, + t2, 0, 4 + ); } else { vertices.push( t1, 0, 0, @@ -315,26 +466,48 @@ class WebGL2WaveRender { initData() { const webglLocation = this.webglLocation; - const webgl2 = webglLocation.webgl2; + const gl = webglLocation.gl; const globalLookup = this.globalLookup; - const verticesMap = this.verticesMap; + const lineVerticesMap = this.lineVerticesMap; + const maskVerticesMap = this.maskVerticesMap; for (const id of Reflect.ownKeys(globalLookup.chango)) { const signalItem = globalLookup.chango[id]; - const vertices = verticesMap.get(id); + + const lineVertices = lineVerticesMap.get(id); + if (lineVertices === undefined) { + // console.warn(`无法找到 link 为 ${id} 的顶点数据`); + continue; + } - const vertexBuffer = webgl2.createBuffer(); - webgl2.bindBuffer(webgl2.ARRAY_BUFFER, vertexBuffer); - // 将初始化的顶点数据复制到 buffer 区域 - webgl2.bufferData(webgl2.ARRAY_BUFFER, vertices, webgl2.STATIC_DRAW); - - signalItem.vao = webgl2.createVertexArray(); - webgl2.bindVertexArray(signalItem.vao); - webgl2.vertexAttribIPointer(webglLocation.pos, 3, webgl2.UNSIGNED_INT, 0, 0); - webgl2.enableVertexAttribArray(webglLocation.pos); - webgl2.uniform4fv(webglLocation.colors, cColors); - webgl2.uniform2fv(webglLocation.tilts, cTilts); + // 创建并设置 绘制wave轮廓 主体轮廓的 缓冲区、vao、顶点设置 + const lineVertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, lineVertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, lineVertices, gl.STATIC_DRAW); + signalItem.lineVao = gl.createVertexArray(); + gl.bindVertexArray(signalItem.lineVao); + gl.vertexAttribIPointer(webglLocation.pos, 4, gl.UNSIGNED_INT, 0, 0); + gl.enableVertexAttribArray(webglLocation.pos); + + + const maskVertices = maskVerticesMap.get(id); + if (maskVertices === undefined) { + continue; + } + + // 创建并设置 绘制wave半透明遮罩层 主体轮廓的 缓冲区、vao、顶点设置 + const maskVertexBuffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, maskVertexBuffer); + gl.bufferData(gl.ARRAY_BUFFER, maskVertices, gl.STATIC_DRAW); + signalItem.maskVao = gl.createVertexArray(); + gl.bindVertexArray(signalItem.maskVao); + gl.vertexAttribIPointer(webglLocation.pos, 4, gl.UNSIGNED_INT, 0, 0); + gl.enableVertexAttribArray(webglLocation.pos); } + + gl.uniform4fv(webglLocation.colors, gl_Colors); + gl.uniform2fv(webglLocation.widthShifts, gl_WidthShifts); + gl.uniform2fv(webglLocation.shifts, gl_Shifts); } render() { @@ -344,42 +517,74 @@ class WebGL2WaveRender { const canvas = this.canvas; const webglLocation = this.webglLocation; - const webgl2 = webglLocation.webgl2; + const gl = webglLocation.gl; const globalLookup = this.globalLookup; - const verticesMap = this.verticesMap; + const lineVerticesMap = this.lineVerticesMap; + const maskVerticesMap = this.maskVerticesMap; const elements = this.elements; + const timeScaleHeight = parseInt(document.body.style.getPropertyValue('--time-scale-height').match(/\d+/)[0]); + const sidebarPadding = parseInt(document.body.style.getPropertyValue('--sidebar-padding').match(/\d+/)[0]); + const vcdRenderPadding = parseInt(document.body.style.getPropertyValue('--vcd-render-padding').match(/\d+/)[0]); + const canvasPaddingTop = timeScaleHeight + sidebarPadding - vcdRenderPadding; + this.animationHandler = window.requestAnimationFrame(() => { const { width, height, xScale, xOffset, yOffset, yStep, yDuty } = this.pstate; - const canvasHeight = height - 40; - canvas.width = width; + const canvasHeight = height - canvasPaddingTop; + const canvasWidth = width; + + // 默认 1594 + canvas.width = canvasWidth; + + // 默认 1260 canvas.height = canvasHeight; - + // 设置 glsl 变量 - webgl2.uniform1f(webglLocation.tilt, 3 / width); - webgl2.uniform2f(webglLocation.scale, 2 * xScale / width, yStep * yDuty / canvasHeight); + gl.uniform2f(webglLocation.scale, + 2 * xScale / canvasWidth, + yStep * yDuty / canvasHeight + ); + console.log(yStep, yDuty, canvasHeight); // 设置 webgl 和 canvas 大小位置一致 - webgl2.viewport(0, 0, width, canvasHeight); + gl.viewport(0, 0, canvasWidth, canvasHeight); // 清楚颜色缓冲区,也就是删除上一次的渲染结果 - webgl2.clear(webgl2.COLOR_BUFFER_BIT); + gl.clear(gl.COLOR_BUFFER_BIT); + // 根据 globalLookup 当前激活的需要渲染的信号进行渲染 let index = 0; for (const signal of globalLookup.currentWires) { + const wave = globalLookup.chango[signal.link].wave; + // this.makeBitVertex(wave, globalLookup.time, true); const signalItem = globalLookup.chango[signal.link]; if (!signalItem) { return; } - webgl2.bindVertexArray(signalItem.vao); - webgl2.uniform2f(webglLocation.offset, + // TODO: 将此处的 offset 计算中的参数和 globalSetting 的数字形成关联 + gl.uniform2f(webglLocation.offset, (2 * xOffset / width) - 1, (2 * yOffset - 2 * yStep * (index + .7)) / canvasHeight + 1 ); - // 根据 vao 进行绘制 - const vertices = verticesMap.get(signal.link); - // console.log(vertices); - webgl2.drawArrays(webgl2.LINE_STRIP, 0, vertices.length / 3); + + + console.log('offset y', (2 * yOffset - 2 * yStep * (index + .7)) / canvasHeight + 1); + + // 根据 lineVao 进行绘制 + const lineVertices = lineVerticesMap.get(signal.link); + const maskVertices = maskVerticesMap.get(signal.link); + + if (signal.size === 1) { + // 如果是 width 为 1 的 + gl.bindVertexArray(signalItem.lineVao); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, lineVertices.length / 4); +`` + gl.bindVertexArray(signalItem.maskVao); + gl.drawArrays(gl.TRIANGLES, 0, maskVertices.length / 4); + } else { + // 如果是 width 大于 1 的 + gl.drawArrays(gl.LINE_STRIP, 0, lineVertices.length / 4); + } index ++; } diff --git a/src/hook/wave-view/gen-resize-handler.js b/src/hook/wave-view/gen-resize-handler.js index 954c0c5..7cd2cdf 100644 --- a/src/hook/wave-view/gen-resize-handler.js +++ b/src/hook/wave-view/gen-resize-handler.js @@ -18,12 +18,8 @@ const genResizeHandler = pstate => yOffset = yOffsetMax; } pstate.yOffset = yOffset; - // console.log('resize handler', pstate); - // X - // const xScaleMin = pstate.xScaleMin = (width - sidebarWidth) / time; + const xScaleMin = pstate.xScaleMin = 0.001; - console.log(width, sidebarWidth); - console.log('xScaleMin', xScaleMin); pstate.xScale = (xScale < xScaleMin) ? xScaleMin : xScale; xOffsetUpdate(pstate, xOffset); }; diff --git a/src/hook/wave-view/get-label.js b/src/hook/wave-view/get-label.js index c29d318..4e5abcb 100644 --- a/src/hook/wave-view/get-label.js +++ b/src/hook/wave-view/get-label.js @@ -11,7 +11,6 @@ const getLabel = (lane) => { const formatter = format(fmt, width); return (value, mask, x, w) => { - console.log(value, mask, x, w); if (mask) { if (value) { diff --git a/src/hook/wave-view/key-bindo.js b/src/hook/wave-view/key-bindo.js index b8b51e3..d674482 100644 --- a/src/hook/wave-view/key-bindo.js +++ b/src/hook/wave-view/key-bindo.js @@ -52,9 +52,8 @@ const editable = { module.exports = { // Alt + <, >. left / right - 'Alt+,': scroll.left, 'Shift+icon:scrollUp': scroll.left, - - 'Alt+.': scroll.right, 'Shift+icon:scrollDown': scroll.right, + 'Alt+,': scroll.left, + 'Alt+.': scroll.right, // Alt + [ ] home / end 'Alt+[': { desc: 'Jump to beginning of time', fn: pstate => xOffsetUpdate(pstate, pstate.sidebarWidth) }, // Home @@ -63,15 +62,18 @@ module.exports = { // ALT + - + 'Alt+=': pluso, // '+': pluso, '=': pluso, - 'Ctrl+icon:scrollUp': pluso, - 'Alt+-': minuso, // '-': minuso, '_': minuso, - 'Ctrl+icon:scrollDown': minuso, - 'Alt+0': fullo, // 'Shift+f': fullo, F: fullo, 'Shift+F': fullo, - 'Alt+/': editable, + // wheel + 'icon:scrollLeft': scroll.left, + 'icon:scrollRight': scroll.right, + 'Shift+icon:scrollUp': scroll.left, + 'Shift+icon:scrollDown': scroll.right, + 'Ctrl+icon:scrollUp': pluso, + 'Ctrl+icon:scrollDown': minuso, + // CAN'T DO: Alt + e, d, f, l // ArrowUp: scroll.up, 'Shift+ArrowUp': scroll.up, diff --git a/src/hook/wave-view/render-values.js b/src/hook/wave-view/render-values.js index 999d9d5..d7a0f83 100644 --- a/src/hook/wave-view/render-values.js +++ b/src/hook/wave-view/render-values.js @@ -91,7 +91,7 @@ function* renderValues(desc, pstate) { const [tCur, vCur, mCur] = (mark || [desc.time, 0, 0]); const xCur = getX(pstate, tCur); - console.log(mark, vPre, mPre, vCur, mCur); + // console.log(mark, vPre, mPre, vCur, mCur); if (vPre !== undefined || mPre !== undefined) { if (xPre > width && xCur > width) { // both time stamps to the right @@ -111,9 +111,7 @@ function* renderValues(desc, pstate) { } xPre = xCur; vPre = vCur; - console.log(mPre, mCur); mPre = mCur; - console.log(mPre, mCur); } } ml.push(mLane); diff --git a/src/hook/wave-view/water.js b/src/hook/wave-view/water.js index 5cf7359..1ac7b88 100644 --- a/src/hook/wave-view/water.js +++ b/src/hook/wave-view/water.js @@ -33,7 +33,7 @@ const progress = (lane, desc, pstate) => { if (desc.chango[clock.ref] === undefined) { - console.log(desc.chango, clock, clock.ref); + // console.log(desc.chango, clock, clock.ref); return pco; } const clockWave = desc.chango[clock.ref].wave; diff --git a/src/i18n/index.js b/src/i18n/index.js index e291d8e..1ef008b 100644 --- a/src/i18n/index.js +++ b/src/i18n/index.js @@ -6,6 +6,7 @@ import zh from './zh.json'; const i18n = createI18n({ legacy: false, locale: 'en', + warnHtmlMessage: false, messages: { en, zh } }); diff --git a/test/render-line/delaunator.min.js b/test/render-line/delaunator.min.js new file mode 100644 index 0000000..1f63da5 --- /dev/null +++ b/test/render-line/delaunator.min.js @@ -0,0 +1 @@ +!function(t,i){"object"==typeof exports&&"undefined"!=typeof module?module.exports=i():"function"==typeof define&&define.amd?define(i):(t="undefined"!=typeof globalThis?globalThis:t||self).Delaunator=i()}(this,(function(){"use strict";const t=134217729;function i(t,i,s,e,n){let h,r,l,o,a=i[0],f=e[0],c=0,u=0;f>a==f>-a?(h=a,a=i[++c]):(h=f,f=e[++u]);let _=0;if(ca==f>-a?(r=a+h,l=h-(r-a),a=i[++c]):(r=f+h,l=h-(r-f),f=e[++u]),h=r,0!==l&&(n[_++]=l);ca==f>-a?(r=h+a,o=r-h,l=h-(r-o)+(a-o),a=i[++c]):(r=h+f,o=r-h,l=h-(r-o)+(f-o),f=e[++u]),h=r,0!==l&&(n[_++]=l);for(;c0!=d>0)return g;const y=Math.abs(_+d);return Math.abs(g)>=33306690738754716e-32*y?g:-function(s,o,a,f,c,u,_){let d,g,y,w,b,A,k,M,p,x,S,T,z,U,m,K,L,v;const F=s-c,P=a-c,E=o-u,H=f-u;U=F*H,A=t*F,k=A-(A-F),M=F-k,A=t*H,p=A-(A-H),x=H-p,m=M*x-(U-k*p-M*p-k*x),K=E*P,A=t*E,k=A-(A-E),M=E-k,A=t*P,p=A-(A-P),x=P-p,L=M*x-(K-k*p-M*p-k*x),S=m-L,b=m-S,e[0]=m-(S+b)+(b-L),T=U+S,b=T-U,z=U-(T-b)+(S-b),S=z-K,b=z-S,e[1]=z-(S+b)+(b-K),v=T+S,b=v-T,e[2]=T-(v-b)+(S-b),e[3]=v;let I=function(t,i){let s=i[0];for(let e=1;e=N||-I>=N)return I;if(b=s-F,d=s-(F+b)+(b-c),b=a-P,y=a-(P+b)+(b-c),b=o-E,g=o-(E+b)+(b-u),b=f-H,w=f-(H+b)+(b-u),0===d&&0===g&&0===y&&0===w)return I;if(N=11093356479670487e-47*_+33306690738754706e-32*Math.abs(I),I+=F*w+H*d-(E*y+P*g),I>=N||-I>=N)return I;U=d*H,A=t*d,k=A-(A-d),M=d-k,A=t*H,p=A-(A-H),x=H-p,m=M*x-(U-k*p-M*p-k*x),K=g*P,A=t*g,k=A-(A-g),M=g-k,A=t*P,p=A-(A-P),x=P-p,L=M*x-(K-k*p-M*p-k*x),S=m-L,b=m-S,l[0]=m-(S+b)+(b-L),T=U+S,b=T-U,z=U-(T-b)+(S-b),S=z-K,b=z-S,l[1]=z-(S+b)+(b-K),v=T+S,b=v-T,l[2]=T-(v-b)+(S-b),l[3]=v;const j=i(4,e,4,l,n);U=F*w,A=t*F,k=A-(A-F),M=F-k,A=t*w,p=A-(A-w),x=w-p,m=M*x-(U-k*p-M*p-k*x),K=E*y,A=t*E,k=A-(A-E),M=E-k,A=t*y,p=A-(A-y),x=y-p,L=M*x-(K-k*p-M*p-k*x),S=m-L,b=m-S,l[0]=m-(S+b)+(b-L),T=U+S,b=T-U,z=U-(T-b)+(S-b),S=z-K,b=z-S,l[1]=z-(S+b)+(b-K),v=T+S,b=v-T,l[2]=T-(v-b)+(S-b),l[3]=v;const q=i(j,n,4,l,h);U=d*w,A=t*d,k=A-(A-d),M=d-k,A=t*w,p=A-(A-w),x=w-p,m=M*x-(U-k*p-M*p-k*x),K=g*y,A=t*g,k=A-(A-g),M=g-k,A=t*y,p=A-(A-y),x=y-p,L=M*x-(K-k*p-M*p-k*x),S=m-L,b=m-S,l[0]=m-(S+b)+(b-L),T=U+S,b=T-U,z=U-(T-b)+(S-b),S=z-K,b=z-S,l[1]=z-(S+b)+(b-K),v=T+S,b=v-T,l[2]=T-(v-b)+(S-b),l[3]=v;const D=i(q,h,4,l,r);return r[D-1]}(s,o,a,f,c,u,y)}const a=Math.pow(2,-52),f=new Uint32Array(512);class c{static from(t,i=w,s=b){const e=t.length,n=new Float64Array(2*e);for(let h=0;h>1;if(i>0&&"number"!=typeof t[0])throw new Error("Expected coords to contain numbers.");this.coords=t;const s=Math.max(2*i-5,0);this._triangles=new Uint32Array(3*s),this._halfedges=new Int32Array(3*s),this._hashSize=Math.ceil(Math.sqrt(i)),this._hullPrev=new Uint32Array(i),this._hullNext=new Uint32Array(i),this._hullTri=new Uint32Array(i),this._hullHash=new Int32Array(this._hashSize).fill(-1),this._ids=new Uint32Array(i),this._dists=new Float64Array(i),this.update()}update(){const{coords:t,_hullPrev:i,_hullNext:s,_hullTri:e,_hullHash:n}=this,h=t.length>>1;let r=1/0,l=1/0,f=-1/0,c=-1/0;for(let i=0;if&&(f=s),e>c&&(c=e),this._ids[i]=i}const _=(r+f)/2,y=(l+c)/2;let w,b,A,k=1/0;for(let i=0;i0&&(b=i,k=s)}let x=t[2*b],S=t[2*b+1],T=1/0;for(let i=0;ie&&(i[s++]=n,e=this._dists[n])}return this.hull=i.subarray(0,s),this.triangles=new Uint32Array(0),void(this.halfedges=new Uint32Array(0))}if(o(M,p,x,S,z,U)<0){const t=b,i=x,s=S;b=A,x=z,S=U,A=t,z=i,U=s}const m=function(t,i,s,e,n,h){const r=s-t,l=e-i,o=n-t,a=h-i,f=r*r+l*l,c=o*o+a*a,u=.5/(r*a-l*o);return{x:t+(a*f-l*c)*u,y:i+(r*c-o*f)*u}}(M,p,x,S,z,U);this._cx=m.x,this._cy=m.y;for(let i=0;i0&&Math.abs(c-h)<=a&&Math.abs(u-r)<=a)continue;if(h=c,r=u,f===w||f===b||f===A)continue;let _=0;for(let t=0,i=this._hashKey(c,u);t=0;)if(g=d,g===_){g=-1;break}if(-1===g)continue;let y=this._addTriangle(g,f,s[g],-1,-1,e[g]);e[f]=this._legalize(y+2),e[g]=y,K++;let k=s[g];for(;d=s[k],o(c,u,t[2*k],t[2*k+1],t[2*d],t[2*d+1])<0;)y=this._addTriangle(k,f,d,e[f],-1,e[k]),e[f]=this._legalize(y+2),s[k]=k,K--,k=d;if(g===_)for(;d=i[g],o(c,u,t[2*d],t[2*d+1],t[2*g],t[2*g+1])<0;)y=this._addTriangle(d,f,g,-1,e[g],e[d]),this._legalize(y+2),e[d]=y,s[g]=g,K--,g=d;this._hullStart=i[f]=g,s[g]=i[k]=f,s[f]=k,n[this._hashKey(c,u)]=f,n[this._hashKey(t[2*g],t[2*g+1])]=g}this.hull=new Uint32Array(K);for(let t=0,i=this._hullStart;t0?3-s:1+s)/4}(t-this._cx,i-this._cy)*this._hashSize)%this._hashSize}_legalize(t){const{_triangles:i,_halfedges:s,coords:e}=this;let n=0,h=0;for(;;){const r=s[t],l=t-t%3;if(h=l+(t+2)%3,-1===r){if(0===n)break;t=f[--n];continue}const o=r-r%3,a=l+(t+1)%3,c=o+(r+2)%3,u=i[h],d=i[t],g=i[a],y=i[c];if(_(e[2*u],e[2*u+1],e[2*d],e[2*d+1],e[2*g],e[2*g+1],e[2*y],e[2*y+1])){i[t]=y,i[r]=u;const e=s[c];if(-1===e){let i=this._hullStart;do{if(this._hullTri[i]===c){this._hullTri[i]=t;break}i=this._hullPrev[i]}while(i!==this._hullStart)}this._link(t,e),this._link(r,s[h]),this._link(h,c);const l=o+(r+1)%3;n=s&&i[t[r]]>h;)t[r+1]=t[r--];t[r+1]=e}else{let n=s+1,h=e;y(t,s+e>>1,n),i[t[s]]>i[t[e]]&&y(t,s,e),i[t[n]]>i[t[e]]&&y(t,n,e),i[t[s]]>i[t[n]]&&y(t,s,n);const r=t[n],l=i[r];for(;;){do{n++}while(i[t[n]]l);if(h=h-s?(g(t,i,n,e),g(t,i,s,h-1)):(g(t,i,s,h-1),g(t,i,n,e))}}function y(t,i,s){const e=t[i];t[i]=t[s],t[s]=e}function w(t){return t[0]}function b(t){return t[1]}return c})); diff --git a/test/render-line/fragment.shader.glsl b/test/render-line/fragment.shader.glsl new file mode 100644 index 0000000..5301de0 --- /dev/null +++ b/test/render-line/fragment.shader.glsl @@ -0,0 +1,9 @@ +#version 300 es + +precision mediump float; +uniform vec4 a_color; +out vec4 outColor; + +void main(){ + outColor = a_color; +} \ No newline at end of file diff --git a/test/render-line/index.html b/test/render-line/index.html new file mode 100644 index 0000000..fb16177 --- /dev/null +++ b/test/render-line/index.html @@ -0,0 +1,24 @@ + + + + + + Document + + + + + + + + + \ No newline at end of file diff --git a/test/render-line/main.js b/test/render-line/main.js new file mode 100644 index 0000000..00555e4 --- /dev/null +++ b/test/render-line/main.js @@ -0,0 +1,278 @@ +/** + * @description 创建着色器对象 + * @param {WebGL2RenderingContext} gl + * @param {'VERTEX_SHADER' | 'FRAGMENT_SHADER'} type + * @param {string} source + * @return { WebGLShader | undefined } + */ +function makeShader(gl, type, source) { + // 创建 shader + const shader = gl.createShader(gl[type]); + // 给 shader 提供 glsl 代码 + gl.shaderSource(shader, source); + // 编译 glsl 生成 shader + gl.compileShader(shader); + const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS) + // 如果成功,则返回 shader,否则返回 undefined + return ok ? shader : gl.deleteShader(shader); +} + + +/** + * + * @param {string} path + * @return {string} + */ +async function getSource(path) { + const response = await fetch(path); + const source = await response.text(); + return source; +} + + +window.onload = async () => { + const canvas = document.getElementById('canvas'); + const gl = canvas.getContext('webgl2'); + + if (!(gl instanceof WebGL2RenderingContext)) { + console.log('浏览器不支持 webgl2'); + return; + } + + const vertexSource = await getSource('./vertex.shader.glsl'); + const fragementSource = await getSource('./fragment.shader.glsl'); + const vertexShader = makeShader(gl, 'VERTEX_SHADER', vertexSource); + const fragmentShader = makeShader(gl, 'FRAGMENT_SHADER', fragementSource); + if (!vertexShader || !fragmentShader) { + console.log('着色器创建失败'); + return; + } + + const program = createProgram(gl, vertexShader, fragmentShader); + if (!program) { + console.log('着色程序创建失败'); + return; + } + + gl.viewport(0, 0, gl.canvas.width, gl.canvas.height); + gl.clearColor(0, 0, 0, 0); + gl.clear(gl.COLOR_BUFFER_BIT); + + const points = [ + 0, -0.5, + 0.5, -0.5, + ]; + + drawMask(gl, program, points, { width: 0.06 }); + drawLine2D(gl, program, points, { width: 0.06 }); +} + +function onTheSameLine(x0, y0, x1, y1, x2, y2) { + const slope1 = (x1 - x0) !== 0 ? (y1 - y0) / (x1 - x0) : Infinity; + const slope2 = (x2 - x0) !== 0 ? (y2 - y0) / (x2 - x0) : Infinity; + + return slope1 === slope2; +} + +function sgn(value) { + if (value === 0) return 0; + return value > 0 ? 1 : -1; +} + +/** + * + * @param {WebGL2RenderingContext} gl + * @param {WebGLProgram} program + * @param {number[]} points + * @param {{ + * width: number + * color: string + * }} config + */ +function drawLine2D(gl, program, points, config) { + const pointNum = points.length >> 1; + const w = config.width; + const shift = w / 2; + const positions = []; + for (let i = 0; i < pointNum; ++ i) { + const x1 = points[(i << 1)]; + const y1 = points[(i << 1) + 1]; + + if (i === 0) { + const x2 = points[((i + 1) << 1)]; + const y2 = points[((i + 1) << 1) + 1]; + if (y1 === y2) { + // console.log('enter i = 0'); + positions.push( + x1, y1 + shift, // v0 + x1, y1 - shift // v1 + ); + } else if (x1 === x2) { + positions.push( + x1 + shift, y1, // v1 + x1 - shift, y1, // v0 + ); + } + } else if (i === pointNum - 1) { + const x0 = points[((i - 1) << 1)]; + const y0 = points[((i - 1) << 1) + 1]; + if (y1 === y0) { + // console.log('enter i = pointNum - 1'); + positions.push( + x1, y1 + shift, // v0 + x1, y1 - shift // v1 + ); + } else if (x1 === x0) { + positions.push( + x1 + shift, y1, // v1 + x1 - shift, y1, // v0 + ); + } + } else { + const x0 = points[((i - 1) << 1)]; + const y0 = points[((i - 1) << 1) + 1]; + const x2 = points[((i + 1) << 1)]; + const y2 = points[((i + 1) << 1) + 1]; + + if (x0 !== x1 && y0 === y1 && x1 === x2 && y1 !== y2) { + const d = sgn(y2 - y1); + if (y2 > y1) { + positions.push( + x1 - shift, y1 + shift, + x1 + shift, y1 - shift + ); + } else { + positions.push( + x1 + shift, y1 + shift, + x1 - shift, y1 - shift, + ); + } + + } else if (x0 === x1 && y0 !== y1 && x1 !== x2 && y1 === y2) { + const d = sgn(y1 - y0); + if (y1 > y0) { + positions.push( + x1 - shift, y1 + shift, + x1 + shift, y1 - shift, + ); + } else { + positions.push( + x1 + shift, y1 + shift, + x1 - shift, y1 - shift, + ); + } + + } + } + } + + const positionFloat32 = new Float32Array(positions); + const buffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, positionFloat32, gl.STATIC_DRAW); + gl.useProgram(program); + const positionLocation = gl.getAttribLocation(program, 'a_position'); + const colorLocation = gl.getUniformLocation(program, 'a_color'); + gl.uniform4f(colorLocation, 0.4, 0.0, 1.0, 1.0); + gl.enableVertexAttribArray(positionLocation); + gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); + gl.drawArrays(gl.TRIANGLE_STRIP, 0, positionFloat32.length >> 1); +} + + + + +/** + * + * @param {WebGL2RenderingContext} gl + * @param {WebGLProgram} program + * @param {number[]} times + * @param {{ +* width: number +* color: string +* }} config +* @param {number} yshift +*/ +function drawBlock(gl, program, times, config, yshift) { + +} + +/** + * + * @param {WebGL2RenderingContext} gl + * @param {WebGLProgram} program + * @param {number[]} points + * @param {{ +* width: number +* color: string +* }} config +*/ +function drawMask(gl, program, points, config) { + const positions = []; + const pointNum = points.length >> 1; + const w = config.width; + const shift = w / 2; + for (let i = 0; i < pointNum; ++ i) { + const x1 = points[(i << 1)]; + const y1 = points[(i << 1) + 1]; + if (i + 1 < pointNum) { + const x2 = points[((i + 1) << 1)]; + const y2 = points[((i + 1) << 1) + 1]; + if (y2 > y1 && i + 2 < pointNum) { + const x3 = points[((i + 2) << 1)]; + const y3 = points[((i + 2) << 1) + 1]; + const p1 = [x1, y1 - shift]; + const p2 = [x2, y2 - shift]; + const p3 = [x3, y3 - shift]; + const p4 = [x3, y1 - shift]; + + positions.push( + ...p1, + ...p2, + ...p3, + ...p1, + ...p3, + ...p4 + ); + } + } + } + + const positionFloat32 = new Float32Array(positions); + const buffer = gl.createBuffer(); + gl.bindBuffer(gl.ARRAY_BUFFER, buffer); + gl.bufferData(gl.ARRAY_BUFFER, positionFloat32, gl.STATIC_DRAW); + gl.useProgram(program); + + const aPostionLocation = gl.getAttribLocation(program, 'a_position'); + const colorLocation = gl.getUniformLocation(program, 'a_color'); + gl.uniform4f(colorLocation, 0.4, 0.0, 1.0, 0.2); + + gl.enable(gl.BLEND); + gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + + gl.enableVertexAttribArray(aPostionLocation); + gl.vertexAttribPointer(aPostionLocation, 2, gl.FLOAT, false, 0, 0); + gl.drawArrays(gl.TRIANGLES, 0, positionFloat32.length >> 1); +} + + +/** + * @description 创建着色器 + * @param {WebGL2RenderingContext} gl + * @param {WebGLShader} vertexShader + * @param {WebGLShader} fragmentShader + * @return { WebGLProgram | undefined } + */ +function createProgram(gl, vertexShader, fragmentShader) { + // 创建着色程序 + const program = gl.createProgram(); + // 加载着色器到着色程序 + gl.attachShader(program, vertexShader); + gl.attachShader(program, fragmentShader); + // 连接着色程序 + gl.linkProgram(program); + const ok = gl.getProgramParameter(program, gl.LINK_STATUS); + + return ok ? program : gl.deleteProgram(program); +} diff --git a/test/render-line/vertex.shader.glsl b/test/render-line/vertex.shader.glsl new file mode 100644 index 0000000..181a6a8 --- /dev/null +++ b/test/render-line/vertex.shader.glsl @@ -0,0 +1,7 @@ +#version 300 es + +in vec4 a_position; + +void main() { + gl_Position = a_position; +} \ No newline at end of file diff --git a/test/render-line/webgl.drawio b/test/render-line/webgl.drawio new file mode 100644 index 0000000..11e7f20 --- /dev/null +++ b/test/render-line/webgl.drawio @@ -0,0 +1,655 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/test/shader/fragment.glsl b/test/shader/fragment.glsl new file mode 100644 index 0000000..fcd4e6c --- /dev/null +++ b/test/shader/fragment.glsl @@ -0,0 +1,7 @@ +#version 300 es +precision mediump float; +in vec4 v_color; +out vec4 outColor; +void main() { + outColor = v_color; +} \ No newline at end of file diff --git a/test/vertex.glsl b/test/shader/vertex.glsl similarity index 75% rename from test/vertex.glsl rename to test/shader/vertex.glsl index 1878564..8d10330 100644 --- a/test/vertex.glsl +++ b/test/shader/vertex.glsl @@ -7,11 +7,11 @@ 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( + 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 - ); + ); } \ No newline at end of file