save
This commit is contained in:
parent
a5a8735cac
commit
9a1642633f
@ -1,3 +0,0 @@
|
||||
import { reactive } from "vue";
|
||||
|
||||
export const signalModal = reactive();
|
@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div class="">
|
||||
<el-radio-group v-model="signalModal">
|
||||
<el-radio-group v-model="signalModal"
|
||||
@click="onRadioClick"
|
||||
>
|
||||
<!-- 数字模式 -->
|
||||
<el-radio-button :label="0">
|
||||
<el-tooltip
|
||||
@ -37,16 +39,41 @@
|
||||
|
||||
|
||||
<script setup>
|
||||
import { defineComponent, ref } from 'vue';
|
||||
import { globalLookup } from '@/hook/global';
|
||||
import { defineComponent, nextTick, ref, watch } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
|
||||
// 负责展示波形形式的模块,分为数字形式、折线模拟形式、阶梯模拟形式
|
||||
defineComponent({ name: 'signal-modal' });
|
||||
|
||||
const { t } = useI18n();
|
||||
|
||||
const signalModal = ref(0);
|
||||
|
||||
|
||||
function getOneSelectLink() {
|
||||
let selectedLink = undefined;
|
||||
for (const link of globalLookup.sidebarSelectedWireLinks) {
|
||||
selectedLink = link;
|
||||
break;
|
||||
}
|
||||
return selectedLink;
|
||||
}
|
||||
|
||||
|
||||
|
||||
watch(globalLookup.sidebarSelectedWireLinks, () => {
|
||||
const link = getOneSelectLink();
|
||||
if (link) {
|
||||
const option = globalLookup.currentSignalRenderOptions.get(link);
|
||||
if (option && typeof option.renderModal === 'number') {
|
||||
signalModal.value = option.renderModal;
|
||||
} else {
|
||||
signalModal.value = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
|
@ -21,7 +21,7 @@ class ShaderMaker {
|
||||
gl.compileShader(shader);
|
||||
const ok = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
|
||||
if (!ok) {
|
||||
console.log('创建类型为 ' + type + ' 的着色器失败!');
|
||||
console.log('创建类型为 ' + this.type + ' 的着色器失败!');
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
@ -30,8 +30,10 @@ class ShaderMaker {
|
||||
const colorsLength = gl_Colors_template.length << 1;
|
||||
|
||||
const vertexShader = new ShaderMaker('VERTEX_SHADER', `#version 300 es
|
||||
in uvec4 pos;
|
||||
in ivec2 pos;
|
||||
in ivec3 control;
|
||||
out vec4 v_color;
|
||||
uniform float posYFactor;
|
||||
uniform vec2 scale;
|
||||
uniform vec2 offset;
|
||||
uniform vec4 colors[${colorsLength}];
|
||||
@ -39,14 +41,24 @@ uniform vec2 shifts[7]; // 基础八位图偏移量,为了性能,po
|
||||
uniform vec2 widthShifts[8]; // 用于构造线宽的偏移
|
||||
|
||||
void main() {
|
||||
v_color = colors[pos.z];
|
||||
vec2 shift = shifts[pos.y];
|
||||
vec2 widthShift = widthShifts[pos.w];
|
||||
gl_Position = vec4(
|
||||
float(pos.x) * scale.x + offset.x + float(widthShift.x) + shift.y,
|
||||
float(shift.x) * scale.y + offset.y + float(widthShift.y),
|
||||
1, 1
|
||||
);
|
||||
vec2 shift = shifts[control.x];
|
||||
vec2 ws = widthShifts[control.y];
|
||||
v_color = colors[control.z];
|
||||
|
||||
// 为了性能,传递进来进来的都是整数,pos.y 需要除以 posYFactor
|
||||
float posX = float(pos.x);
|
||||
float posY = float(pos.y) / posYFactor;
|
||||
|
||||
// 偏移包括三部分:用户滚动时发生的全局位移、为了设置线宽发生的位移、与 scale 无关的额外位移
|
||||
float offsetX = offset.x + float(ws.x) + float(shift.x);
|
||||
float offsetY = offset.y + float(ws.y) + float(shift.y);
|
||||
|
||||
gl_Position = vec4(
|
||||
posX * scale.x + offsetX,
|
||||
posY * scale.y + offsetY,
|
||||
1,
|
||||
1
|
||||
);
|
||||
}`);
|
||||
|
||||
const fragmentShader = new ShaderMaker('FRAGMENT_SHADER', `#version 300 es
|
||||
|
@ -88,24 +88,24 @@ const gl_Shifts = new Float32Array([ // 14
|
||||
-1, 0 // 6
|
||||
]);
|
||||
|
||||
// 视屏幕本身而定
|
||||
const posYFactor = 10000;
|
||||
const glslInputLength = 5;
|
||||
|
||||
// 为了满足 vec 类型的波形的开头和结尾的那个小小的内嵌的、不受scale影响的值
|
||||
// 第一列 Y 第二列 X 在所有计算完成后的额外偏移量
|
||||
const barShift = 0.004;
|
||||
|
||||
const gl_Shifts_for_bar = new Float32Array([
|
||||
0, 0, // 0
|
||||
1, barShift, // 1
|
||||
1, -barShift, // 2
|
||||
1, 0, // 3
|
||||
-1, barShift, // 4
|
||||
-1, -barShift, // 5
|
||||
-1, 0 // 6
|
||||
0, 0, // 0
|
||||
barShift, 0, // 1
|
||||
-barShift, 0, // 2
|
||||
0, 0, // 3
|
||||
barShift, 0, // 4
|
||||
-barShift, 0, // 5
|
||||
0, 0, // 6
|
||||
]);
|
||||
|
||||
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 lineWidth = 0.004 * 3800 / screenWidthPixel; // 不能写为 0.0045 这样会因为插值造成不同线段的宽度不一致的问题
|
||||
const widthShift = 0.002;
|
||||
@ -120,16 +120,33 @@ const gl_WidthShifts = new Float32Array([
|
||||
widthShift, widthShift // 7
|
||||
]);
|
||||
|
||||
|
||||
function prettyPrint(array) {
|
||||
const stack = [];
|
||||
for (const num of array) {
|
||||
if (stack.length === 5) {
|
||||
console.log(stack);
|
||||
stack.length = 0;
|
||||
}
|
||||
stack.push(num);
|
||||
}
|
||||
if (stack.length > 0) {
|
||||
console.log(stack);
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
getRatio,
|
||||
gl_Colors,
|
||||
gl_Shifts,
|
||||
posYFactor,
|
||||
lineWidth,
|
||||
widthShift,
|
||||
gl_WidthShifts,
|
||||
gl_Shifts_map,
|
||||
screenWidthPixel,
|
||||
screenHeightPixel,
|
||||
gl_Shifts_for_bar,
|
||||
barShift
|
||||
barShift,
|
||||
glslInputLength,
|
||||
prettyPrint
|
||||
};
|
@ -1,8 +1,8 @@
|
||||
import { globalSetting, globalStyle } from '../global';
|
||||
|
||||
import { gl_Colors, gl_Shifts, gl_Shifts_for_bar, gl_Shifts_map, gl_WidthShifts, barShift, getRatio, screenHeightPixel, maskColorIndexOffset } from './render-utils.js';
|
||||
import { gl_Colors, gl_Shifts, gl_Shifts_for_bar, gl_WidthShifts, barShift, getRatio, screenHeightPixel, maskColorIndexOffset, posYFactor, glslInputLength, prettyPrint } from './render-utils.js';
|
||||
import { vertexShader, fragmentShader } from './render-shader.js';
|
||||
import { renderAsCommonDigital } from './toolbar/renderModal';
|
||||
import { renderAsBit, renderAsCommonDigital, renderAsLadderAnalog } from './toolbar/renderModal';
|
||||
|
||||
// const { ChangoItem } = require('./types.d.ts');
|
||||
|
||||
@ -47,6 +47,7 @@ class WebGL2WaveRender {
|
||||
* scale: WebGLUniformLocation,
|
||||
* offset: WebGLUniformLocation,
|
||||
* pos: number,
|
||||
* control: number,
|
||||
* widthShifts: WebGLUniformLocation,
|
||||
* gl: WebGL2RenderingContext
|
||||
* }}
|
||||
@ -61,9 +62,11 @@ class WebGL2WaveRender {
|
||||
const webglLocation = {
|
||||
colors: gl.getUniformLocation(program, 'colors'),
|
||||
shifts: gl.getUniformLocation(program, 'shifts'),
|
||||
posYFactor: gl.getUniformLocation(program, 'posYFactor'),
|
||||
scale: gl.getUniformLocation(program, 'scale'),
|
||||
offset: gl.getUniformLocation(program, 'offset'),
|
||||
pos: gl.getAttribLocation(program, 'pos'),
|
||||
control: gl.getAttribLocation(program, 'control'),
|
||||
widthShifts: gl.getUniformLocation(program, 'widthShifts'),
|
||||
gl
|
||||
};
|
||||
@ -74,8 +77,8 @@ class WebGL2WaveRender {
|
||||
/**
|
||||
*
|
||||
* @returns {{
|
||||
* lineVerticesMap: Map<string, Uint32Array>,
|
||||
* maskVerticesMap: Map<string, Uint32Array>
|
||||
* lineVerticesMap: Map<string, Int32Array>,
|
||||
* maskVerticesMap: Map<string, Int32Array>
|
||||
* }}
|
||||
*/
|
||||
makeVertex() {
|
||||
@ -98,8 +101,8 @@ class WebGL2WaveRender {
|
||||
*
|
||||
* @param {string} id 波形的 link
|
||||
* @returns {{
|
||||
* lineVertices: Uint32Array
|
||||
* maskVertices: Uint32Array
|
||||
* lineVertices: Int32Array
|
||||
* maskVertices: Int32Array
|
||||
* }}
|
||||
*/
|
||||
makeVertexByID(id) {
|
||||
@ -122,239 +125,27 @@ class WebGL2WaveRender {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @description 将 bit 类型的 wave 的值转化为渲染需要用到的值
|
||||
* @param {string} link
|
||||
* @param {number} value
|
||||
* @return {{
|
||||
* y: number // 裁剪空间的纵坐标
|
||||
* color: number // 颜色的索引 颜色rgb = gl_Colors[color]
|
||||
* }}
|
||||
*/
|
||||
translateValue2RenderParameter(link, value) {
|
||||
let colorParam;
|
||||
switch (value) {
|
||||
case 0: colorParam = { y: -1, color: 2 }; break; // 0 value
|
||||
case 1: colorParam = { y: 1, color: 3 }; break; // 1 value
|
||||
case 2: case 3: colorParam = { y: -1, color: 4 }; break; // 不定态 x
|
||||
case 4: case 5: colorParam = { y: 0, color: 2 }; break; // 高阻态 z
|
||||
default: colorParam = { y: -1, color: 7 }; break; // 其他,我也不知道还有啥
|
||||
}
|
||||
|
||||
if (value === 0 || value === 1) {
|
||||
const renderOptions = this.globalLookup.currentSignalRenderOptions;
|
||||
if (renderOptions.has(link)) {
|
||||
const option = renderOptions.get(link);
|
||||
if (typeof option.color === 'number') {
|
||||
colorParam.color = option.color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return colorParam;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @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 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} x1
|
||||
* @param {number} y1
|
||||
* @param {number} x2
|
||||
* @param {number} y2
|
||||
* @param {number} color
|
||||
* @param {number} wsIndex
|
||||
* @returns {number[]}
|
||||
*/
|
||||
makeRectangleVertices(x1, y1, x2, y2, color, wsIndex = 0) {
|
||||
const r1 = [x1, gl_Shifts_map.get(y2), color, wsIndex];
|
||||
const r2 = [x1, gl_Shifts_map.get(y1), color, wsIndex];
|
||||
const r3 = [x2, gl_Shifts_map.get(y1), color, wsIndex];
|
||||
const r4 = [x2, gl_Shifts_map.get(y2), color, wsIndex];
|
||||
return this.makeQuadVertices(r1, r2, r3, r4);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number[]} p1
|
||||
* @param {number[]} p2
|
||||
* @param {number[]} p3
|
||||
* @param {number[]} p4
|
||||
* @returns {number[]}
|
||||
*/
|
||||
makeQuadVertices(p1, p2, p3, p4) {
|
||||
return [
|
||||
...p1, ...p2, ...p3,
|
||||
...p1, ...p3, ...p4
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} link
|
||||
* @param {Array<string | number>} wave
|
||||
* @param { number } time
|
||||
* @returns {{
|
||||
* lineVertices: Uint32Array
|
||||
* maskVertices: Uint32Array
|
||||
* lineVertices: Int32Array
|
||||
* maskVertices: Int32Array
|
||||
* }}
|
||||
*/
|
||||
makeBitVertex(link, 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(link, value1);
|
||||
const renderParam2 = this.translateValue2RenderParameter(link, 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[perspectivePoints.length - 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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 确保最后一个点延申到了 time
|
||||
const lastPoint = perspectivePoints[perspectivePoints.length - 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 = [];
|
||||
|
||||
|
||||
// 制作 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);
|
||||
|
||||
if (wsIndex === undefined) {
|
||||
console.log(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];
|
||||
|
||||
// 开头就有一条线
|
||||
if (i === 0 && p1.y === 1) {
|
||||
while (perspectivePoints[++ i] && perspectivePoints[i].y === 1);
|
||||
// 回退
|
||||
if (-- i > 0) {
|
||||
// 四元组: (x, yshift_index, color_index, width_shift_index)
|
||||
const rectangleVertices = this.makeRectangleVertices(p1.x, 1, perspectivePoints[i].x, -1, p1.color + maskColorIndexOffset, 4);
|
||||
// 三角图元画矩形
|
||||
maskVertices.push(...rectangleVertices);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 上升沿才使用
|
||||
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 rectangleVertices = this.makeRectangleVertices(p2.x, p2.y, p3.x, p1.y, p2.color + maskColorIndexOffset, 4);
|
||||
// 三角图元画矩形
|
||||
maskVertices.push(...rectangleVertices);
|
||||
}
|
||||
}
|
||||
const { lineVertices, maskVertices } = renderAsBit(link, wave, time);
|
||||
|
||||
if (debug) {
|
||||
console.log(perspectivePoints);
|
||||
console.log(pointNum);
|
||||
console.log(lineVertices);
|
||||
}
|
||||
|
||||
return {
|
||||
lineVertices : new Uint32Array(lineVertices),
|
||||
maskVertices : new Uint32Array(maskVertices)
|
||||
lineVertices : new Int32Array(lineVertices),
|
||||
maskVertices : new Int32Array(maskVertices)
|
||||
};
|
||||
}
|
||||
|
||||
@ -364,12 +155,13 @@ class WebGL2WaveRender {
|
||||
* @param {Array<string | number>} wave
|
||||
* @param { number } time
|
||||
* @returns {{
|
||||
* lineVertices: Uint32Array
|
||||
* maskVertices: Uint32Array
|
||||
* lineVertices: Int32Array
|
||||
* maskVertices: Int32Array
|
||||
* }}
|
||||
*/
|
||||
makeVecVertex(link, wave, time, debug = false) {
|
||||
const lookup = this.globalLookup;
|
||||
|
||||
const { lineVertices, maskVertices } = renderAsCommonDigital(lookup, link, wave, time);
|
||||
|
||||
if (debug) {
|
||||
@ -377,13 +169,24 @@ class WebGL2WaveRender {
|
||||
}
|
||||
|
||||
return {
|
||||
lineVertices: new Uint32Array(lineVertices),
|
||||
maskVertices: new Uint32Array(maskVertices)
|
||||
lineVertices: new Int32Array(lineVertices),
|
||||
maskVertices: new Int32Array(maskVertices)
|
||||
};
|
||||
}
|
||||
|
||||
setShaderInput() {
|
||||
const UIntSize = Int32Array.BYTES_PER_ELEMENT; // 4
|
||||
const webglLocation = this.webglLocation;
|
||||
const gl = webglLocation.gl;
|
||||
|
||||
gl.vertexAttribIPointer(webglLocation.pos, 2, gl.INT, 5 * UIntSize, 0);
|
||||
gl.vertexAttribIPointer(webglLocation.control, 3, gl.INT, 5 * UIntSize, 2 * UIntSize);
|
||||
gl.enableVertexAttribArray(webglLocation.pos);
|
||||
gl.enableVertexAttribArray(webglLocation.control);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @description 根据 id (link) 将对应信号的 value 数据转换成对应视图的 VAO 以供 webgl 渲染
|
||||
* @param {string} id
|
||||
* @returns
|
||||
*/
|
||||
@ -407,8 +210,7 @@ class WebGL2WaveRender {
|
||||
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);
|
||||
this.setShaderInput();
|
||||
|
||||
// 创建并设置 绘制wave半透明遮罩层 主体轮廓的 缓冲区、vao、顶点设置
|
||||
const maskVertexBuffer = gl.createBuffer();
|
||||
@ -416,8 +218,7 @@ class WebGL2WaveRender {
|
||||
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);
|
||||
this.setShaderInput();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -439,8 +240,7 @@ class WebGL2WaveRender {
|
||||
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);
|
||||
this.setShaderInput();
|
||||
|
||||
// 创建并设置 绘制wave半透明遮罩层 主体轮廓的 缓冲区、vao、顶点设置
|
||||
const maskVertexBuffer = gl.createBuffer();
|
||||
@ -448,8 +248,7 @@ class WebGL2WaveRender {
|
||||
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);
|
||||
this.setShaderInput();
|
||||
}
|
||||
|
||||
initData() {
|
||||
@ -464,6 +263,7 @@ class WebGL2WaveRender {
|
||||
gl.uniform4fv(webglLocation.colors, gl_Colors);
|
||||
gl.uniform2fv(webglLocation.widthShifts, gl_WidthShifts);
|
||||
gl.uniform2fv(webglLocation.shifts, gl_Shifts);
|
||||
gl.uniform1f(webglLocation.posYFactor, posYFactor);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -536,7 +336,7 @@ class WebGL2WaveRender {
|
||||
canvas.width = canvasWidth;
|
||||
// 默认 1260
|
||||
canvas.height = canvasHeight;
|
||||
|
||||
|
||||
let startTime = undefined;
|
||||
// 默认执行一个 300 ms 的动画
|
||||
const animationDuration = 300;
|
||||
@ -574,7 +374,7 @@ class WebGL2WaveRender {
|
||||
|
||||
// 设置 webgl 和 canvas 大小位置一致
|
||||
gl.viewport(0, 0, canvasWidth, canvasHeight);
|
||||
// 清楚颜色缓冲区,也就是删除上一次的渲染结果
|
||||
// 清除颜色缓冲区,也就是删除上一次的渲染结果
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
// 根据 currentWiresRenderView 视图渲染
|
||||
@ -626,18 +426,18 @@ class WebGL2WaveRender {
|
||||
// 如果是 width 为 1 的
|
||||
gl.uniform2fv(webglLocation.shifts, gl_Shifts);
|
||||
gl.bindVertexArray(signalItem.lineVao);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, lineVertices.length / 4);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, lineVertices.length / glslInputLength);
|
||||
|
||||
gl.bindVertexArray(signalItem.maskVao);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, maskVertices.length / 4);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, maskVertices.length / glslInputLength);
|
||||
} else {
|
||||
// 如果是 width 大于 1 的
|
||||
gl.uniform2fv(webglLocation.shifts, gl_Shifts_for_bar);
|
||||
gl.bindVertexArray(signalItem.lineVao);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, lineVertices.length / 4);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, lineVertices.length / glslInputLength);
|
||||
|
||||
gl.bindVertexArray(signalItem.maskVao);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, maskVertices.length / 4);
|
||||
gl.drawArrays(gl.TRIANGLES, 0, maskVertices.length / glslInputLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -13,7 +13,23 @@
|
||||
* @property {number} minVal
|
||||
*/
|
||||
|
||||
import { maskColorIndexOffset } from "../render-utils";
|
||||
/**
|
||||
* @description
|
||||
* @typedef {Object} BitRenderTempStruct
|
||||
* @property {number} color 颜色的索引 颜色rgb = gl_Colors[color]
|
||||
* @property {number} y 裁剪空间的纵坐标
|
||||
*/
|
||||
|
||||
/**
|
||||
* @description
|
||||
* @typedef {Object} BitRenderHandlePoint
|
||||
* @property {number} x
|
||||
* @property {number} y
|
||||
* @property {number} color
|
||||
*/
|
||||
|
||||
import { globalLookup } from "@/hook/global";
|
||||
import { maskColorIndexOffset, posYFactor } from "../render-utils";
|
||||
import { hexToSignedInt } from "./renderFormat";
|
||||
|
||||
|
||||
@ -24,6 +40,227 @@ function makeQuadVertices(p1, p2, p3, p4) {
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {number} x1
|
||||
* @param {number} y1
|
||||
* @param {number} x2
|
||||
* @param {number} y2
|
||||
* @param {number} color
|
||||
* @param {number} wsIndex
|
||||
* @returns {number[]}
|
||||
*/
|
||||
function makeRectangleVertices(x1, y1, x2, y2, color, wsIndex = 0) {
|
||||
// uvec2 pos; uvec3 control;
|
||||
const r1 = [x1, y2 * posYFactor, 0, wsIndex, color];
|
||||
const r2 = [x1, y1 * posYFactor, 0, wsIndex, color];
|
||||
const r3 = [x2, y1 * posYFactor, 0, wsIndex, color];
|
||||
const r4 = [x2, y2 * posYFactor, 0, wsIndex, color];
|
||||
return makeQuadVertices(r1, r2, r3, r4);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 将 bit 类型的 wave 的值转化为渲染需要用到的值
|
||||
* @param {string} link
|
||||
* @param {number[]} wave
|
||||
* @param {number} time
|
||||
* @return {BitRenderTempStruct}
|
||||
*/
|
||||
function makeBitRenderParam(link, wave, time) {
|
||||
const value = wave[1];
|
||||
let colorParam;
|
||||
switch (value) {
|
||||
case 0: colorParam = { y: -1, color: 2 }; break; // 0 value
|
||||
case 1: colorParam = { y: 1, color: 3 }; break; // 1 value
|
||||
case 2: case 3: colorParam = { y: -1, color: 4 }; break; // 不定态 x
|
||||
case 4: case 5: colorParam = { y: 0, color: 2 }; break; // 高阻态 z
|
||||
default: colorParam = { y: -1, color: 7 }; break; // 其他,我也不知道还有啥
|
||||
}
|
||||
|
||||
if (value === 0 || value === 1) {
|
||||
const renderOptions = globalLookup.currentSignalRenderOptions;
|
||||
if (renderOptions.has(link)) {
|
||||
const option = renderOptions.get(link);
|
||||
if (typeof option.color === 'number') {
|
||||
colorParam.color = option.color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return colorParam;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {BitRenderHandlePoint | undefined} p0 前一个点
|
||||
* @param {BitRenderHandlePoint | undefined} p1 当前的点
|
||||
* @param {BitRenderHandlePoint | undefined} p2 后一个点
|
||||
* @returns {number} 这是 widthshift 的索引,只需要 + 4 再 % 8 就能得到另一个
|
||||
*/
|
||||
function 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 0;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} link
|
||||
* @param {Array<string | number>} wave
|
||||
* @param { number } time
|
||||
* @param {(link: string, wave: number[], time: number) => BitRenderTempStruct} renderParamMaker
|
||||
* @returns {VecRenderNumberVertices}
|
||||
*/
|
||||
function renderBlockWave(link, wave, time, renderParamMaker) {
|
||||
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 = renderParamMaker(link, currentWave, time);
|
||||
const renderParam2 = renderParamMaker(link, nextWave, time);
|
||||
|
||||
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[perspectivePoints.length - 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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 确保最后一个点延申到了 time
|
||||
const lastPoint = perspectivePoints[perspectivePoints.length - 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 = [];
|
||||
|
||||
|
||||
// 制作 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];
|
||||
|
||||
const wsIndex = makeWidthShiftIndexByPoints(p0, p1, p2);
|
||||
|
||||
if (wsIndex === undefined) {
|
||||
console.log(p0, p1, p2);
|
||||
}
|
||||
|
||||
lineVertices.push(
|
||||
// uvec2 pos; uvec3 control;
|
||||
p1.x, p1.y * posYFactor, 0, wsIndex, p1.color,
|
||||
p1.x, p1.y * posYFactor, 0, (wsIndex + 4) % 8, p1.color
|
||||
);
|
||||
|
||||
// 防止颜色不同导致单个图元内出现两个颜色,这会引发shader的渐变
|
||||
if (p2 !== undefined && p1.color !== p2.color) {
|
||||
lineVertices.push(
|
||||
// uvec2 pos; uvec3 control;
|
||||
p1.x, p1.y * posYFactor, 0, wsIndex, p2.color,
|
||||
p1.x, p1.y * posYFactor, 0, (wsIndex + 4) % 8, p2.color,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 制作 maskVertices
|
||||
for (let i = 0; i < pointNum; ++ i) {
|
||||
const p1 = perspectivePoints[i];
|
||||
|
||||
// 开头就有一条线
|
||||
if (i === 0 && p1.y === 1) {
|
||||
while (perspectivePoints[++ i] && perspectivePoints[i].y === 1);
|
||||
// 回退
|
||||
if (-- i > 0) {
|
||||
// 四元组: (x, yshift_index, color_index, width_shift_index)
|
||||
const rectangleVertices = makeRectangleVertices(p1.x, 1, perspectivePoints[i].x, -1, p1.color + maskColorIndexOffset, 4);
|
||||
// 三角图元画矩形
|
||||
maskVertices.push(...rectangleVertices);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// 上升沿才使用
|
||||
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 rectangleVertices = makeRectangleVertices(p2.x, p2.y, p3.x, p1.y, p2.color + maskColorIndexOffset, 4);
|
||||
// 三角图元画矩形
|
||||
maskVertices.push(...rectangleVertices);
|
||||
}
|
||||
}
|
||||
|
||||
return { lineVertices, maskVertices };
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} link
|
||||
* @param {Array<string | number>} wave
|
||||
* @param { number } time
|
||||
* @returns {VecRenderNumberVertices}
|
||||
*/
|
||||
export function renderAsBit(link, wave, time) {
|
||||
return renderBlockWave(link, wave, time, makeBitRenderParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Digital
|
||||
* @param {GlobalLookup} lookup
|
||||
@ -43,13 +280,13 @@ export function renderAsCommonDigital(lookup, link, wave, time) {
|
||||
|
||||
// t1(val) --- t2(val)
|
||||
// 详见 设计图 ./design/webgl.drawio makeVecVertex原理 sheet
|
||||
// 此处的 y 不是 y 的索引,详见 gl_Shifts_for_bar 的设计
|
||||
const p0 = {x: t1, y: 0};
|
||||
const p1 = {x: t2, y: 0};
|
||||
const a0 = {x: t1, y: 4};
|
||||
const a1 = {x: t2, y: 5};
|
||||
const a2 = {x: t1, y: 1};
|
||||
const a3 = {x: t2, y: 2};
|
||||
// 详见 gl_Shifts_for_bar 的设计
|
||||
const p0 = {x: t1, y: 0, shift: 0};
|
||||
const p1 = {x: t2, y: 0, shift: 0};
|
||||
const a0 = {x: t1, y: -1, shift: 4};
|
||||
const a1 = {x: t2, y: -1, shift: 5};
|
||||
const a2 = {x: t1, y: 1, shift: 1};
|
||||
const a3 = {x: t2, y: 1, shift: 2};
|
||||
|
||||
let color = 5;
|
||||
const renderOptions = lookup.currentSignalRenderOptions;
|
||||
@ -70,10 +307,10 @@ export function renderAsCommonDigital(lookup, link, wave, time) {
|
||||
const preWsIndex = wsIndice[j];
|
||||
const nextWsIndex = wsIndice[(j + 1) % 6];
|
||||
const quadVertices = makeQuadVertices(
|
||||
[prePoint.x, prePoint.y, color, preWsIndex],
|
||||
[prePoint.x, prePoint.y, color, (preWsIndex + 4) % 8],
|
||||
[nextPoint.x, nextPoint.y, color, (nextWsIndex + 4) % 8],
|
||||
[nextPoint.x, nextPoint.y, color, nextWsIndex],
|
||||
[prePoint.x, prePoint.y * posYFactor, prePoint.shift, preWsIndex, color],
|
||||
[prePoint.x, prePoint.y * posYFactor, prePoint.shift, (preWsIndex + 4) % 8, color],
|
||||
[nextPoint.x, nextPoint.y * posYFactor, nextPoint.shift, (nextWsIndex + 4) % 8, color],
|
||||
[nextPoint.x, nextPoint.y * posYFactor, nextPoint.shift, nextWsIndex, color],
|
||||
);
|
||||
lineVertices.push(...quadVertices);
|
||||
}
|
||||
@ -91,9 +328,9 @@ export function renderAsCommonDigital(lookup, link, wave, time) {
|
||||
const point2 = points[i2];
|
||||
const point3 = points[i3];
|
||||
maskVertices.push(
|
||||
point1.x, point1.y, color + maskColorIndexOffset, wsIndice[i1],
|
||||
point2.x, point2.y, color + maskColorIndexOffset, wsIndice[i2],
|
||||
point3.x, point3.y, color + maskColorIndexOffset, wsIndice[i3]
|
||||
point1.x, point1.y * posYFactor, point1.shift, wsIndice[i1], color + maskColorIndexOffset,
|
||||
point2.x, point2.y * posYFactor, point2.shift, wsIndice[i2], color + maskColorIndexOffset,
|
||||
point3.x, point3.y * posYFactor, point3.shift, wsIndice[i3], color + maskColorIndexOffset,
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -156,9 +393,10 @@ function explainAsJSNumber(formatCode, val, width) {
|
||||
function getMaxMinByFormat(link, wave, time, formatCode, width) {
|
||||
let maxVal = undefined;
|
||||
let minVal = undefined;
|
||||
const length = wave.length;
|
||||
|
||||
// TODO : 优化这段代码
|
||||
for (let i = 0; i < wave.length; ++ i) {
|
||||
for (let i = 0; i < length; ++ i) {
|
||||
const [t1, val, mask] = wave[i];
|
||||
const t2 = (i === (length - 1)) ? time : wave[i + 1][0];
|
||||
const numVal = explainAsJSNumber(formatCode, val, width);
|
||||
@ -189,11 +427,17 @@ function getMaxMinByFormat(link, wave, time, formatCode, width) {
|
||||
function getMappingFunc(formatCode, maxVal, minVal) {
|
||||
if (formatCode === 3) {
|
||||
const maxAbs = Math.max(Math.abs(maxVal), Math.abs(minVal));
|
||||
if (maxAbs === 0) {
|
||||
return val => 0;
|
||||
}
|
||||
const k = 1 / maxAbs;
|
||||
const b = -1;
|
||||
// 把 [-maxAbs, +maxAbs] 映射到 [-1, 1]
|
||||
return val => k * (val + maxAbs) + b;
|
||||
} else {
|
||||
if (maxVal === 0) {
|
||||
return val => -1;
|
||||
}
|
||||
const k = 2 / maxVal;
|
||||
const b = -1;
|
||||
// 把 [0, max] 映射到 [-1, 1]
|
||||
@ -215,33 +459,39 @@ export function renderAsLadderAnalog(lookup, link, wave, time) {
|
||||
const signal = lookup.link2CurrentWires.get(link);
|
||||
const width = signal.size;
|
||||
|
||||
const { maxVal, minVal } = getMaxMinByFormat(lookup, link, wave, time, formatCode, width);
|
||||
const { maxVal, minVal } = getMaxMinByFormat(link, wave, time, formatCode, width);
|
||||
const coordinateTransform = getMappingFunc(formatCode, maxVal, minVal);
|
||||
|
||||
const length = wave.length;
|
||||
const lineVertices = [];
|
||||
const maskVertices = [];
|
||||
|
||||
for (let i = 0; i < length; ++ i) {
|
||||
const [t1, val, mask] = wave[i];
|
||||
const t2 = (i === (length - 1)) ? time : wave[i + 1][0];
|
||||
function makeLadderAnalogRenderParam(link, wave, time) {
|
||||
const [t1, val, mask] = wave;
|
||||
|
||||
let color = 5;
|
||||
if (mask) {
|
||||
color = 4;
|
||||
} else if (renderOptions.has(link)) {
|
||||
const option = renderOptions.get(link);
|
||||
if (typeof option.color === 'number') {
|
||||
color = option.color;
|
||||
}
|
||||
// 不定态
|
||||
return { y: -1, color: 4 };
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 根据当前格式进行转换
|
||||
const numVal = explainAsJSNumber(formatCode, val, width);
|
||||
// 此时的 y 是一个 -1 到 1 的浮点数,因为 VAO 我设置了 Int
|
||||
const y = coordinateTransform(numVal);
|
||||
|
||||
console.log(t1, y);
|
||||
const colorParam = { y, color: 5 };
|
||||
|
||||
if (renderOptions.has(link)) {
|
||||
const option = renderOptions.get(link);
|
||||
if (typeof option.color === 'number') {
|
||||
colorParam.color = option.color;
|
||||
}
|
||||
}
|
||||
|
||||
return colorParam;
|
||||
}
|
||||
|
||||
return renderBlockWave(link, wave, time, makeLadderAnalogRenderParam);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -255,7 +505,11 @@ export function renderAsLadderAnalog(lookup, link, wave, time) {
|
||||
export function renderAsLineAnalog(lookup, link, wave, time) {
|
||||
const renderOptions = lookup.currentSignalRenderOptions;
|
||||
const formatCode = getValFormatCode(lookup, link);
|
||||
|
||||
const { maxVal, minVal } = getMaxMinByFormat(lookup, link, wave, time, formatCode);
|
||||
const signal = lookup.link2CurrentWires.get(link);
|
||||
const width = signal.size;
|
||||
|
||||
const { maxVal, minVal } = getMaxMinByFormat(link, wave, time, formatCode, width);
|
||||
|
||||
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user