import { mat4, quat, vec3 } from 'gl-matrix';
import macro from 'vtk.js/Sources/macros'; import vtkBufferObject from 'vtk.js/Sources/Rendering/OpenGL/BufferObject'; import { ObjectType } from 'vtk.js/Sources/Rendering/OpenGL/BufferObject/Constants'; import { Representation } from 'vtk.js/Sources/Rendering/Core/Property/Constants';
const { vtkErrorMacro } = macro;
function computeInverseShiftAndScaleMatrix(coordShift, coordScale) { const inverseScale = new Float64Array(3); vec3.inverse(inverseScale, coordScale);
const matrix = new Float64Array(16); mat4.fromRotationTranslationScale( matrix, quat.create(), coordShift, inverseScale );
return matrix; }
function shouldApplyCoordShiftAndScale(coordShift, coordScale) { if (coordShift === null || coordScale === null) { return false; }
return !( vec3.exactEquals(coordShift, [0, 0, 0]) && vec3.exactEquals(coordScale, [1, 1, 1]) ); }
function vtkOpenGLCellArrayBufferObject(publicAPI, model) { model.classHierarchy.push('vtkOpenGLCellArrayBufferObject');
publicAPI.setType(ObjectType.ARRAY_BUFFER);
publicAPI.createVBO = ( cellArray, inRep, outRep, options, selectionMaps = null ) => { if (!cellArray.getData() || !cellArray.getData().length) { model.elementCount = 0; return 0; }
model.blockSize = 3; model.vertexOffset = 0; model.normalOffset = 0; model.tCoordOffset = 0; model.tCoordComponents = 0; model.colorComponents = 0; model.colorOffset = 0; model.customData = [];
const pointData = options.points.getData(); let normalData = null; let tcoordData = null; let colorData = null;
const colorComponents = options.colors ? options.colors.getNumberOfComponents() : 0; const textureComponents = options.tcoords ? options.tcoords.getNumberOfComponents() : 0;
if (options.normals) { model.normalOffset = 4 * model.blockSize; model.blockSize += 3; normalData = options.normals.getData(); }
if (options.customAttributes) { options.customAttributes.forEach((a) => { if (a) { model.customData.push({ data: a.getData(), offset: 4 * model.blockSize, components: a.getNumberOfComponents(), name: a.getName(), }); model.blockSize += a.getNumberOfComponents(); } }); }
if (options.tcoords) { model.tCoordOffset = 4 * model.blockSize; model.tCoordComponents = textureComponents; model.blockSize += textureComponents; tcoordData = options.tcoords.getData(); }
if (options.colors) { model.colorComponents = options.colors.getNumberOfComponents(); model.colorOffset = 0; colorData = options.colors.getData(); if (!model.colorBO) { model.colorBO = vtkBufferObject.newInstance(); } model.colorBO.setOpenGLRenderWindow(model._openGLRenderWindow); } else { model.colorBO = null; } model.stride = 4 * model.blockSize;
let pointIdx = 0; let normalIdx = 0; let tcoordIdx = 0; let colorIdx = 0; let custIdx = 0; let cellCount = 0; let addAPoint;
const cellBuilders = { anythingToPoints(numPoints, cellPts, offset, cellId) { for (let i = 0; i < numPoints; ++i) { addAPoint(cellPts[offset + i], cellId); } }, linesToWireframe(numPoints, cellPts, offset, cellIdx) { for (let i = 0; i < numPoints - 1; ++i) { addAPoint(cellPts[offset + i], cellIdx); addAPoint(cellPts[offset + i + 1], cellIdx); } }, polysToWireframe(numPoints, cellPts, offset, cellIdx) { if (numPoints > 2) { for (let i = 0; i < numPoints; ++i) { addAPoint(cellPts[offset + i], cellIdx); addAPoint(cellPts[offset + ((i + 1) % numPoints)], cellIdx); } } }, stripsToWireframe(numPoints, cellPts, offset, cellIdx) { if (numPoints > 2) { for (let i = 0; i < numPoints - 1; ++i) { addAPoint(cellPts[offset + i], cellIdx); addAPoint(cellPts[offset + i + 1], cellIdx); } for (let i = 0; i < numPoints - 2; i++) { addAPoint(cellPts[offset + i], cellIdx); addAPoint(cellPts[offset + i + 2], cellIdx); } } }, polysToSurface(npts, cellPts, offset, cellIdx) { for (let i = 0; i < npts - 2; i++) { addAPoint(cellPts[offset + 0], cellIdx); addAPoint(cellPts[offset + i + 1], cellIdx); addAPoint(cellPts[offset + i + 2], cellIdx); } }, stripsToSurface(npts, cellPts, offset, cellIdx) { for (let i = 0; i < npts - 2; i++) { addAPoint(cellPts[offset + i], cellIdx); addAPoint(cellPts[offset + i + 1 + (i % 2)], cellIdx); addAPoint(cellPts[offset + i + 1 + ((i + 1) % 2)], cellIdx); } }, };
const cellCounters = { anythingToPoints(numPoints, cellPts) { return numPoints; }, linesToWireframe(numPoints, cellPts) { if (numPoints > 1) { return (numPoints - 1) * 2; } return 0; }, polysToWireframe(numPoints, cellPts) { if (numPoints > 2) { return numPoints * 2; } return 0; }, stripsToWireframe(numPoints, cellPts) { if (numPoints > 2) { return numPoints * 4 - 6; } return 0; }, polysToSurface(npts, cellPts) { if (npts > 2) { return (npts - 2) * 3; } return 0; }, stripsToSurface(npts, cellPts, offset) { if (npts > 2) { return (npts - 2) * 3; } return 0; }, };
let func = null; let countFunc = null; if (outRep === Representation.POINTS || inRep === 'verts') { func = cellBuilders.anythingToPoints; countFunc = cellCounters.anythingToPoints; } else if (outRep === Representation.WIREFRAME || inRep === 'lines') { func = cellBuilders[`${inRep}ToWireframe`]; countFunc = cellCounters[`${inRep}ToWireframe`]; } else { func = cellBuilders[`${inRep}ToSurface`]; countFunc = cellCounters[`${inRep}ToSurface`]; }
const array = cellArray.getData(); const size = array.length; let caboCount = 0; for (let index = 0; index < size; ) { caboCount += countFunc(array[index], array); index += array[index] + 1; }
let packedUCVBO = null; const packedVBO = new Float32Array(caboCount * model.blockSize); if (colorData) { packedUCVBO = new Uint8Array(caboCount * 4); } let vboidx = 0; let ucidx = 0;
let diagSq = 0.0; let distSq = 0.0; for (let i = 0; i < 3; ++i) { const range = options.points.getRange(i);
const delta = range[1] - range[0]; diagSq += delta * delta;
const distShift = 0.5 * (range[1] + range[0]); distSq += distShift * distShift; }
const useShiftAndScale = diagSq > 0 && (Math.abs(distSq) / diagSq > 1.0e6 || Math.abs(Math.log10(diagSq)) > 3.0 || (diagSq === 0 && distSq > 1.0e6));
if (useShiftAndScale) { const coordShift = new Float64Array(3); const coordScale = new Float64Array(3); for (let i = 0; i < 3; ++i) { const range = options.points.getRange(i); const delta = range[1] - range[0];
coordShift[i] = 0.5 * (range[1] + range[0]); coordScale[i] = delta > 0 ? 1.0 / delta : 1.0; } publicAPI.setCoordShiftAndScale(coordShift, coordScale); } else if (model.coordShiftAndScaleEnabled === true) { publicAPI.setCoordShiftAndScale(null, null); }
if (selectionMaps) { if (!selectionMaps.points && !selectionMaps.cells) { selectionMaps.points = new Int32Array(caboCount); selectionMaps.cells = new Int32Array(caboCount); } else { const newPoints = new Int32Array( caboCount + selectionMaps.points.length ); newPoints.set(selectionMaps.points); selectionMaps.points = newPoints; const newCells = new Int32Array(caboCount + selectionMaps.cells.length); newCells.set(selectionMaps.cells); selectionMaps.cells = newCells; } }
let pointCount = options.vertexOffset; addAPoint = function addAPointFunc(pointId, cellId) { if (selectionMaps) { selectionMaps.points[pointCount] = pointId; selectionMaps.cells[pointCount] = cellCount + options.cellOffset; } ++pointCount;
pointIdx = pointId * 3;
if (!model.coordShiftAndScaleEnabled) { packedVBO[vboidx++] = pointData[pointIdx++]; packedVBO[vboidx++] = pointData[pointIdx++]; packedVBO[vboidx++] = pointData[pointIdx++]; } else { packedVBO[vboidx++] = (pointData[pointIdx++] - model.coordShift[0]) * model.coordScale[0]; packedVBO[vboidx++] = (pointData[pointIdx++] - model.coordShift[1]) * model.coordScale[1]; packedVBO[vboidx++] = (pointData[pointIdx++] - model.coordShift[2]) * model.coordScale[2]; }
if (normalData !== null) { if (options.haveCellNormals) { normalIdx = (cellCount + options.cellOffset) * 3; } else { normalIdx = pointId * 3; } packedVBO[vboidx++] = normalData[normalIdx++]; packedVBO[vboidx++] = normalData[normalIdx++]; packedVBO[vboidx++] = normalData[normalIdx++]; }
model.customData.forEach((attr) => { custIdx = pointId * attr.components; for (let j = 0; j < attr.components; ++j) { packedVBO[vboidx++] = attr.data[custIdx++]; } });
if (tcoordData !== null) { if (options.useTCoordsPerCell) { tcoordIdx = cellId * textureComponents; } else { tcoordIdx = pointId * textureComponents; } for (let j = 0; j < textureComponents; ++j) { packedVBO[vboidx++] = tcoordData[tcoordIdx++]; } }
if (colorData !== null) { if (options.haveCellScalars) { colorIdx = (cellCount + options.cellOffset) * colorComponents; } else { colorIdx = pointId * colorComponents; } packedUCVBO[ucidx++] = colorData[colorIdx++]; packedUCVBO[ucidx++] = colorData[colorIdx++]; packedUCVBO[ucidx++] = colorData[colorIdx++]; packedUCVBO[ucidx++] = colorComponents === 4 ? colorData[colorIdx++] : 255; } };
for (let index = 0; index < size; index += array[index] + 1, cellCount++) { func(array[index], array, index + 1, cellCount + options.cellOffset); } model.elementCount = caboCount; publicAPI.upload(packedVBO, ObjectType.ARRAY_BUFFER); if (model.colorBO) { model.colorBOStride = 4; model.colorBO.upload(packedUCVBO, ObjectType.ARRAY_BUFFER); } return cellCount; };
publicAPI.setCoordShiftAndScale = (coordShift, coordScale) => { if ( coordShift !== null && (coordShift.constructor !== Float64Array || coordShift.length !== 3) ) { vtkErrorMacro('Wrong type for coordShift, expected vec3 or null'); return; }
if ( coordScale !== null && (coordScale.constructor !== Float64Array || coordScale.length !== 3) ) { vtkErrorMacro('Wrong type for coordScale, expected vec3 or null'); return; }
if ( model.coordShift === null || coordShift === null || !vec3.equals(coordShift, model.coordShift) ) { model.coordShift = coordShift; }
if ( model.coordScale === null || coordScale === null || !vec3.equals(coordScale, model.coordScale) ) { model.coordScale = coordScale; }
model.coordShiftAndScaleEnabled = shouldApplyCoordShiftAndScale( model.coordShift, model.coordScale );
if (model.coordShiftAndScaleEnabled) { model.inverseShiftAndScaleMatrix = computeInverseShiftAndScaleMatrix( model.coordShift, model.coordScale ); } else { model.inverseShiftAndScaleMatrix = null; } }; }
const DEFAULT_VALUES = { elementCount: 0, stride: 0, colorBOStride: 0, vertexOffset: 0, normalOffset: 0, tCoordOffset: 0, tCoordComponents: 0, colorOffset: 0, colorComponents: 0, tcoordBO: null, customData: [], coordShift: null, coordScale: null, coordShiftAndScaleEnabled: false, inverseShiftAndScaleMatrix: null, };
export function extend(publicAPI, model, initialValues = {}) { Object.assign(model, DEFAULT_VALUES, initialValues);
vtkBufferObject.extend(publicAPI, model, initialValues);
macro.setGet(publicAPI, model, [ 'colorBO', 'elementCount', 'stride', 'colorBOStride', 'vertexOffset', 'normalOffset', 'tCoordOffset', 'tCoordComponents', 'colorOffset', 'colorComponents', 'customData', ]);
macro.get(publicAPI, model, [ 'coordShift', 'coordScale', 'coordShiftAndScaleEnabled', 'inverseShiftAndScaleMatrix', ]);
vtkOpenGLCellArrayBufferObject(publicAPI, model); }
export const newInstance = macro.newInstance(extend);
export default { newInstance, extend };
|