@thewtex/vtk.js-esm
Version:
Visualization Toolkit for the Web
553 lines (459 loc) • 19 kB
JavaScript
import _defineProperty from '@babel/runtime/helpers/defineProperty';
import { obj, setGet, newInstance as newInstance$1, newTypedArray, vtkDebugMacro as vtkDebugMacro$1 } from '../../macro.js';
import { j as cross, l as normalize } from '../../Common/Core/Math/index.js';
import vtkWebGPUBuffer from './Buffer.js';
import vtkWebGPUTypes from './Types.js';
import vtkProperty from '../Core/Property.js';
import Constants from './BufferManager/Constants.js';
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (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 = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var BufferUsage = Constants.BufferUsage,
PrimitiveTypes = Constants.PrimitiveTypes;
var Representation = vtkProperty.Representation;
var vtkDebugMacro = vtkDebugMacro$1; // the webgpu constants all show up as undefined
/* eslint-disable no-undef */
// ----------------------------------------------------------------------------
// Static API
// ----------------------------------------------------------------------------
var STATIC = {};
function requestMatches(req1, req2) {
if (req1.time !== req2.time) return false;
if (req1.format !== req2.format) return false;
if (req1.usage !== req2.usage) return false;
if (req1.hash !== req2.hash) return false;
return true;
}
var cellCounters = {
// easy, every input point becomes an output point
anythingToPoints: function anythingToPoints(numPoints, cellPts) {
return numPoints;
},
linesToWireframe: function linesToWireframe(numPoints, cellPts) {
if (numPoints > 1) {
return (numPoints - 1) * 2;
}
return 0;
},
polysToWireframe: function polysToWireframe(numPoints, cellPts) {
if (numPoints > 2) {
return numPoints * 2;
}
return 0;
},
stripsToWireframe: function stripsToWireframe(numPoints, cellPts) {
if (numPoints > 2) {
return numPoints * 4 - 6;
}
return 0;
},
polysToSurface: function polysToSurface(npts, cellPts) {
if (npts > 2) {
return (npts - 2) * 3;
}
return 0;
},
stripsToSurface: function stripsToSurface(npts, cellPts, offset) {
if (numPoints > 2) {
return (npts - 2) * 3;
}
return 0;
}
};
function getPrimitiveName(primType) {
switch (primType) {
case PrimitiveTypes.Points:
return 'points';
case PrimitiveTypes.Lines:
return 'lines';
case PrimitiveTypes.Triangles:
return 'polys';
case PrimitiveTypes.TriangleStrips:
return 'strips';
default:
return '';
}
}
function getOutputSize(cellArray, representation, inRepName) {
var countFunc = null;
if (representation === Representation.POINTS || inRepName === 'points') {
countFunc = cellCounters.anythingToPoints;
} else if (representation === Representation.WIREFRAME || inRepName === 'lines') {
countFunc = cellCounters["".concat(inRepName, "ToWireframe")];
} else {
countFunc = cellCounters["".concat(inRepName, "ToSurface")];
}
var array = cellArray.getData();
var size = array.length;
var caboCount = 0;
for (var index = 0; index < size;) {
caboCount += countFunc(array[index], array);
index += array[index] + 1;
}
return caboCount;
}
function packArray(cellArray, primType, representation, inArray, outputType, options) {
var result = {
elementCount: 0,
blockSize: 0,
stride: 0
};
if (!cellArray.getData() || !cellArray.getData().length) {
return result;
} // setup shift and scale
var shift = [0.0, 0.0, 0.0, 0.0];
if (options.shift) {
if (options.shift.length) {
shift = options.shift;
} else {
shift.fill(options.shift);
}
}
var scale = [1.0, 1.0, 1.0, 1.0];
if (options.scale) {
if (options.scale.length) {
scale = options.scale;
} else {
scale.fill(options.scale);
}
}
var packExtra = Object.prototype.hasOwnProperty.call(options, 'packExtra') ? options.packExtra : false;
var pointData = inArray.getData();
var addAPoint;
var cellBuilders = {
// easy, every input point becomes an output point
anythingToPoints: function anythingToPoints(numPoints, cellPts, offset, cellId) {
for (var i = 0; i < numPoints; ++i) {
addAPoint(cellPts[offset + i], cellId);
}
},
linesToWireframe: function linesToWireframe(numPoints, cellPts, offset, cellId) {
// for lines we add a bunch of segments
for (var i = 0; i < numPoints - 1; ++i) {
addAPoint(cellPts[offset + i], cellId);
addAPoint(cellPts[offset + i + 1], cellId);
}
},
polysToWireframe: function polysToWireframe(numPoints, cellPts, offset, cellId) {
// for polys we add a bunch of segments and close it
if (numPoints > 2) {
for (var i = 0; i < numPoints; ++i) {
addAPoint(cellPts[offset + i], cellId);
addAPoint(cellPts[offset + (i + 1) % numPoints], cellId);
}
}
},
stripsToWireframe: function stripsToWireframe(numPoints, cellPts, offset, cellId) {
if (numPoints > 2) {
// for strips we add a bunch of segments and close it
for (var i = 0; i < numPoints - 1; ++i) {
addAPoint(cellPts[offset + i], cellId);
addAPoint(cellPts[offset + i + 1], cellId);
}
for (var _i = 0; _i < numPoints - 2; _i++) {
addAPoint(cellPts[offset + _i], cellId);
addAPoint(cellPts[offset + _i + 2], cellId);
}
}
},
polysToSurface: function polysToSurface(npts, cellPts, offset, cellId) {
for (var i = 0; i < npts - 2; i++) {
addAPoint(cellPts[offset + 0], cellId);
addAPoint(cellPts[offset + i + 1], cellId);
addAPoint(cellPts[offset + i + 2], cellId);
}
},
stripsToSurface: function stripsToSurface(npts, cellPts, offset, cellId) {
for (var i = 0; i < npts - 2; i++) {
addAPoint(cellPts[offset + i], cellId);
addAPoint(cellPts[offset + i + 1 + i % 2], cellId);
addAPoint(cellPts[offset + i + 1 + (i + 1) % 2], cellId);
}
}
};
var inRepName = getPrimitiveName(primType);
var func = null;
if (representation === Representation.POINTS || primType === PrimitiveTypes.Points) {
func = cellBuilders.anythingToPoints;
} else if (representation === Representation.WIREFRAME || primType === PrimitiveTypes.Lines) {
func = cellBuilders["".concat(inRepName, "ToWireframe")];
} else {
func = cellBuilders["".concat(inRepName, "ToSurface")];
}
var array = cellArray.getData();
var size = array.length;
var caboCount = getOutputSize(cellArray, representation, inRepName);
var vboidx = 0;
var numComp = inArray.getNumberOfComponents();
var packedVBO = newTypedArray(outputType, caboCount * (numComp + (packExtra ? 1 : 0))); // pick the right function based on point versus cell data
var getData = function getData(ptId, cellId) {
return pointData[ptId];
};
if (options.cellData) {
getData = function getData(ptId, cellId) {
return pointData[cellId];
};
} // add data based on number of components
if (numComp === 1) {
addAPoint = function addAPointFunc(i, cellid) {
packedVBO[vboidx++] = scale[0] * getData(i, cellid) + shift[0];
};
} else if (numComp === 2) {
addAPoint = function addAPointFunc(i, cellid) {
packedVBO[vboidx++] = scale[0] * getData(i * 2, cellid * 2) + shift[0];
packedVBO[vboidx++] = scale[1] * getData(i * 2 + 1, cellid * 2 + 1) + shift[1];
};
} else if (numComp === 3 && !packExtra) {
addAPoint = function addAPointFunc(i, cellid) {
packedVBO[vboidx++] = scale[0] * getData(i * 3, cellid * 3) + shift[0];
packedVBO[vboidx++] = scale[1] * getData(i * 3 + 1, cellid * 3 + 1) + shift[1];
packedVBO[vboidx++] = scale[2] * getData(i * 3 + 2, cellid * 3 + 2) + shift[2];
};
} else if (numComp === 3 && packExtra) {
addAPoint = function addAPointFunc(i, cellid) {
packedVBO[vboidx++] = scale[0] * getData(i * 3, cellid * 3) + shift[0];
packedVBO[vboidx++] = scale[1] * getData(i * 3 + 1, cellid * 3 + 1) + shift[1];
packedVBO[vboidx++] = scale[2] * getData(i * 3 + 2, cellid * 3 + 2) + shift[2];
packedVBO[vboidx++] = scale[3] * 1.0 + shift[3];
};
} else if (numComp === 4) {
addAPoint = function addAPointFunc(i, cellid) {
packedVBO[vboidx++] = scale[0] * getData(i * 4, cellid * 4) + shift[0];
packedVBO[vboidx++] = scale[1] * getData(i * 4 + 1, cellid * 4 + 1) + shift[1];
packedVBO[vboidx++] = scale[2] * getData(i * 4 + 2, cellid * 4 + 2) + shift[2];
packedVBO[vboidx++] = scale[3] * getData(i * 4 + 3, cellid * 4 + 3) + shift[3];
};
}
var cellId = options.cellOffset;
for (var index = 0; index < size;) {
func(array[index], array, index + 1, cellId);
index += array[index] + 1;
cellId++;
}
result.nativeArray = packedVBO;
result.elementCount = caboCount;
return result;
}
function getNormal(pointData, i0, i1, i2) {
var v1 = [pointData[i2 * 3] - pointData[i1 * 3], pointData[i2 * 3 + 1] - pointData[i1 * 3 + 1], pointData[i2 * 3 + 2] - pointData[i1 * 3 + 2]];
var v2 = [pointData[i0 * 3] - pointData[i1 * 3], pointData[i0 * 3 + 1] - pointData[i1 * 3 + 1], pointData[i0 * 3 + 2] - pointData[i1 * 3 + 2]];
var result = [];
cross(v1, v2, result);
normalize(result);
return result;
}
function generateNormals(cellArray, primType, representation, inArray) {
if (!cellArray.getData() || !cellArray.getData().length) {
return null;
}
var pointData = inArray.getData();
var addAPoint;
var cellBuilders = {
polysToPoints: function polysToPoints(numPoints, cellPts, offset) {
var normal = getNormal(pointData, cellPts[offset], cellPts[offset + 1], cellPts[offset + 2]);
for (var i = 0; i < numPoints; ++i) {
addAPoint(normal);
}
},
polysToWireframe: function polysToWireframe(numPoints, cellPts, offset) {
// for polys we add a bunch of segments and close it
// compute the normal
var normal = getNormal(pointData, cellPts[offset], cellPts[offset + 1], cellPts[offset + 2]);
for (var i = 0; i < numPoints; ++i) {
addAPoint(normal);
addAPoint(normal);
}
},
polysToSurface: function polysToSurface(npts, cellPts, offset) {
if (npts < 3) {
// ignore degenerate triangles
vtkDebugMacro('skipping degenerate triangle');
} else {
// compute the normal
var normal = getNormal(pointData, cellPts[offset], cellPts[offset + 1], cellPts[offset + 2]);
for (var i = 0; i < npts - 2; i++) {
addAPoint(normal);
addAPoint(normal);
addAPoint(normal);
}
}
}
};
var primName = getPrimitiveName(primType);
var func = null;
if (representation === Representation.POINTS) {
func = cellBuilders["".concat(primName, "ToPoints")];
} else if (representation === Representation.WIREFRAME) {
func = cellBuilders["".concat(primName, "ToWireframe")];
} else {
func = cellBuilders["".concat(primName, "ToSurface")];
}
var caboCount = getOutputSize(cellArray, representation, primName);
var vboidx = 0;
var packedVBO = new Int8Array(caboCount * 4);
addAPoint = function addAPointFunc(normal) {
packedVBO[vboidx++] = 127 * normal[0];
packedVBO[vboidx++] = 127 * normal[1];
packedVBO[vboidx++] = 127 * normal[2];
packedVBO[vboidx++] = 127;
};
var array = cellArray.getData();
var size = array.length;
for (var index = 0; index < size;) {
func(array[index], array, index + 1);
index += array[index] + 1;
}
return packedVBO;
} // ----------------------------------------------------------------------------
// vtkWebGPUBufferManager methods
// ----------------------------------------------------------------------------
function vtkWebGPUBufferManager(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkWebGPUBufferManager'); // is the buffer already present?
publicAPI.hasBuffer = function (req) {
if (req.source) {
// if a matching buffer already exists then return true
if (model.buffers.has(req.source)) {
var dabuffers = model.buffers.get(req.source);
for (var i = 0; i < dabuffers.length; i++) {
if (requestMatches(dabuffers[i].request, req)) {
return true;
}
}
}
}
return false;
}; // we cache based on the passed in source, when the source is
// garbage collected then the cache entry is removed. If a source
// is not provided then the buffer is NOT cached and you are on your own
// if you want to share it etc
publicAPI.getBuffer = function (req) {
if (req.source) {
// if a matching buffer already exists then return it
if (model.buffers.has(req.source)) {
var dabuffers = model.buffers.get(req.source);
for (var i = 0; i < dabuffers.length; i++) {
if (requestMatches(dabuffers[i].request, req)) {
return dabuffers[i].buffer;
}
}
}
} // if a dataArray is provided set the nativeArray
if (req.dataArray && !req.nativeArray) {
req.nativeArray = req.dataArray.getData();
} // create one
var buffer = vtkWebGPUBuffer.newInstance();
buffer.setDevice(model.device);
var gpuUsage = null; // handle uniform buffers
if (req.usage === BufferUsage.UniformArray) {
/* eslint-disable no-bitwise */
gpuUsage = GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST;
/* eslint-enable no-bitwise */
buffer.createAndWrite(req.nativeArray, gpuUsage);
} // handle storage buffers
if (req.usage === BufferUsage.Storage) {
/* eslint-disable no-bitwise */
gpuUsage = GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST;
/* eslint-enable no-bitwise */
buffer.createAndWrite(req.nativeArray, gpuUsage);
} // handle textures
if (req.usage === BufferUsage.Texture) {
/* eslint-disable no-bitwise */
gpuUsage = GPUBufferUsage.COPY_SRC;
/* eslint-enable no-bitwise */
buffer.createAndWrite(req.nativeArray, gpuUsage);
} // all of the below types that have gpuUsage = VERTEX require format
// to be provided.
// handle point data
if (req.usage === BufferUsage.PointArray) {
gpuUsage = GPUBufferUsage.VERTEX;
var arrayType = vtkWebGPUTypes.getNativeTypeFromBufferFormat(req.format);
var result = packArray(req.cells, req.primitiveType, req.representation, req.dataArray, arrayType, {
packExtra: req.packExtra,
shift: req.shift,
scale: req.scale,
cellData: req.cellData,
cellOffset: req.cellOffset
}); // console.log(result);
buffer.createAndWrite(result.nativeArray, gpuUsage);
buffer.setStrideInBytes(vtkWebGPUTypes.getByteStrideFromBufferFormat(req.format));
buffer.setArrayInformation([{
offset: 0,
format: req.format
}]);
} // handle normals from points, snorm8x4
if (req.usage === BufferUsage.NormalsFromPoints) {
gpuUsage = GPUBufferUsage.VERTEX;
var normals = generateNormals(req.cells, req.primitiveType, req.representation, req.dataArray);
buffer.createAndWrite(normals, gpuUsage);
buffer.setStrideInBytes(vtkWebGPUTypes.getByteStrideFromBufferFormat(req.format));
buffer.setArrayInformation([{
offset: 0,
format: req.format
}]);
}
if (req.usage === BufferUsage.RawVertex) {
gpuUsage = GPUBufferUsage.VERTEX;
buffer.createAndWrite(req.nativeArray, gpuUsage);
buffer.setStrideInBytes(vtkWebGPUTypes.getByteStrideFromBufferFormat(req.format));
buffer.setArrayInformation([{
offset: 0,
format: req.format
}]);
}
buffer.setSourceTime(req.time); // cache the buffer if we have a dataArray.
// We create a new req that only has the 4 fields required for
// a comparison to avoid GC cycles
if (req.source) {
if (!model.buffers.has(req.source)) {
model.buffers.set(req.source, []);
}
var _dabuffers = model.buffers.get(req.source);
_dabuffers.push({
request: {
time: req.time,
format: req.format,
usage: req.usage,
hash: req.hash
},
buffer: buffer
});
}
return buffer;
};
publicAPI.getFullScreenQuadBuffer = function () {
if (model.fullScreenQuadBuffer) {
return model.fullScreenQuadBuffer;
}
model.fullScreenQuadBuffer = vtkWebGPUBuffer.newInstance();
model.fullScreenQuadBuffer.setDevice(model.device); // prettier-ignore
var array = new Float32Array([-1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0]);
model.fullScreenQuadBuffer.createAndWrite(array, GPUBufferUsage.VERTEX);
model.fullScreenQuadBuffer.setStrideInBytes(12);
model.fullScreenQuadBuffer.setArrayInformation([{
offset: 0,
format: 'float32x3'
}]);
return model.fullScreenQuadBuffer;
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
var DEFAULT_VALUES = {
device: null,
fullScreenQuadBuffer: null
}; // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues); // Object methods
obj(publicAPI, model); // this is a cache, and a cache with GC pretty much means WeakMap
model.buffers = new WeakMap();
setGet(publicAPI, model, ['device']);
vtkWebGPUBufferManager(publicAPI, model);
} // ----------------------------------------------------------------------------
var newInstance = newInstance$1(extend); // ----------------------------------------------------------------------------
var vtkWebGPUBufferManager$1 = _objectSpread(_objectSpread({
newInstance: newInstance,
extend: extend
}, STATIC), Constants);
export default vtkWebGPUBufferManager$1;
export { STATIC, extend, newInstance };