import macro from 'vtk.js/Sources/macros'; import Constants from 'vtk.js/Sources/Rendering/WebGPU/BufferManager/Constants'; import vtkProperty from 'vtk.js/Sources/Rendering/Core/Property'; import vtkWebGPUBuffer from 'vtk.js/Sources/Rendering/WebGPU/Buffer';
const { Representation } = vtkProperty; const { PrimitiveTypes } = Constants;
class _LimitedMap { constructor() { this.keys = new Uint32Array(10); this.values = new Uint32Array(10); this.count = 0; }
clear() { this.count = 0; }
has(key) { for (let i = 0; i < this.count; i++) { if (this.keys[i] === key) { return true; } } return undefined; }
get(key) { for (let i = 0; i < this.count; i++) { if (this.keys[i] === key) { return this.values[i]; } } return undefined; }
set(key, value) { if (this.count < 9) { this.keys[this.count] = key; this.values[this.count++] = value; } } }
function getPrimitiveName(primType) { switch (primType) { case PrimitiveTypes.Points: return 'points'; case PrimitiveTypes.Lines: return 'lines'; case PrimitiveTypes.Triangles: case PrimitiveTypes.TriangleEdges: return 'polys'; case PrimitiveTypes.TriangleStripEdges: case PrimitiveTypes.TriangleStrips: return 'strips'; default: return ''; } }
function _getOrAddFlatId(state, ptId, cellId) { let flatId = state.pointIdToFlatId[ptId]; if (flatId < 0) { flatId = state.flatId; state.pointIdToFlatId[ptId] = flatId; state.flatIdToPointId[state.flatId] = ptId; state.flatIdToCellId[state.flatId] = cellId; state.flatId++; } return flatId; }
function fillCell(ptIds, cellId, state) { const numPtIds = ptIds.length; for (let ptIdx = 0; ptIdx < numPtIds; ptIdx++) { let ptId = ptIds[ptIdx]; if (state.cellProvokedMap.has(ptId)) { state.ibo[state.iboId++] = state.cellProvokedMap.get(ptId);
for (let ptIdx2 = ptIdx + 1; ptIdx2 < ptIdx + numPtIds; ptIdx2++) { ptId = ptIds[ptIdx2 % numPtIds]; const flatId = _getOrAddFlatId(state, ptId, cellId); state.ibo[state.iboId++] = flatId; } return; } }
for (let ptIdx = 0; ptIdx < numPtIds; ptIdx++) { let ptId = ptIds[ptIdx]; if (!state.provokedPointIds[ptId]) { let flatId = _getOrAddFlatId(state, ptId, cellId); state.provokedPointIds[ptId] = 1; state.cellProvokedMap.set(ptId, flatId); state.flatIdToCellId[flatId] = cellId; state.ibo[state.iboId++] = flatId;
for (let ptIdx2 = ptIdx + 1; ptIdx2 < ptIdx + numPtIds; ptIdx2++) { ptId = ptIds[ptIdx2 % numPtIds]; flatId = _getOrAddFlatId(state, ptId, cellId); state.ibo[state.iboId++] = flatId; } return; } }
let ptId = ptIds[0]; let flatId = state.flatId; state.cellProvokedMap.set(ptId, flatId); state.flatIdToPointId[state.flatId] = ptId; state.flatIdToCellId[state.flatId] = cellId; state.flatId++;
state.ibo[state.iboId++] = flatId;
for (let ptIdx2 = 1; ptIdx2 < numPtIds; ptIdx2++) { ptId = ptIds[ptIdx2]; flatId = _getOrAddFlatId(state, ptId, cellId); state.ibo[state.iboId++] = flatId; } }
function countCell(ptIds, cellId, state) { const numPtIds = ptIds.length; state.iboSize += numPtIds;
for (let ptIdx = 0; ptIdx < numPtIds; ptIdx++) { const ptId = ptIds[ptIdx]; if (state.cellProvokedMap.has(ptId)) { return; } }
for (let ptIdx = 0; ptIdx < numPtIds; ptIdx++) { const ptId = ptIds[ptIdx]; if (!state.provokedPointIds[ptId]) { state.provokedPointIds[ptId] = 1; state.cellProvokedMap.set(ptId, 1); return; } } state.cellProvokedMap.set(ptIds[0], 1); state.extraPoints++; }
let processCell;
const _single = new Uint32Array(1); const _double = new Uint32Array(2); const _triple = new Uint32Array(3); const _indexCellBuilders = { anythingToPoints(numPoints, cellPts, offset, cellId, state) { for (let i = 0; i < numPoints; ++i) { _single[0] = cellPts[offset + i]; processCell(_single, cellId, state); } }, linesToWireframe(numPoints, cellPts, offset, cellId, state) { for (let i = 0; i < numPoints - 1; ++i) { _double[0] = cellPts[offset + i]; _double[1] = cellPts[offset + i + 1]; processCell(_double, cellId, state); } }, polysToWireframe(numPoints, cellPts, offset, cellId, state) { if (numPoints > 2) { for (let i = 0; i < numPoints; ++i) { _double[0] = cellPts[offset + i]; _double[1] = cellPts[offset + ((i + 1) % numPoints)]; processCell(_double, cellId, state); } } }, stripsToWireframe(numPoints, cellPts, offset, cellId, state) { if (numPoints > 2) { for (let i = 0; i < numPoints - 1; ++i) { _double[0] = cellPts[offset + i]; _double[1] = cellPts[offset + i + 1]; processCell(_double, cellId, state); } for (let i = 0; i < numPoints - 2; i++) { _double[0] = cellPts[offset + i]; _double[1] = cellPts[offset + i + 2]; processCell(_double, cellId, state); } } }, polysToSurface(npts, cellPts, offset, cellId, state) { for (let i = 0; i < npts - 2; i++) { _triple[0] = cellPts[offset]; _triple[1] = cellPts[offset + i + 1]; _triple[2] = cellPts[offset + i + 2]; processCell(_triple, cellId, state); } }, stripsToSurface(npts, cellPts, offset, cellId, state) { for (let i = 0; i < npts - 2; i++) { _triple[0] = cellPts[offset + i]; _triple[1] = cellPts[offset + i + 1 + (i % 2)]; _triple[2] = cellPts[offset + i + 1 + ((i + 1) % 2)]; processCell(_triple, cellId, state); } }, };
function vtkWebGPUIndexBuffer(publicAPI, model) { model.classHierarchy.push('vtkWebGPUIndexBuffer');
publicAPI.buildIndexBuffer = (req) => { const cellArray = req.cells; const primitiveType = req.primitiveType; const representation = req.representation; const cellOffset = req.cellOffset;
const array = cellArray.getData(); const cellArraySize = array.length;
const inRepName = getPrimitiveName(primitiveType);
const numPts = req.numberOfPoints; const state = { provokedPointIds: new Uint8Array(numPts), extraPoints: 0, iboSize: 0, flatId: 0, iboId: 0, cellProvokedMap: new _LimitedMap(), };
let func = null; if ( representation === Representation.POINTS || primitiveType === PrimitiveTypes.Points ) { func = _indexCellBuilders.anythingToPoints; } else if ( representation === Representation.WIREFRAME || primitiveType === PrimitiveTypes.Lines ) { func = _indexCellBuilders[`${inRepName}ToWireframe`]; } else { func = _indexCellBuilders[`${inRepName}ToSurface`]; }
processCell = countCell; let cellId = cellOffset || 0; for (let cellArrayIndex = 0; cellArrayIndex < cellArraySize; ) { state.cellProvokedMap.clear(); func(array[cellArrayIndex], array, cellArrayIndex + 1, cellId, state); cellArrayIndex += array[cellArrayIndex] + 1; cellId++; }
if (numPts <= 0xffff) { state.flatIdToPointId = new Uint16Array(numPts + state.extraPoints); } else { state.flatIdToPointId = new Uint32Array(numPts + state.extraPoints); } if (numPts + state.extraPoints < 0x8fff) { state.pointIdToFlatId = new Int16Array(numPts); } else { state.pointIdToFlatId = new Int32Array(numPts); } if (numPts + state.extraPoints <= 0xffff) { state.ibo = new Uint16Array(state.iboSize); req.format = 'uint16'; } else { state.ibo = new Uint32Array(state.iboSize); req.format = 'uint32'; } if (cellId <= 0xffff) { state.flatIdToCellId = new Uint16Array(numPts + state.extraPoints); } else { state.flatIdToCellId = new Uint32Array(numPts + state.extraPoints); } state.pointIdToFlatId.fill(-1); state.provokedPointIds.fill(0);
processCell = fillCell; cellId = cellOffset || 0; for (let cellArrayIndex = 0; cellArrayIndex < cellArraySize; ) { state.cellProvokedMap.clear(); func(array[cellArrayIndex], array, cellArrayIndex + 1, cellId, state); cellArrayIndex += array[cellArrayIndex] + 1; cellId++; }
delete state.provokedPointIds; delete state.pointIdToFlatId;
req.nativeArray = state.ibo; model.flatIdToPointId = state.flatIdToPointId; model.flatIdToCellId = state.flatIdToCellId; model.flatSize = state.flatId; model.indexCount = state.iboId; }; }
const DEFAULT_VALUES = { flatIdToPointId: null, flatIdToCellId: null, flatSize: 0, indexCount: 0, };
export function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues);
vtkWebGPUBuffer.extend(publicAPI, model, initialValues);
macro.setGet(publicAPI, model, [ 'flatIdToPointId', 'flatIdToCellId', 'flatSize', 'indexCount', ]);
vtkWebGPUIndexBuffer(publicAPI, model); }
export const newInstance = macro.newInstance(extend);
export default { newInstance, extend, ...Constants };
|