@acransac/vtk.js
Version:
Visualization Toolkit for the Web
228 lines (182 loc) • 6.64 kB
JavaScript
import macro from 'vtk.js/Sources/macro';
import vtkViewNode from 'vtk.js/Sources/Rendering/SceneGraph/ViewNode';
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
const { vtkDebugMacro } = macro;
// ----------------------------------------------------------------------------
// vtkOpenGLRenderer methods
// ----------------------------------------------------------------------------
/* eslint-disable no-bitwise */
function vtkOpenGLRenderer(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkOpenGLRenderer');
// Builds myself.
publicAPI.buildPass = (prepass) => {
if (prepass) {
if (!model.renderable) {
return;
}
// make sure we have a camera
if (!model.renderable.isActiveCameraCreated()) {
model.renderable.resetCamera();
}
publicAPI.updateLights();
publicAPI.prepareNodes();
publicAPI.addMissingNode(model.renderable.getActiveCamera());
publicAPI.addMissingNodes(model.renderable.getViewPropsWithNestedProps());
publicAPI.removeUnusedNodes();
}
};
publicAPI.updateLights = () => {
let count = 0;
const lights = model.renderable.getLightsByReference();
for (let index = 0; index < lights.length; ++index) {
if (lights[index].getSwitch() > 0.0) {
count++;
}
}
if (!count) {
vtkDebugMacro('No lights are on, creating one.');
model.renderable.createLight();
}
return count;
};
publicAPI.opaqueZBufferPass = (prepass) => {
if (prepass) {
let clearMask = 0;
const gl = model.context;
if (!model.renderable.getTransparent()) {
model.context.clearColor(1.0, 0.0, 0.0, 1.0);
clearMask |= gl.COLOR_BUFFER_BIT;
}
if (!model.renderable.getPreserveDepthBuffer()) {
gl.clearDepth(1.0);
clearMask |= gl.DEPTH_BUFFER_BIT;
gl.depthMask(true);
}
const ts = publicAPI.getTiledSizeAndOrigin();
gl.enable(gl.SCISSOR_TEST);
gl.scissor(ts.lowerLeftU, ts.lowerLeftV, ts.usize, ts.vsize);
gl.viewport(ts.lowerLeftU, ts.lowerLeftV, ts.usize, ts.vsize);
gl.colorMask(true, true, true, true);
gl.clear(clearMask);
gl.enable(gl.DEPTH_TEST);
}
};
// Renders myself
publicAPI.cameraPass = (prepass) => {
if (prepass) {
publicAPI.clear();
}
};
publicAPI.getAspectRatio = () => {
const size = model.parent.getSizeByReference();
const viewport = model.renderable.getViewportByReference();
return (
(size[0] * (viewport[2] - viewport[0])) /
((viewport[3] - viewport[1]) * size[1])
);
};
publicAPI.getTiledSizeAndOrigin = () => {
const vport = model.renderable.getViewportByReference();
// if there is no window assume 0 1
const tileViewPort = [0.0, 0.0, 1.0, 1.0];
// find the lower left corner of the viewport, taking into account the
// lower left boundary of this tile
const vpu = vtkMath.clampValue(vport[0] - tileViewPort[0], 0.0, 1.0);
const vpv = vtkMath.clampValue(vport[1] - tileViewPort[1], 0.0, 1.0);
// store the result as a pixel value
const ndvp = model.parent.normalizedDisplayToDisplay(vpu, vpv);
const lowerLeftU = Math.round(ndvp[0]);
const lowerLeftV = Math.round(ndvp[1]);
// find the upper right corner of the viewport, taking into account the
// lower left boundary of this tile
let vpu2 = vtkMath.clampValue(vport[2] - tileViewPort[0], 0.0, 1.0);
let vpv2 = vtkMath.clampValue(vport[3] - tileViewPort[1], 0.0, 1.0);
// also watch for the upper right boundary of the tile
if (vpu2 > tileViewPort[2] - tileViewPort[0]) {
vpu2 = tileViewPort[2] - tileViewPort[0];
}
if (vpv2 > tileViewPort[3] - tileViewPort[1]) {
vpv2 = tileViewPort[3] - tileViewPort[1];
}
const ndvp2 = model.parent.normalizedDisplayToDisplay(vpu2, vpv2);
// now compute the size of the intersection of the viewport with the
// current tile
let usize = Math.round(ndvp2[0]) - lowerLeftU;
let vsize = Math.round(ndvp2[1]) - lowerLeftV;
if (usize < 0) {
usize = 0;
}
if (vsize < 0) {
vsize = 0;
}
return { usize, vsize, lowerLeftU, lowerLeftV };
};
publicAPI.clear = () => {
let clearMask = 0;
const gl = model.context;
if (!model.renderable.getTransparent()) {
const background = model.renderable.getBackgroundByReference();
// renderable ensures that background has 4 entries.
model.context.clearColor(
background[0],
background[1],
background[2],
background[3]
);
clearMask |= gl.COLOR_BUFFER_BIT;
}
if (!model.renderable.getPreserveDepthBuffer()) {
gl.clearDepth(1.0);
clearMask |= gl.DEPTH_BUFFER_BIT;
gl.depthMask(true);
}
gl.colorMask(true, true, true, true);
const ts = publicAPI.getTiledSizeAndOrigin();
gl.enable(gl.SCISSOR_TEST);
gl.scissor(ts.lowerLeftU, ts.lowerLeftV, ts.usize, ts.vsize);
gl.viewport(ts.lowerLeftU, ts.lowerLeftV, ts.usize, ts.vsize);
gl.clear(clearMask);
gl.enable(gl.DEPTH_TEST);
/* eslint-enable no-bitwise */
};
publicAPI.releaseGraphicsResources = () => {
if (model.selector !== null) {
model.selector.releaseGraphicsResources();
}
};
publicAPI.setOpenGLRenderWindow = (rw) => {
if (model.openGLRenderWindow === rw) {
return;
}
publicAPI.releaseGraphicsResources();
model.openGLRenderWindow = rw;
model.context = null;
if (rw) {
model.context = model.openGLRenderWindow.getContext();
}
};
}
// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
const DEFAULT_VALUES = {
context: null,
openGLRenderWindow: null,
selector: null,
};
// ----------------------------------------------------------------------------
export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, DEFAULT_VALUES, initialValues);
// Inheritance
vtkViewNode.extend(publicAPI, model, initialValues);
// Build VTK API
macro.get(publicAPI, model, ['shaderCache']);
macro.setGet(publicAPI, model, ['selector']);
// Object methods
vtkOpenGLRenderer(publicAPI, model);
}
// ----------------------------------------------------------------------------
export const newInstance = macro.newInstance(extend, 'vtkOpenGLRenderer');
// ----------------------------------------------------------------------------
export default { newInstance, extend };