UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

237 lines (190 loc) 9.34 kB
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 };