@kitware/vtk.js
Version:
Visualization Toolkit for the Web
997 lines (793 loc) • 42.6 kB
JavaScript
import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
import { newInstance as newInstance$1, obj, get, vtkErrorMacro as vtkErrorMacro$1 } from '../../macros.js';
import { mat4, vec3 } from 'gl-matrix';
import vtkClosedPolyLineToSurfaceFilter from '../../Filters/General/ClosedPolyLineToSurfaceFilter.js';
import vtkCubeSource from '../../Filters/Sources/CubeSource.js';
import vtkCutter from '../../Filters/Core/Cutter.js';
import vtkDataArray from '../../Common/Core/DataArray.js';
import vtkHelper from './Helper.js';
import { f as vtkMath } from '../../Common/Core/Math/index.js';
import vtkOpenGLTexture from './Texture.js';
import vtkPlane from '../../Common/DataModel/Plane.js';
import vtkPolyData from '../../Common/DataModel/PolyData.js';
import vtkReplacementShaderMapper from './ReplacementShaderMapper.js';
import vtkShaderProgram from './ShaderProgram.js';
import vtkViewNode from '../SceneGraph/ViewNode.js';
import { v as vtkImageResliceMapperVS } from './glsl/vtkImageResliceMapperVS.glsl.js';
import { v as vtkImageResliceMapperFS } from './glsl/vtkImageResliceMapperFS.glsl.js';
import InterpolationType from '../Core/ImageProperty/Constants.js';
import { VtkDataTypes } from '../../Common/Core/DataArray/Constants.js';
import { Filter } from './Texture/Constants.js';
import { Representation } from '../Core/Property/Constants.js';
import { registerOverride } from './ViewNodeFactory.js';
var vtkErrorMacro = vtkErrorMacro$1; // ----------------------------------------------------------------------------
// helper methods
// ----------------------------------------------------------------------------
function computeFnToString(property, fn, numberOfComponents) {
var pwfun = fn.apply(property);
if (pwfun) {
var iComps = property.getIndependentComponents();
return "".concat(property.getMTime(), "-").concat(iComps, "-").concat(numberOfComponents);
}
return '0';
}
function safeMatrixMultiply(matrixArray, matrixType, tmpMat) {
matrixType.identity(tmpMat);
return matrixArray.reduce(function (res, matrix, index) {
if (index === 0) {
return matrix ? matrixType.copy(res, matrix) : matrixType.identity(res);
}
return matrix ? matrixType.multiply(res, res, matrix) : res;
}, tmpMat);
} // ----------------------------------------------------------------------------
// vtkOpenGLImageResliceMapper methods
// ----------------------------------------------------------------------------
function vtkOpenGLImageResliceMapper(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkOpenGLImageResliceMapper');
publicAPI.buildPass = function (prepass) {
if (prepass) {
model.currentRenderPass = null;
model._openGLImageSlice = publicAPI.getFirstAncestorOfType('vtkOpenGLImageSlice');
model._openGLRenderer = publicAPI.getFirstAncestorOfType('vtkOpenGLRenderer');
var ren = model._openGLRenderer.getRenderable();
model._openGLCamera = model._openGLRenderer.getViewNodeFor(ren.getActiveCamera());
model._openGLRenderWindow = model._openGLRenderer.getParent();
model.context = model._openGLRenderWindow.getContext();
model.tris.setOpenGLRenderWindow(model._openGLRenderWindow);
if (!model.openGLTexture) {
model.openGLTexture = vtkOpenGLTexture.newInstance();
}
model.openGLTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
model.pwfTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
}
};
publicAPI.translucentPass = function (prepass, renderPass) {
if (prepass) {
model.currentRenderPass = renderPass;
publicAPI.render();
}
};
publicAPI.zBufferPass = function (prepass) {
if (prepass) {
model.haveSeenDepthRequest = true;
model.renderDepth = true;
publicAPI.render();
model.renderDepth = false;
}
};
publicAPI.opaqueZBufferPass = function (prepass) {
return publicAPI.zBufferPass(prepass);
};
publicAPI.opaquePass = function (prepass) {
if (prepass) {
publicAPI.render();
}
};
publicAPI.getCoincidentParameters = function (ren, actor) {
if (model.renderable.getResolveCoincidentTopology()) {
return model.renderable.getCoincidentTopologyPolygonOffsetParameters();
}
return null;
}; // Renders myself
publicAPI.render = function () {
var actor = model._openGLImageSlice.getRenderable();
var ren = model._openGLRenderer.getRenderable();
publicAPI.renderPiece(ren, actor);
};
publicAPI.renderPiece = function (ren, actor) {
publicAPI.invokeEvent({
type: 'StartEvent'
});
model.renderable.update();
model.currentInput = model.renderable.getInputData();
if (!model.currentInput) {
vtkErrorMacro('No input!');
return;
}
publicAPI.updateResliceGeometry();
publicAPI.renderPieceStart(ren, actor);
publicAPI.renderPieceDraw(ren, actor);
publicAPI.renderPieceFinish(ren, actor);
publicAPI.invokeEvent({
type: 'EndEvent'
});
};
publicAPI.renderPieceStart = function (ren, actor) {
// make sure the BOs are up to date
publicAPI.updateBufferObjects(ren, actor);
var iType = actor.getProperty().getInterpolationType();
if (iType === InterpolationType.NEAREST) {
model.openGLTexture.setMinificationFilter(Filter.NEAREST);
model.openGLTexture.setMagnificationFilter(Filter.NEAREST);
model.colorTexture.setMinificationFilter(Filter.NEAREST);
model.colorTexture.setMagnificationFilter(Filter.NEAREST);
model.pwfTexture.setMinificationFilter(Filter.NEAREST);
model.pwfTexture.setMagnificationFilter(Filter.NEAREST);
} else {
model.openGLTexture.setMinificationFilter(Filter.LINEAR);
model.openGLTexture.setMagnificationFilter(Filter.LINEAR);
model.colorTexture.setMinificationFilter(Filter.LINEAR);
model.colorTexture.setMagnificationFilter(Filter.LINEAR);
model.pwfTexture.setMinificationFilter(Filter.LINEAR);
model.pwfTexture.setMagnificationFilter(Filter.LINEAR);
} // No buffer objects bound.
model.lastBoundBO = null;
};
publicAPI.renderPieceDraw = function (ren, actor) {
var gl = model.context; // render the texture
model.openGLTexture.activate();
model.colorTexture.activate();
model.pwfTexture.activate(); // update shaders if required
publicAPI.updateShaders(model.tris, ren, actor); // Finally draw
gl.drawArrays(gl.TRIANGLES, 0, model.tris.getCABO().getElementCount());
model.tris.getVAO().release();
model.openGLTexture.deactivate();
model.colorTexture.deactivate();
model.pwfTexture.deactivate();
};
publicAPI.renderPieceFinish = function (ren, actor) {};
publicAPI.updateBufferObjects = function (ren, actor) {
// Rebuild buffer objects if needed
if (publicAPI.getNeedToRebuildBufferObjects(ren, actor)) {
publicAPI.buildBufferObjects(ren, actor);
}
};
publicAPI.getNeedToRebuildBufferObjects = function (ren, actor) {
return model.VBOBuildTime.getMTime() < publicAPI.getMTime() || model.VBOBuildTime.getMTime() < actor.getMTime() || model.VBOBuildTime.getMTime() < model.renderable.getMTime() || model.VBOBuildTime.getMTime() < actor.getProperty().getMTime() || model.VBOBuildTime.getMTime() < model.currentInput.getMTime() || model.VBOBuildTime.getMTime() < model.resliceGeom.getMTime();
};
publicAPI.buildBufferObjects = function (ren, actor) {
var _image$getPointData;
var image = model.currentInput;
if (!image) {
return;
}
var scalars = (_image$getPointData = image.getPointData()) === null || _image$getPointData === void 0 ? void 0 : _image$getPointData.getScalars();
if (!scalars) {
return;
}
var numComp = scalars.getNumberOfComponents();
if (!model._externalOpenGLTexture) {
var _toString = "".concat(image.getMTime(), "A").concat(scalars.getMTime());
if (model.openGLTextureString !== _toString) {
// Build the image scalar texture
var dims = image.getDimensions(); // Use norm16 for the 3D texture if the extension is available
model.openGLTexture.getOglNorm16Ext(model.context.getExtension('EXT_texture_norm16'));
model.openGLTexture.releaseGraphicsResources(model._openGLRenderWindow);
model.openGLTexture.resetFormatAndType();
model.openGLTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars);
model.openGLTextureString = _toString;
}
}
var ppty = actor.getProperty();
var iComps = ppty.getIndependentComponents();
var numIComps = iComps ? numComp : 1;
var textureHeight = iComps ? 2 * numIComps : 1;
var cfunToString = computeFnToString(ppty, ppty.getRGBTransferFunction, numIComps);
if (model.colorTextureString !== cfunToString) {
var cWidth = 1024;
var cSize = cWidth * textureHeight * 3;
var cTable = new Uint8Array(cSize);
var cfun = ppty.getRGBTransferFunction();
if (cfun) {
var tmpTable = new Float32Array(cWidth * 3);
for (var c = 0; c < numIComps; c++) {
cfun = ppty.getRGBTransferFunction(c);
var cRange = cfun.getRange();
cfun.getTable(cRange[0], cRange[1], cWidth, tmpTable, 1);
if (iComps) {
for (var i = 0; i < cWidth * 3; i++) {
cTable[c * cWidth * 6 + i] = 255.0 * tmpTable[i];
cTable[c * cWidth * 6 + i + cWidth * 3] = 255.0 * tmpTable[i];
}
} else {
for (var _i = 0; _i < cWidth * 3; _i++) {
cTable[c * cWidth * 6 + _i] = 255.0 * tmpTable[_i];
}
}
}
model.colorTexture.releaseGraphicsResources(model._openGLRenderWindow);
model.colorTexture.resetFormatAndType();
model.colorTexture.create2DFromRaw(cWidth, textureHeight, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
} else {
for (var _i2 = 0; _i2 < cWidth * 3; ++_i2) {
cTable[_i2] = 255.0 * _i2 / ((cWidth - 1) * 3);
cTable[_i2 + 1] = 255.0 * _i2 / ((cWidth - 1) * 3);
cTable[_i2 + 2] = 255.0 * _i2 / ((cWidth - 1) * 3);
}
model.colorTexture.create2DFromRaw(cWidth, 1, 3, VtkDataTypes.UNSIGNED_CHAR, cTable);
}
model.colorTextureString = cfunToString;
} // Build piecewise function buffer. This buffer is used either
// for component weighting or opacity, depending on whether we're
// rendering components independently or not.
var pwfunToString = computeFnToString(ppty, ppty.getPiecewiseFunction, numIComps);
if (model.pwfTextureString !== pwfunToString) {
var pwfWidth = 1024;
var pwfSize = pwfWidth * textureHeight;
var pwfTable = new Uint8Array(pwfSize);
var pwfun = ppty.getPiecewiseFunction(); // support case where pwfun is added/removed
model.pwfTexture.releaseGraphicsResources(model._openGLRenderWindow);
model.pwfTexture.resetFormatAndType();
if (pwfun) {
var pwfFloatTable = new Float32Array(pwfSize);
var _tmpTable = new Float32Array(pwfWidth);
for (var _c = 0; _c < numIComps; ++_c) {
pwfun = ppty.getPiecewiseFunction(_c);
if (pwfun === null) {
// Piecewise constant max if no function supplied for this component
pwfFloatTable.fill(1.0);
} else {
var pwfRange = pwfun.getRange();
pwfun.getTable(pwfRange[0], pwfRange[1], pwfWidth, _tmpTable, 1); // adjust for sample distance etc
if (iComps) {
for (var _i3 = 0; _i3 < pwfWidth; _i3++) {
pwfFloatTable[_c * pwfWidth * 2 + _i3] = _tmpTable[_i3];
pwfFloatTable[_c * pwfWidth * 2 + _i3 + pwfWidth] = _tmpTable[_i3];
}
} else {
for (var _i4 = 0; _i4 < pwfWidth; _i4++) {
pwfFloatTable[_c * pwfWidth * 2 + _i4] = _tmpTable[_i4];
}
}
}
}
model.pwfTexture.create2DFromRaw(pwfWidth, textureHeight, 1, VtkDataTypes.FLOAT, pwfFloatTable);
} else {
// default is opaque
pwfTable.fill(255.0);
model.pwfTexture.create2DFromRaw(pwfWidth, 1, 1, VtkDataTypes.UNSIGNED_CHAR, pwfTable);
}
model.pwfTextureString = pwfunToString;
}
var vboString = "".concat(model.resliceGeom.getMTime(), "A").concat(model.renderable.getSlabThickness());
if (!model.tris.getCABO().getElementCount() || model.VBOBuildString !== vboString) {
var points = vtkDataArray.newInstance({
numberOfComponents: 3,
values: model.resliceGeom.getPoints().getData()
});
points.setName('points');
var cells = vtkDataArray.newInstance({
numberOfComponents: 1,
values: model.resliceGeom.getPolys().getData()
});
var options = {
points: points,
cellOffset: 0
};
if (model.renderable.getSlabThickness() > 0.0) {
var n = model.resliceGeom.getPointData().getNormals();
if (!n) {
vtkErrorMacro('Slab mode requested without normals');
} else {
options.normals = n;
}
}
model.tris.getCABO().createVBO(cells, 'polys', Representation.SURFACE, options);
}
model.VBOBuildString = vboString;
model.VBOBuildTime.modified();
};
publicAPI.updateShaders = function (cellBO, ren, actor) {
model.lastBoundBO = cellBO; // has something changed that would require us to recreate the shader?
if (publicAPI.getNeedToRebuildShaders(cellBO, ren, actor)) {
var shaders = {
Vertex: null,
Fragment: null,
Geometry: null
};
publicAPI.buildShaders(shaders, ren, actor); // compile and bind the program if needed
var newShader = model._openGLRenderWindow.getShaderCache().readyShaderProgramArray(shaders.Vertex, shaders.Fragment, shaders.Geometry); // if the shader changed reinitialize the VAO
if (newShader !== cellBO.getProgram()) {
cellBO.setProgram(newShader); // reset the VAO as the shader has changed
cellBO.getVAO().releaseGraphicsResources();
}
cellBO.getShaderSourceTime().modified();
} else {
model._openGLRenderWindow.getShaderCache().readyShaderProgram(cellBO.getProgram());
}
cellBO.getVAO().bind();
publicAPI.setMapperShaderParameters(cellBO, ren, actor);
publicAPI.setCameraShaderParameters(cellBO, ren, actor);
publicAPI.setPropertyShaderParameters(cellBO, ren, actor);
};
publicAPI.setMapperShaderParameters = function (cellBO, ren, actor) {
var program = cellBO.getProgram();
if (cellBO.getCABO().getElementCount() && (model.VBOBuildTime.getMTime() > cellBO.getAttributeUpdateTime().getMTime() || cellBO.getShaderSourceTime().getMTime() > cellBO.getAttributeUpdateTime().getMTime())) {
// Set the 3D texture
if (program.isUniformUsed('texture1')) {
program.setUniformi('texture1', model.openGLTexture.getTextureUnit());
} // Set the plane vertex attributes
if (program.isAttributeUsed('vertexWC')) {
if (!cellBO.getVAO().addAttributeArray(program, cellBO.getCABO(), 'vertexWC', cellBO.getCABO().getVertexOffset(), cellBO.getCABO().getStride(), model.context.FLOAT, 3, model.context.FALSE)) {
vtkErrorMacro('Error setting vertexWC in shader VAO.');
}
} // If we are doing slab mode, we need normals
if (program.isAttributeUsed('normalWC')) {
if (!cellBO.getVAO().addAttributeArray(program, cellBO.getCABO(), 'normalWC', cellBO.getCABO().getNormalOffset(), cellBO.getCABO().getStride(), model.context.FLOAT, 3, model.context.FALSE)) {
vtkErrorMacro('Error setting normalWC in shader VAO.');
}
}
if (program.isUniformUsed('slabThickness')) {
program.setUniformf('slabThickness', model.renderable.getSlabThickness());
}
if (program.isUniformUsed('spacing')) {
program.setUniform3fv('spacing', model.currentInput.getSpacing());
}
if (program.isUniformUsed('slabType')) {
program.setUniformi('slabType', model.renderable.getSlabType());
}
if (program.isUniformUsed('slabType')) {
program.setUniformi('slabType', model.renderable.getSlabType());
}
if (program.isUniformUsed('slabTrapezoid')) {
program.setUniformi('slabTrapezoid', model.renderable.getSlabTrapezoidIntegration());
}
var shiftScaleEnabled = cellBO.getCABO().getCoordShiftAndScaleEnabled();
var inverseShiftScaleMatrix = shiftScaleEnabled ? cellBO.getCABO().getInverseShiftAndScaleMatrix() : null; // Set the world->texture matrix
if (program.isUniformUsed('WCTCMatrix')) {
var image = model.currentInput;
mat4.identity(model.tmpMat4);
var bounds = image.getBounds();
var sc = [bounds[1] - bounds[0], bounds[3] - bounds[2], bounds[5] - bounds[4]];
var o = [bounds[0], bounds[2], bounds[4]];
var q = [0, 0, 0, 1];
mat4.fromRotationTranslationScale(model.tmpMat4, q, o, sc);
mat4.invert(model.tmpMat4, model.tmpMat4);
if (inverseShiftScaleMatrix) {
mat4.multiply(model.tmpMat4, model.tmpMat4, inverseShiftScaleMatrix);
}
program.setUniformMatrix('WCTCMatrix', model.tmpMat4);
}
cellBO.getAttributeUpdateTime().modified();
} // Depth request
if (model.haveSeenDepthRequest) {
cellBO.getProgram().setUniformi('depthRequest', model.renderDepth ? 1 : 0);
} // handle coincident
if (cellBO.getProgram().isUniformUsed('coffset')) {
var cp = publicAPI.getCoincidentParameters(ren, actor);
cellBO.getProgram().setUniformf('coffset', cp.offset); // cfactor isn't always used when coffset is.
if (cellBO.getProgram().isUniformUsed('cfactor')) {
cellBO.getProgram().setUniformf('cfactor', cp.factor);
}
}
};
publicAPI.setCameraShaderParameters = function (cellBO, ren, actor) {
// [WMVP]C == {world, model, view, projection} coordinates
// e.g. WCPC == world to projection coordinate transformation
var keyMats = model._openGLCamera.getKeyMatrices(ren);
var actMats = model._openGLImageSlice.getKeyMatrices();
var shiftScaleEnabled = cellBO.getCABO().getCoordShiftAndScaleEnabled();
var inverseShiftScaleMatrix = shiftScaleEnabled ? cellBO.getCABO().getInverseShiftAndScaleMatrix() : null;
var program = cellBO.getProgram();
if (program.isUniformUsed('MCPCMatrix')) {
mat4.identity(model.tmpMat4);
program.setUniformMatrix('MCPCMatrix', safeMatrixMultiply([keyMats.wcpc, actMats.mcwc, inverseShiftScaleMatrix], mat4, model.tmpMat4));
}
if (program.isUniformUsed('MCVCMatrix')) {
mat4.identity(model.tmpMat4);
program.setUniformMatrix('MCVCMatrix', safeMatrixMultiply([keyMats.wcvc, actMats.mcwc, inverseShiftScaleMatrix], mat4, model.tmpMat4));
}
};
publicAPI.setPropertyShaderParameters = function (cellBO, ren, actor) {
var program = cellBO.getProgram();
var ppty = actor.getProperty();
var opacity = ppty.getOpacity();
program.setUniformf('opacity', opacity); // Component mix
// Independent components: Mixed according to component weights
// Dependent components: Mixed using the following logic:
// - 2 comps => LA
// - 3 comps => RGB + opacity from pwf
// - 4 comps => RGBA
var numComp = model.openGLTexture.getComponents();
var iComps = ppty.getIndependentComponents();
if (iComps) {
for (var i = 0; i < numComp; ++i) {
program.setUniformf("mix".concat(i), ppty.getComponentWeight(i));
}
} // Color opacity map
var volInfo = model.openGLTexture.getVolumeInfo(); // three levels of shift scale combined into one
// for performance in the fragment shader
for (var _i5 = 0; _i5 < numComp; _i5++) {
var cw = ppty.getColorWindow();
var cl = ppty.getColorLevel();
var target = iComps ? _i5 : 0;
var cfun = ppty.getRGBTransferFunction(target);
if (cfun && ppty.getUseLookupTableScalarRange()) {
var cRange = cfun.getRange();
cw = cRange[1] - cRange[0];
cl = 0.5 * (cRange[1] + cRange[0]);
}
var scale = volInfo.scale[_i5] / cw;
var shift = (volInfo.offset[_i5] - cl) / cw + 0.5;
program.setUniformf("cshift".concat(_i5), shift);
program.setUniformf("cscale".concat(_i5), scale);
}
var texColorUnit = model.colorTexture.getTextureUnit();
program.setUniformi('colorTexture1', texColorUnit); // pwf shift/scale
for (var _i6 = 0; _i6 < numComp; _i6++) {
var pwfScale = 1.0;
var pwfShift = 0.0;
var _target = iComps ? _i6 : 0;
var pwfun = ppty.getPiecewiseFunction(_target);
if (pwfun) {
var pwfRange = pwfun.getRange();
var length = pwfRange[1] - pwfRange[0];
var mid = 0.5 * (pwfRange[0] + pwfRange[1]);
pwfScale = volInfo.scale[_i6] / length;
pwfShift = (volInfo.offset[_i6] - mid) / length + 0.5;
}
program.setUniformf("pwfshift".concat(_i6), pwfShift);
program.setUniformf("pwfscale".concat(_i6), pwfScale);
}
var texOpacityUnit = model.pwfTexture.getTextureUnit();
program.setUniformi('pwfTexture1', texOpacityUnit); // Background color
program.setUniform4fv('backgroundColor', model.renderable.getBackgroundColor());
};
publicAPI.getNeedToRebuildShaders = function (cellBO, ren, actor) {
// has something changed that would require us to recreate the shader?
// candidates are
// property modified (representation interpolation and lighting)
// input modified
// light complexity changed
// render pass shader replacement changed
var tNumComp = model.openGLTexture.getComponents();
var iComp = actor.getProperty().getIndependentComponents();
var slabTh = model.renderable.getSlabThickness();
var slabType = model.renderable.getSlabType();
var slabTrap = model.renderable.getSlabTrapezoidIntegration(); // has the render pass shader replacement changed? Two options
var needRebuild = false;
if (!model.currentRenderPass && model.lastRenderPassShaderReplacement || model.currentRenderPass && model.currentRenderPass.getShaderReplacement() !== model.lastRenderPassShaderReplacement) {
needRebuild = true;
}
if (needRebuild || model.lastHaveSeenDepthRequest !== model.haveSeenDepthRequest || cellBO.getProgram() === 0 || model.lastTextureComponents !== tNumComp || model.lastIndependentComponents !== iComp || model.lastSlabThickness !== slabTh || model.lastSlabType !== slabType || model.lastSlabTrapezoidIntegration !== slabTrap) {
model.lastHaveSeenDepthRequest = model.haveSeenDepthRequest;
model.lastTextureComponents = tNumComp;
model.lastIndependentComponents = iComp;
model.lastSlabThickness = slabTh;
model.lastSlabType = slabType;
model.lastSlabTrapezoidIntegration = slabTrap;
return true;
}
return false;
};
publicAPI.getShaderTemplate = function (shaders, ren, actor) {
shaders.Vertex = vtkImageResliceMapperVS;
shaders.Fragment = vtkImageResliceMapperFS;
shaders.Geometry = '';
};
publicAPI.replaceShaderValues = function (shaders, ren, actor) {
publicAPI.replaceShaderTCoord(shaders, ren, actor);
publicAPI.replaceShaderPositionVC(shaders, ren, actor);
if (model.haveSeenDepthRequest) {
var FSSource = shaders.Fragment;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Dec', 'uniform int depthRequest;').result;
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ZBuffer::Impl', ['if (depthRequest == 1) {', 'float iz = floor(gl_FragCoord.z*65535.0 + 0.1);', 'float rf = floor(iz/256.0)/255.0;', 'float gf = mod(iz,256.0)/255.0;', 'gl_FragData[0] = vec4(rf, gf, 0.0, 1.0); }']).result;
shaders.Fragment = FSSource;
}
publicAPI.replaceShaderCoincidentOffset(shaders, ren, actor);
};
publicAPI.replaceShaderTCoord = function (shaders, ren, actor) {
var VSSource = shaders.Vertex;
var GSSource = shaders.Geometry;
var FSSource = shaders.Fragment;
var tcoordVSDec = ['uniform mat4 WCTCMatrix;', 'out vec3 fragTexCoord;'];
var slabThickness = model.renderable.getSlabThickness();
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Dec', tcoordVSDec).result;
var tcoordVSImpl = ['fragTexCoord = (WCTCMatrix * vertexWC).xyz;'];
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::TCoord::Impl', tcoordVSImpl).result;
var tNumComp = model.openGLTexture.getComponents();
var iComps = actor.getProperty().getIndependentComponents();
var tcoordFSDec = ['in vec3 fragTexCoord;', 'uniform highp sampler3D texture1;', 'uniform mat4 WCTCMatrix;', // color shift and scale
'uniform float cshift0;', 'uniform float cscale0;', // pwf shift and scale
'uniform float pwfshift0;', 'uniform float pwfscale0;', // color and pwf textures
'uniform sampler2D colorTexture1;', 'uniform sampler2D pwfTexture1;', // opacity
'uniform float opacity;', // background color
'uniform vec4 backgroundColor;'];
if (iComps) {
for (var comp = 1; comp < tNumComp; comp++) {
tcoordFSDec = tcoordFSDec.concat([// color shift and scale
"uniform float cshift".concat(comp, ";"), "uniform float cscale".concat(comp, ";"), // weighting shift and scale
"uniform float pwfshift".concat(comp, ";"), "uniform float pwfscale".concat(comp, ";")]);
} // the heights defined below are the locations
// for the up to four components of the tfuns
// the tfuns have a height of 2XnumComps pixels so the
// values are computed to hit the middle of the two rows
// for that component
switch (tNumComp) {
case 1:
tcoordFSDec = tcoordFSDec.concat(['uniform float mix0;', '#define height0 0.5']);
break;
case 2:
tcoordFSDec = tcoordFSDec.concat(['uniform float mix0;', 'uniform float mix1;', '#define height0 0.25', '#define height1 0.75']);
break;
case 3:
tcoordFSDec = tcoordFSDec.concat(['uniform float mix0;', 'uniform float mix1;', 'uniform float mix2;', '#define height0 0.17', '#define height1 0.5', '#define height2 0.83']);
break;
case 4:
tcoordFSDec = tcoordFSDec.concat(['uniform float mix0;', 'uniform float mix1;', 'uniform float mix2;', 'uniform float mix3;', '#define height0 0.125', '#define height1 0.375', '#define height2 0.625', '#define height3 0.875']);
break;
default:
vtkErrorMacro('Unsupported number of independent coordinates.');
}
}
if (slabThickness > 0.0) {
tcoordFSDec = tcoordFSDec.concat(['uniform vec3 spacing;', 'uniform float slabThickness;', 'uniform int slabType;', 'uniform int slabTrapezoid;']);
tcoordFSDec = tcoordFSDec.concat(['vec4 compositeValue(vec4 currVal, vec4 valToComp, int trapezoid)', '{', ' vec4 retVal = vec4(1.0);', ' if (slabType == 0) // min', ' {', ' retVal = min(currVal, valToComp);', ' }', ' else if (slabType == 1) // max', ' {', ' retVal = max(currVal, valToComp);', ' }', ' else if (slabType == 3) // sum', ' {', ' retVal = currVal + (trapezoid > 0 ? 0.5 * valToComp : valToComp); ', ' }', ' else // mean', ' {', ' retVal = currVal + (trapezoid > 0 ? 0.5 * valToComp : valToComp); ', ' }', ' return retVal;', '}']);
}
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Dec', tcoordFSDec).result;
var tcoordFSImpl = ['if (any(greaterThan(fragTexCoord, vec3(1.0))) || any(lessThan(fragTexCoord, vec3(0.0))))', '{', ' // set the background color and exit', ' gl_FragData[0] = backgroundColor;', ' return;', '}', 'vec4 tvalue = texture(texture1, fragTexCoord);'];
if (slabThickness > 0.0) {
tcoordFSImpl = tcoordFSImpl.concat(['// Get the first and last samples', 'int numSlices = 1;', 'vec3 normalxspacing = normalWCVSOutput * spacing * 0.5;', 'float distTraveled = length(normalxspacing);', 'int trapezoid = 0;', 'while (distTraveled < slabThickness * 0.5)', '{', ' distTraveled += length(normalxspacing);', ' float fnumSlices = float(numSlices);', ' if (distTraveled > slabThickness * 0.5)', ' {', ' // Before stepping outside the slab, sample at the boundaries', ' normalxspacing = normalWCVSOutput * slabThickness * 0.5 / fnumSlices;', ' trapezoid = slabTrapezoid;', ' }', ' vec3 fragTCoordNeg = (WCTCMatrix * vec4(vertexWCVSOutput.xyz - fnumSlices * normalxspacing, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = texture(texture1, fragTCoordNeg);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', ' vec3 fragTCoordPos = (WCTCMatrix * vec4(vertexWCVSOutput.xyz + fnumSlices * normalxspacing, 1.0)).xyz;', ' if (!any(greaterThan(fragTCoordNeg, vec3(1.0))) && !any(lessThan(fragTCoordNeg, vec3(0.0))))', ' {', ' vec4 newVal = texture(texture1, fragTCoordPos);', ' tvalue = compositeValue(tvalue, newVal, trapezoid);', ' numSlices += 1;', ' }', '}', '// Finally, if slab type is *mean*, divide the sum by the numSlices', 'if (slabType == 2)', '{', ' tvalue = tvalue / float(numSlices);', '}']);
}
if (iComps) {
var rgba = ['r', 'g', 'b', 'a'];
for (var _comp = 0; _comp < tNumComp; ++_comp) {
tcoordFSImpl = tcoordFSImpl.concat(["vec3 tcolor".concat(_comp, " = mix").concat(_comp, " * texture2D(colorTexture1, vec2(tvalue.").concat(rgba[_comp], " * cscale").concat(_comp, " + cshift").concat(_comp, ", height").concat(_comp, ")).rgb;"), "float compWeight".concat(_comp, " = mix").concat(_comp, " * texture2D(pwfTexture1, vec2(tvalue.").concat(rgba[_comp], " * pwfscale").concat(_comp, " + pwfshift").concat(_comp, ", height").concat(_comp, ")).r;")]);
}
switch (tNumComp) {
case 1:
tcoordFSImpl = tcoordFSImpl.concat(['gl_FragData[0] = vec4(tcolor0.rgb, compWeight0 * opacity);']);
break;
case 2:
tcoordFSImpl = tcoordFSImpl.concat(['float weightSum = compWeight0 + compWeight1;', 'gl_FragData[0] = vec4(vec3((tcolor0.rgb * (compWeight0 / weightSum)) + (tcolor1.rgb * (compWeight1 / weightSum))), opacity);']);
break;
case 3:
tcoordFSImpl = tcoordFSImpl.concat(['float weightSum = compWeight0 + compWeight1 + compWeight2;', 'gl_FragData[0] = vec4(vec3((tcolor0.rgb * (compWeight0 / weightSum)) + (tcolor1.rgb * (compWeight1 / weightSum)) + (tcolor2.rgb * (compWeight2 / weightSum))), opacity);']);
break;
case 4:
tcoordFSImpl = tcoordFSImpl.concat(['float weightSum = compWeight0 + compWeight1 + compWeight2 + compWeight3;', 'gl_FragData[0] = vec4(vec3((tcolor0.rgb * (compWeight0 / weightSum)) + (tcolor1.rgb * (compWeight1 / weightSum)) + (tcolor2.rgb * (compWeight2 / weightSum)) + (tcolor3.rgb * (compWeight3 / weightSum))), opacity);']);
break;
default:
vtkErrorMacro('Unsupported number of independent coordinates.');
}
} else {
// dependent components
switch (tNumComp) {
case 1:
tcoordFSImpl = tcoordFSImpl.concat(['// Dependent components', 'float intensity = tvalue.r;', 'vec3 tcolor = texture2D(colorTexture1, vec2(intensity * cscale0 + cshift0, 0.5)).rgb;', 'float scalarOpacity = texture2D(pwfTexture1, vec2(intensity * pwfscale0 + pwfshift0, 0.5)).r;', 'gl_FragData[0] = vec4(tcolor, scalarOpacity * opacity);']);
break;
case 2:
tcoordFSImpl = tcoordFSImpl.concat(['float intensity = tvalue.r*cscale0 + cshift0;', 'gl_FragData[0] = vec4(texture2D(colorTexture1, vec2(intensity, 0.5)).rgb, pwfscale0*tvalue.g + pwfshift0);']);
break;
case 3:
tcoordFSImpl = tcoordFSImpl.concat(['vec4 tcolor = cscale0*tvalue + cshift0;', 'gl_FragData[0] = vec4(texture2D(colorTexture1, vec2(tcolor.r,0.5)).r,', ' texture2D(colorTexture1, vec2(tcolor.g,0.5)).r,', ' texture2D(colorTexture1, vec2(tcolor.b,0.5)).r, opacity);']);
break;
default:
tcoordFSImpl = tcoordFSImpl.concat(['vec4 tcolor = cscale0*tvalue + cshift0;', 'gl_FragData[0] = vec4(texture2D(colorTexture1, vec2(tcolor.r,0.5)).r,', ' texture2D(colorTexture1, vec2(tcolor.g,0.5)).r,', ' texture2D(colorTexture1, vec2(tcolor.b,0.5)).r, tcolor.a);']);
}
}
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', tcoordFSImpl).result;
shaders.Vertex = VSSource;
shaders.Fragment = FSSource;
shaders.Geometry = GSSource;
};
publicAPI.replaceShaderPositionVC = function (shaders, ren, actor) {
var VSSource = shaders.Vertex;
var GSSource = shaders.Geometry;
var FSSource = shaders.Fragment;
var slabThickness = model.renderable.getSlabThickness();
var posVCVSDec = ['attribute vec4 vertexWC;']; // Add a unique hash to the shader to ensure that the shader program is unique to this mapper.
posVCVSDec = posVCVSDec.concat(["//".concat(publicAPI.getMTime()).concat(model.resliceGeomUpdateString)]);
if (slabThickness > 0.0) {
posVCVSDec = posVCVSDec.concat(['attribute vec3 normalWC;', 'varying vec3 normalWCVSOutput;', 'varying vec4 vertexWCVSOutput;']);
}
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Dec', posVCVSDec).result;
var posVCVSImpl = ['gl_Position = MCPCMatrix * vertexWC;'];
if (slabThickness > 0.0) {
posVCVSImpl = posVCVSImpl.concat(['normalWCVSOutput = normalWC;', 'vertexWCVSOutput = vertexWC;']);
}
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Impl', posVCVSImpl).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::Camera::Dec', ['uniform mat4 MCPCMatrix;', 'uniform mat4 MCVCMatrix;']).result;
var posVCFSDec = [];
if (slabThickness > 0.0) {
posVCFSDec = posVCFSDec.concat(['varying vec3 normalWCVSOutput;', 'varying vec4 vertexWCVSOutput;']);
}
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::PositionVC::Dec', posVCFSDec).result;
shaders.Vertex = VSSource;
shaders.Geometry = GSSource;
shaders.Fragment = FSSource;
};
function isVectorAxisAligned(n) {
vtkMath.normalize(n);
var tmpN = [0, 0, 0];
for (var i = 0; i < 3; ++i) {
vec3.zero(tmpN);
tmpN[i] = 1.0;
var dotP = vtkMath.dot(n, tmpN);
if (dotP < -0.999 || dotP > 0.999) {
return [true, i];
}
}
return [false, 2];
}
publicAPI.updateResliceGeometry = function () {
var resGeomString = '';
var image = model.currentInput;
var imageBounds = image === null || image === void 0 ? void 0 : image.getBounds(); // Orthogonal slicing by default
var orthoSlicing = true;
var orthoAxis = 2;
if (model.renderable.getSlicePolyData()) {
resGeomString = resGeomString.concat("PolyData".concat(model.renderable.getSlicePolyData().getMTime()));
} else if (model.renderable.getSlicePlane()) {
resGeomString = resGeomString.concat("Plane".concat(model.renderable.getSlicePlane().getMTime()));
if (image) {
resGeomString = resGeomString.concat("Image".concat(image.getMTime()));
} // Check to see if we can bypass oblique slicing related bounds computation
var _isVectorAxisAligned = isVectorAxisAligned(model.renderable.getSlicePlane().getNormal());
var _isVectorAxisAligned2 = _slicedToArray(_isVectorAxisAligned, 2);
orthoSlicing = _isVectorAxisAligned2[0];
orthoAxis = _isVectorAxisAligned2[1];
} else {
var _model$renderable$get;
// Create a default slice plane here
var plane = vtkPlane.newInstance();
plane.setNormal(0, 0, 1);
var bds = [0, 1, 0, 1, 0, 1];
if (image) {
bds = imageBounds;
}
plane.setOrigin(bds[0], bds[2], 0.5 * (bds[5] + bds[4]));
model.renderable.setSlicePlane(plane);
resGeomString = resGeomString.concat("Plane".concat((_model$renderable$get = model.renderable.getSlicePlane()) === null || _model$renderable$get === void 0 ? void 0 : _model$renderable$get.getMTime()));
if (image) {
resGeomString = resGeomString.concat("Image".concat(image.getMTime()));
}
}
if (!model.resliceGeom || model.resliceGeomUpdateString !== resGeomString) {
if (model.renderable.getSlicePolyData()) {
model.resliceGeom = model.renderable.getSlicePolyData();
} else if (model.renderable.getSlicePlane()) {
var bounds = image ? imageBounds : [0, 1, 0, 1, 0, 1];
if (!orthoSlicing) {
var cube = vtkCubeSource.newInstance();
cube.setCenter(0.5 * (bounds[0] + bounds[1]), 0.5 * (bounds[2] + bounds[3]), 0.5 * (bounds[4] + bounds[5]));
cube.setXLength(bounds[1] - bounds[0]);
cube.setYLength(bounds[3] - bounds[2]);
cube.setZLength(bounds[5] - bounds[4]);
var cutter = vtkCutter.newInstance();
cutter.setInputConnection(cube.getOutputPort());
cutter.setCutFunction(model.renderable.getSlicePlane());
var pds = vtkClosedPolyLineToSurfaceFilter.newInstance();
pds.setInputConnection(cutter.getOutputPort());
pds.update();
model.resliceGeom = pds.getOutputData(); // The above method does not generate point normals
// Set it manually here.
var n = model.renderable.getSlicePlane().getNormal();
var npts = model.resliceGeom.getNumberOfPoints();
vtkMath.normalize(n);
var normalsData = new Float32Array(npts * 3);
for (var i = 0; i < npts; ++i) {
normalsData[3 * i] = n[0];
normalsData[3 * i + 1] = n[1];
normalsData[3 * i + 2] = n[2];
}
var normals = vtkDataArray.newInstance({
numberOfComponents: 3,
values: normalsData,
name: 'Normals'
});
model.resliceGeom.getPointData().setNormals(normals);
} else {
var ptsArray = new Float32Array(12);
var o = model.renderable.getSlicePlane().getOrigin();
var otherAxes = [(orthoAxis + 1) % 3, (orthoAxis + 2) % 3].sort();
var ptIdx = 0;
for (var _i7 = 0; _i7 < 2; ++_i7) {
for (var j = 0; j < 2; ++j) {
ptsArray[ptIdx + orthoAxis] = o[orthoAxis];
ptsArray[ptIdx + otherAxes[0]] = bounds[2 * otherAxes[0] + j];
ptsArray[ptIdx + otherAxes[1]] = bounds[2 * otherAxes[1] + _i7];
ptIdx += 3;
}
}
var cellArray = new Uint16Array(8);
cellArray[0] = 3;
cellArray[1] = 0;
cellArray[2] = 1;
cellArray[3] = 3;
cellArray[4] = 3;
cellArray[5] = 0;
cellArray[6] = 3;
cellArray[7] = 2;
var _n = model.renderable.getSlicePlane().getNormal();
vtkMath.normalize(_n);
var _normalsData = new Float32Array(12);
for (var _i8 = 0; _i8 < 4; ++_i8) {
_normalsData[3 * _i8] = _n[0];
_normalsData[3 * _i8 + 1] = _n[1];
_normalsData[3 * _i8 + 2] = _n[2];
}
if (!model.resliceGeom) {
model.resliceGeom = vtkPolyData.newInstance();
}
model.resliceGeom.getPoints().setData(ptsArray, 3);
model.resliceGeom.getPolys().setData(cellArray, 1);
var _normals = vtkDataArray.newInstance({
numberOfComponents: 3,
values: _normalsData,
name: 'Normals'
});
model.resliceGeom.getPointData().setNormals(_normals);
model.resliceGeom.modified();
}
} else {
vtkErrorMacro('Something went wrong.', 'A default slice plane should have been created in the beginning of', 'updateResliceGeometry.');
}
model.resliceGeomUpdateString = resGeomString;
}
};
publicAPI.setOpenGLTexture = function (oglTex) {
if (oglTex) {
model.openGLTexture = oglTex;
model._externalOpenGLTexture = true;
}
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
var DEFAULT_VALUES = {
VBOBuildTime: {},
VBOBuildString: null,
haveSeenDepthRequest: false,
lastHaveSeenDepthRequest: false,
lastIndependentComponents: false,
lastTextureComponents: 0,
lastSlabThickness: 0,
lastSlabTrapezoidIntegration: 0,
lastSlabType: -1,
openGLTexture: null,
openGLTextureString: null,
colorTextureString: null,
pwfTextureString: null,
resliceGeom: null,
resliceGeomUpdateString: null,
tris: null,
colorTexture: null,
pwfTexture: null,
_externalOpenGLTexture: false
}; // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance
vtkViewNode.extend(publicAPI, model, initialValues);
vtkReplacementShaderMapper.implementReplaceShaderCoincidentOffset(publicAPI, model, initialValues);
vtkReplacementShaderMapper.implementBuildShadersWithReplacements(publicAPI, model, initialValues);
model.tris = vtkHelper.newInstance();
model.openGLTexture = vtkOpenGLTexture.newInstance();
model.colorTexture = vtkOpenGLTexture.newInstance();
model.pwfTexture = vtkOpenGLTexture.newInstance();
model.VBOBuildTime = {};
obj(model.VBOBuildTime); // model.modelToView = mat4.identity(new Float64Array(16));
model.tmpMat4 = mat4.identity(new Float64Array(16));
get(publicAPI, model, ['openGLTexture']); // Object methods
vtkOpenGLImageResliceMapper(publicAPI, model);
} // ----------------------------------------------------------------------------
var newInstance = newInstance$1(extend, 'vtkOpenGLImageResliceMapper'); // ----------------------------------------------------------------------------
var vtkImageResliceMapper = {
newInstance: newInstance,
extend: extend
}; // Register ourself to OpenGL backend if imported
registerOverride('vtkImageResliceMapper', newInstance);
export { vtkImageResliceMapper as default, extend, newInstance };