@kitware/vtk.js
Version:
Visualization Toolkit for the Web
237 lines (190 loc) • 9.34 kB
JavaScript
import macro from '../../macros.js';
import vtkCellArrayBufferObject from './CellArrayBufferObject.js';
import vtkShaderProgram from './ShaderProgram.js';
import vtkVertexArrayObject from './VertexArrayObject.js';
import { Representation } from '../Core/Property/Constants.js';
var primTypes = {
Start: 0,
Points: 0,
Lines: 1,
Tris: 2,
TriStrips: 3,
TrisEdges: 4,
TriStripsEdges: 5,
End: 6
}; // ----------------------------------------------------------------------------
// vtkOpenGLHelper methods
// ----------------------------------------------------------------------------
function vtkOpenGLHelper(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkOpenGLHelper');
publicAPI.setOpenGLRenderWindow = function (win) {
model.context = win.getContext();
model.program.setContext(model.context);
model.VAO.setOpenGLRenderWindow(win);
model.CABO.setOpenGLRenderWindow(win);
};
publicAPI.releaseGraphicsResources = function (oglwin) {
model.VAO.releaseGraphicsResources();
model.CABO.releaseGraphicsResources();
model.CABO.setElementCount(0);
};
publicAPI.drawArrays = function (ren, actor, rep, oglMapper) {
// Are there any entries
if (model.CABO.getElementCount()) {
// are we drawing edges
var mode = publicAPI.getOpenGLMode(rep);
var wideLines = publicAPI.haveWideLines(ren, actor);
var gl = model.context;
var depthMask = gl.getParameter(gl.DEPTH_WRITEMASK);
if (model.pointPicking) {
gl.depthMask(false);
}
var drawingLines = mode === gl.LINES;
if (drawingLines && wideLines) {
publicAPI.updateShaders(ren, actor, oglMapper);
gl.drawArraysInstanced(mode, 0, model.CABO.getElementCount(), 2 * Math.ceil(actor.getProperty().getLineWidth()));
} else {
gl.lineWidth(actor.getProperty().getLineWidth());
publicAPI.updateShaders(ren, actor, oglMapper);
gl.drawArrays(mode, 0, model.CABO.getElementCount()); // reset the line width
gl.lineWidth(1);
}
var stride = (mode === gl.POINTS ? 1 : 0) || (mode === gl.LINES ? 2 : 3);
if (model.pointPicking) {
gl.depthMask(depthMask);
}
return model.CABO.getElementCount() / stride;
}
return 0;
};
publicAPI.getOpenGLMode = function (rep) {
if (model.pointPicking) {
return model.context.POINTS;
}
var type = model.primitiveType;
if (rep === Representation.POINTS || type === primTypes.Points) {
return model.context.POINTS;
}
if (rep === Representation.WIREFRAME || type === primTypes.Lines || type === primTypes.TrisEdges || type === primTypes.TriStripsEdges) {
return model.context.LINES;
}
return model.context.TRIANGLES;
};
publicAPI.haveWideLines = function (ren, actor) {
if (actor.getProperty().getLineWidth() > 1.0) {
// we have wide lines, but the OpenGL implementation may
// actually support them, check the range to see if we
// really need have to implement our own wide lines
if (model.CABO.getOpenGLRenderWindow()) {
if (model.CABO.getOpenGLRenderWindow().getHardwareMaximumLineWidth() >= actor.getProperty().getLineWidth()) {
return false;
}
}
return true;
}
return false;
};
publicAPI.getNeedToRebuildShaders = function (ren, actor, oglMapper) {
// has something changed that would require us to recreate the shader?
// candidates are
// property modified (representation interpolation and lighting)
// input modified
// mapper modified (lighting complexity)
if (oglMapper.getNeedToRebuildShaders(publicAPI, ren, actor) || publicAPI.getProgram() === 0 || publicAPI.getShaderSourceTime().getMTime() < oglMapper.getMTime() || publicAPI.getShaderSourceTime().getMTime() < actor.getMTime()) {
return true;
}
return false;
};
publicAPI.updateShaders = function (ren, actor, oglMapper) {
// has something changed that would require us to recreate the shader?
if (publicAPI.getNeedToRebuildShaders(ren, actor, oglMapper)) {
var shaders = {
Vertex: null,
Fragment: null,
Geometry: null
};
oglMapper.buildShaders(shaders, ren, actor); // compile and bind the program if needed
var newShader = model.CABO.getOpenGLRenderWindow().getShaderCache().readyShaderProgramArray(shaders.Vertex, shaders.Fragment, shaders.Geometry); // if the shader changed reinitialize the VAO
if (newShader !== publicAPI.getProgram()) {
publicAPI.setProgram(newShader); // reset the VAO as the shader has changed
publicAPI.getVAO().releaseGraphicsResources();
}
publicAPI.getShaderSourceTime().modified();
} else {
model.CABO.getOpenGLRenderWindow().getShaderCache().readyShaderProgram(publicAPI.getProgram());
}
publicAPI.getVAO().bind();
oglMapper.setMapperShaderParameters(publicAPI, ren, actor);
oglMapper.setPropertyShaderParameters(publicAPI, ren, actor);
oglMapper.setCameraShaderParameters(publicAPI, ren, actor);
oglMapper.setLightingShaderParameters(publicAPI, ren, actor);
oglMapper.invokeShaderCallbacks(publicAPI, ren, actor);
};
publicAPI.setMapperShaderParameters = function (ren, actor, size) {
if (publicAPI.haveWideLines(ren, actor)) {
publicAPI.getProgram().setUniform2f('viewportSize', size.usize, size.vsize);
var lineWidth = parseFloat(actor.getProperty().getLineWidth());
var halfLineWidth = lineWidth / 2.0;
publicAPI.getProgram().setUniformf('lineWidthStepSize', lineWidth / Math.ceil(lineWidth));
publicAPI.getProgram().setUniformf('halfLineWidth', halfLineWidth);
}
if (model.primitiveType === primTypes.Points || actor.getProperty().getRepresentation() === Representation.POINTS) {
publicAPI.getProgram().setUniformf('pointSize', actor.getProperty().getPointSize());
} else if (model.pointPicking) {
publicAPI.getProgram().setUniformf('pointSize', publicAPI.getPointPickingPrimitiveSize());
}
};
publicAPI.replaceShaderPositionVC = function (shaders, ren, actor) {
var VSSource = shaders.Vertex; // Always set point size in case we need picking
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Dec', ['//VTK::PositionVC::Dec', 'uniform float pointSize;']).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Impl', ['//VTK::PositionVC::Impl', ' gl_PointSize = pointSize;'], false).result; // for lines, make sure we add the width code
if (publicAPI.getOpenGLMode(actor.getProperty().getRepresentation()) === model.context.LINES && publicAPI.haveWideLines(ren, actor)) {
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Dec', ['//VTK::PositionVC::Dec', 'uniform vec2 viewportSize;', 'uniform float lineWidthStepSize;', 'uniform float halfLineWidth;']).result;
VSSource = vtkShaderProgram.substitute(VSSource, '//VTK::PositionVC::Impl', ['//VTK::PositionVC::Impl', ' if (halfLineWidth > 0.0)', ' {', ' float offset = float(gl_InstanceID / 2) * lineWidthStepSize - halfLineWidth;', ' vec4 tmpPos = gl_Position;', ' vec3 tmpPos2 = tmpPos.xyz / tmpPos.w;', ' tmpPos2.x = tmpPos2.x + 2.0 * mod(float(gl_InstanceID), 2.0) * offset / viewportSize[0];', ' tmpPos2.y = tmpPos2.y + 2.0 * mod(float(gl_InstanceID + 1), 2.0) * offset / viewportSize[1];', ' gl_Position = vec4(tmpPos2.xyz * tmpPos.w, tmpPos.w);', ' }']).result;
}
shaders.Vertex = VSSource;
};
publicAPI.getPointPickingPrimitiveSize = function () {
if (model.primitiveType === primTypes.Points) {
return 2;
}
if (model.primitiveType === primTypes.Lines) {
return 4;
}
return 6;
};
} // ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------
var DEFAULT_VALUES = {
context: null,
program: null,
shaderSourceTime: null,
VAO: null,
attributeUpdateTime: null,
CABO: null,
primitiveType: 0,
pointPicking: false
}; // ----------------------------------------------------------------------------
function extend(publicAPI, model) {
var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API
macro.obj(publicAPI, model);
model.shaderSourceTime = {};
macro.obj(model.shaderSourceTime);
model.attributeUpdateTime = {};
macro.obj(model.attributeUpdateTime);
macro.setGet(publicAPI, model, ['program', 'shaderSourceTime', 'VAO', 'attributeUpdateTime', 'CABO', 'primitiveType', 'pointPicking']);
model.program = vtkShaderProgram.newInstance();
model.VAO = vtkVertexArrayObject.newInstance();
model.CABO = vtkCellArrayBufferObject.newInstance(); // Object methods
vtkOpenGLHelper(publicAPI, model);
} // ----------------------------------------------------------------------------
var newInstance = macro.newInstance(extend); // ----------------------------------------------------------------------------
var vtkHelper = {
newInstance: newInstance,
extend: extend,
primTypes: primTypes
};
export { vtkHelper as default, extend, newInstance, primTypes };