@kitware/vtk.js
Version:
Visualization Toolkit for the Web
398 lines (320 loc) • 13.7 kB
JavaScript
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import _classCallCheck from '@babel/runtime/helpers/classCallCheck';
import _createClass from '@babel/runtime/helpers/createClass';
import macro from '../../macros.js';
import Constants from './BufferManager/Constants.js';
import vtkProperty from '../Core/Property.js';
import vtkWebGPUBuffer from './Buffer.js';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
var Representation = vtkProperty.Representation;
var PrimitiveTypes = Constants.PrimitiveTypes; // Simulate a small map of pointId to flatId for a cell. The original code
// used a map and was 2.6x slower (4.7 to 1.9 seconds). Using two fixed
// length arrays with a count is so much faster even with the required for
// loops and if statements. This only works as we know the usage is
// restricted to clear(), set() get() and has() so the count is always
// incrmenting except for clear where it goes back to 0. Performance
// improvement is probably due to this appoach not hitting the heap but wow
// it is so much faster. Code that adds to these vectors checks against 9 to
// make sure there is room. Switching to test against vec.length -1 results
// in a small performance hit, so if you change 10, search for 9 in this
// small class and change those as well.
var _LimitedMap = /*#__PURE__*/function () {
function _LimitedMap() {
_classCallCheck(this, _LimitedMap);
this.keys = new Uint32Array(10);
this.values = new Uint32Array(10);
this.count = 0;
}
_createClass(_LimitedMap, [{
key: "clear",
value: function clear() {
this.count = 0;
}
}, {
key: "has",
value: function has(key) {
for (var i = 0; i < this.count; i++) {
if (this.keys[i] === key) {
return true;
}
}
return undefined;
}
}, {
key: "get",
value: function get(key) {
for (var i = 0; i < this.count; i++) {
if (this.keys[i] === key) {
return this.values[i];
}
}
return undefined;
}
}, {
key: "set",
value: function set(key, value) {
if (this.count < 9) {
this.keys[this.count] = key;
this.values[this.count++] = value;
}
}
}]);
return _LimitedMap;
}();
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) {
var 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) {
var numPtIds = ptIds.length; // are any points already marked for this cell? If so use that as the provoking point
for (var ptIdx = 0; ptIdx < numPtIds; ptIdx++) {
var _ptId = ptIds[ptIdx];
if (state.cellProvokedMap.has(_ptId)) {
state.ibo[state.iboId++] = state.cellProvokedMap.get(_ptId); // insert remaining ptIds (they do not need to provoke)
for (var ptIdx2 = ptIdx + 1; ptIdx2 < ptIdx + numPtIds; ptIdx2++) {
_ptId = ptIds[ptIdx2 % numPtIds];
var _flatId = _getOrAddFlatId(state, _ptId, cellId); // add to ibo
state.ibo[state.iboId++] = _flatId;
} // all done now
return;
}
} // else have any of the points not been used yet? (not in provokedPointIds)
for (var _ptIdx = 0; _ptIdx < numPtIds; _ptIdx++) {
var _ptId2 = ptIds[_ptIdx];
if (!state.provokedPointIds[_ptId2]) {
var _flatId2 = _getOrAddFlatId(state, _ptId2, cellId); // mark provoking and add to ibo
state.provokedPointIds[_ptId2] = 1;
state.cellProvokedMap.set(_ptId2, _flatId2); // when provoking always set the cellId as an original non-provoking value
// will have been stored and we need to overwrite that
state.flatIdToCellId[_flatId2] = cellId;
state.ibo[state.iboId++] = _flatId2; // insert remaining ptIds (they do not need to provoke)
for (var _ptIdx2 = _ptIdx + 1; _ptIdx2 < _ptIdx + numPtIds; _ptIdx2++) {
_ptId2 = ptIds[_ptIdx2 % numPtIds];
_flatId2 = _getOrAddFlatId(state, _ptId2, cellId); // add to ibo
state.ibo[state.iboId++] = _flatId2;
} // all done now
return;
}
} // if we got here then none of the ptIds could be used to provoke
// so just duplicate the first one
var ptId = ptIds[0];
var flatId = state.flatId;
state.cellProvokedMap.set(ptId, flatId);
state.flatIdToPointId[state.flatId] = ptId;
state.flatIdToCellId[state.flatId] = cellId;
state.flatId++; // add to ibo
state.ibo[state.iboId++] = flatId; // insert remaining ptIds (they do not need to provoke)
for (var _ptIdx3 = 1; _ptIdx3 < numPtIds; _ptIdx3++) {
ptId = ptIds[_ptIdx3];
flatId = _getOrAddFlatId(state, ptId, cellId); // add to ibo
state.ibo[state.iboId++] = flatId;
}
}
function countCell(ptIds, cellId, state) {
var numPtIds = ptIds.length;
state.iboSize += numPtIds; // are any points already marked for this cell? If so use that as the provoking point
for (var ptIdx = 0; ptIdx < numPtIds; ptIdx++) {
var ptId = ptIds[ptIdx];
if (state.cellProvokedMap.has(ptId)) {
return;
}
} // else have any of the points not been used yet? (not in provokedPointIds)
for (var _ptIdx4 = 0; _ptIdx4 < numPtIds; _ptIdx4++) {
var _ptId3 = ptIds[_ptIdx4];
if (!state.provokedPointIds[_ptId3]) {
state.provokedPointIds[_ptId3] = 1;
state.cellProvokedMap.set(_ptId3, 1);
return;
}
} // if we got here then none of the ptIds could be used to provoke
state.cellProvokedMap.set(ptIds[0], 1);
state.extraPoints++;
}
var processCell;
var _single = new Uint32Array(1);
var _double = new Uint32Array(2);
var _triple = new Uint32Array(3);
var _indexCellBuilders = {
// easy, every input point becomes an output point
anythingToPoints: function anythingToPoints(numPoints, cellPts, offset, cellId, state) {
for (var i = 0; i < numPoints; ++i) {
_single[0] = cellPts[offset + i];
processCell(_single, cellId, state);
}
},
linesToWireframe: function linesToWireframe(numPoints, cellPts, offset, cellId, state) {
// for lines we add a bunch of segments
for (var i = 0; i < numPoints - 1; ++i) {
_double[0] = cellPts[offset + i];
_double[1] = cellPts[offset + i + 1];
processCell(_double, cellId, state);
}
},
polysToWireframe: function polysToWireframe(numPoints, cellPts, offset, cellId, state) {
// for polys we add a bunch of segments and close it
if (numPoints > 2) {
for (var i = 0; i < numPoints; ++i) {
_double[0] = cellPts[offset + i];
_double[1] = cellPts[offset + (i + 1) % numPoints];
processCell(_double, cellId, state);
}
}
},
stripsToWireframe: function stripsToWireframe(numPoints, cellPts, offset, cellId, state) {
if (numPoints > 2) {
// for strips we add a bunch of segments and close it
for (var i = 0; i < numPoints - 1; ++i) {
_double[0] = cellPts[offset + i];
_double[1] = cellPts[offset + i + 1];
processCell(_double, cellId, state);
}
for (var _i = 0; _i < numPoints - 2; _i++) {
_double[0] = cellPts[offset + _i];
_double[1] = cellPts[offset + _i + 2];
processCell(_double, cellId, state);
}
}
},
polysToSurface: function polysToSurface(npts, cellPts, offset, cellId, state) {
for (var 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: function stripsToSurface(npts, cellPts, offset, cellId, state) {
for (var 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);
}
}
}; // ----------------------------------------------------------------------------
// vtkWebGPUIndexBufferManager methods
// ----------------------------------------------------------------------------
function vtkWebGPUIndexBuffer(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkWebGPUIndexBuffer');
publicAPI.buildIndexBuffer = function (req) {
var cellArray = req.cells;
var primitiveType = req.primitiveType;
var representation = req.representation;
var cellOffset = req.cellOffset;
var array = cellArray.getData();
var cellArraySize = array.length;
var inRepName = getPrimitiveName(primitiveType);
var numPts = req.numberOfPoints;
var state = {
provokedPointIds: new Uint8Array(numPts),
// size is good
extraPoints: 0,
iboSize: 0,
flatId: 0,
iboId: 0,
cellProvokedMap: new _LimitedMap()
};
var func = null;
if (representation === Representation.POINTS || primitiveType === PrimitiveTypes.Points) {
func = _indexCellBuilders.anythingToPoints;
} else if (representation === Representation.WIREFRAME || primitiveType === PrimitiveTypes.Lines) {
func = _indexCellBuilders["".concat(inRepName, "ToWireframe")];
} else {
func = _indexCellBuilders["".concat(inRepName, "ToSurface")];
} // first we count how many extra provoking points we need
processCell = countCell;
var cellId = cellOffset || 0;
for (var cellArrayIndex = 0; cellArrayIndex < cellArraySize;) {
state.cellProvokedMap.clear();
func(array[cellArrayIndex], array, cellArrayIndex + 1, cellId, state);
cellArrayIndex += array[cellArrayIndex] + 1;
cellId++;
} // then we allocate the remaining structures
// (we pick the best size to save space and transfer costs)
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); // and fill them in
processCell = fillCell;
cellId = cellOffset || 0;
for (var _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; // store the results we need
req.nativeArray = state.ibo;
model.flatIdToPointId = state.flatIdToPointId;
model.flatIdToCellId = state.flatIdToCellId;
model.flatSize = state.flatId;
model.indexCount = state.iboId;
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
var DEFAULT_VALUES = {
flatIdToPointId: null,
flatIdToCellId: null,
flatSize: 0,
indexCount: 0
}; // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
vtkWebGPUBuffer.extend(publicAPI, model, initialValues);
macro.setGet(publicAPI, model, ['flatIdToPointId', 'flatIdToCellId', 'flatSize', 'indexCount']);
vtkWebGPUIndexBuffer(publicAPI, model);
} // ----------------------------------------------------------------------------
var newInstance = macro.newInstance(extend); // ----------------------------------------------------------------------------
var vtkWebGPUIndexBuffer$1 = _objectSpread({
newInstance: newInstance,
extend: extend
}, Constants);
export { vtkWebGPUIndexBuffer$1 as default, extend, newInstance };