UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

357 lines (279 loc) 11.3 kB
import macro from '../../macros.js'; import { ObjectType } from './BufferObject/Constants.js'; // vtkOpenGLVertexArrayObject methods // ---------------------------------------------------------------------------- function vtkOpenGLVertexArrayObject(publicAPI, model) { // Set our className model.classHierarchy.push('vtkOpenGLVertexArrayObject'); // Public API methods publicAPI.exposedMethod = function () {// This is a publicly exposed method of this object }; publicAPI.initialize = function () { model.instancingExtension = null; if (!model._openGLRenderWindow.getWebgl2()) { model.instancingExtension = model.context.getExtension('ANGLE_instanced_arrays'); } if (!model.forceEmulation && model._openGLRenderWindow && model._openGLRenderWindow.getWebgl2()) { model.extension = null; model.supported = true; model.handleVAO = model.context.createVertexArray(); } else { model.extension = model.context.getExtension('OES_vertex_array_object'); // Start setting up VAO if (!model.forceEmulation && model.extension) { model.supported = true; model.handleVAO = model.extension.createVertexArrayOES(); } else { model.supported = false; } } }; publicAPI.isReady = function () { return (// We either probed and allocated a VAO, or are falling back as the current // hardware does not support VAOs. model.handleVAO !== 0 || model.supported === false ); }; publicAPI.bind = function () { // Either simply bind the VAO, or emulate behavior by binding all attributes. if (!publicAPI.isReady()) { publicAPI.initialize(); } if (publicAPI.isReady() && model.supported) { if (model.extension) { model.extension.bindVertexArrayOES(model.handleVAO); } else { model.context.bindVertexArray(model.handleVAO); } } else if (publicAPI.isReady()) { var gl = model.context; for (var ibuff = 0; ibuff < model.buffers.length; ++ibuff) { var buff = model.buffers[ibuff]; model.context.bindBuffer(gl.ARRAY_BUFFER, buff.buffer); for (var iatt = 0; iatt < buff.attributes.length; ++iatt) { var attrIt = buff.attributes[iatt]; var matrixCount = attrIt.isMatrix ? attrIt.size : 1; for (var i = 0; i < matrixCount; ++i) { gl.enableVertexAttribArray(attrIt.index + i); gl.vertexAttribPointer(attrIt.index + i, attrIt.size, attrIt.type, attrIt.normalize, attrIt.stride, attrIt.offset + attrIt.stride * i / attrIt.size); if (attrIt.divisor > 0) { if (model.instancingExtension) { model.instancingExtension.vertexAttribDivisorANGLE(attrIt.index + i, 1); } else { gl.vertexAttribDivisor(attrIt.index + i, 1); } } } } } } }; publicAPI.release = function () { // Either simply release the VAO, or emulate behavior by releasing all attributes. if (publicAPI.isReady() && model.supported) { if (model.extension) { model.extension.bindVertexArrayOES(null); } else { model.context.bindVertexArray(null); } } else if (publicAPI.isReady()) { var gl = model.context; for (var ibuff = 0; ibuff < model.buffers.length; ++ibuff) { var buff = model.buffers[ibuff]; model.context.bindBuffer(gl.ARRAY_BUFFER, buff.buffer); for (var iatt = 0; iatt < buff.attributes.length; ++iatt) { var attrIt = buff.attributes[iatt]; var matrixCount = attrIt.isMatrix ? attrIt.size : 1; for (var i = 0; i < matrixCount; ++i) { gl.enableVertexAttribArray(attrIt.index + i); gl.vertexAttribPointer(attrIt.index + i, attrIt.size, attrIt.type, attrIt.normalize, attrIt.stride, attrIt.offset + attrIt.stride * i / attrIt.size); if (attrIt.divisor > 0) { if (model.instancingExtension) { model.instancingExtension.vertexAttribDivisorANGLE(attrIt.index + i, 0); } else { gl.vertexAttribDivisor(attrIt.index + i, 0); } } gl.disableVertexAttribArray(attrIt.index + i); } } } } }; publicAPI.shaderProgramChanged = function () { publicAPI.release(); if (model.handleVAO) { if (model.extension) { model.extension.deleteVertexArrayOES(model.handleVAO); } else { model.context.deleteVertexArray(model.handleVAO); } } model.handleVAO = 0; model.handleProgram = 0; }; publicAPI.releaseGraphicsResources = function () { publicAPI.shaderProgramChanged(); if (model.handleVAO) { if (model.extension) { model.extension.deleteVertexArrayOES(model.handleVAO); } else { model.context.deleteVertexArray(model.handleVAO); } } model.handleVAO = 0; model.supported = true; model.handleProgram = 0; }; publicAPI.addAttributeArray = function (program, buffer, name, offset, stride, elementType, elementTupleSize, normalize) { return publicAPI.addAttributeArrayWithDivisor(program, buffer, name, offset, stride, elementType, elementTupleSize, normalize, 0, false); }; publicAPI.addAttributeArrayWithDivisor = function (program, buffer, name, offset, stride, elementType, elementTupleSize, normalize, divisor, isMatrix) { if (!program) { return false; } // Check the program is bound, and the buffer is valid. if (!program.isBound() || buffer.getHandle() === 0 || buffer.getType() !== ObjectType.ARRAY_BUFFER) { return false; } // Perform initialization if necessary, ensure program matches VAOs. if (model.handleProgram === 0) { model.handleProgram = program.getHandle(); } if (!publicAPI.isReady()) { publicAPI.initialize(); } if (!publicAPI.isReady() || model.handleProgram !== program.getHandle()) { return false; } var gl = model.context; var attribs = {}; attribs.name = name; attribs.index = gl.getAttribLocation(model.handleProgram, name); attribs.offset = offset; attribs.stride = stride; attribs.type = elementType; attribs.size = elementTupleSize; attribs.normalize = normalize; attribs.isMatrix = isMatrix; attribs.divisor = divisor; if (attribs.Index === -1) { return false; } // Always make the call as even the first use wants the attrib pointer setting // up when we are emulating. buffer.bind(); gl.enableVertexAttribArray(attribs.index); gl.vertexAttribPointer(attribs.index, attribs.size, attribs.type, attribs.normalize, attribs.stride, attribs.offset); if (divisor > 0) { if (model.instancingExtension) { model.instancingExtension.vertexAttribDivisorANGLE(attribs.index, 1); } else { gl.vertexAttribDivisor(attribs.index, 1); } } attribs.buffer = buffer.getHandle(); // If vertex array objects are not supported then build up our list. if (!model.supported) { // find the buffer var buffFound = false; for (var ibuff = 0; ibuff < model.buffers.length; ++ibuff) { var buff = model.buffers[ibuff]; if (buff.buffer === attribs.buffer) { buffFound = true; var found = false; for (var iatt = 0; iatt < buff.attributes.length; ++iatt) { var attrIt = buff.attributes[iatt]; if (attrIt.name === name) { found = true; buff.attributes[iatt] = attribs; } } if (!found) { buff.attributes.push(attribs); } } } if (!buffFound) { model.buffers.push({ buffer: attribs.buffer, attributes: [attribs] }); } } return true; }; publicAPI.addAttributeMatrixWithDivisor = function (program, buffer, name, offset, stride, elementType, elementTupleSize, normalize, divisor) { // bind the first row of values var result = publicAPI.addAttributeArrayWithDivisor(program, buffer, name, offset, stride, elementType, elementTupleSize, normalize, divisor, true); if (!result) { return result; } var gl = model.context; var index = gl.getAttribLocation(model.handleProgram, name); for (var i = 1; i < elementTupleSize; i++) { gl.enableVertexAttribArray(index + i); gl.vertexAttribPointer(index + i, elementTupleSize, elementType, normalize, stride, offset + stride * i / elementTupleSize); if (divisor > 0) { if (model.instancingExtension) { model.instancingExtension.vertexAttribDivisorANGLE(index + i, 1); } else { gl.vertexAttribDivisor(index + i, 1); } } } return true; }; publicAPI.removeAttributeArray = function (name) { if (!publicAPI.isReady() || model.handleProgram === 0) { return false; } // If we don't have real VAOs find the entry and remove it too. if (!model.supported) { for (var ibuff = 0; ibuff < model.buffers.length; ++ibuff) { var buff = model.buffers[ibuff]; for (var iatt = 0; iatt < buff.attributes.length; ++iatt) { var attrIt = buff.attributes[iatt]; if (attrIt.name === name) { buff.attributes.splice(iatt, 1); if (!buff.attributes.length) { model.buffers.splice(ibuff, 1); } return true; } } } } return true; }; publicAPI.setOpenGLRenderWindow = function (rw) { if (model._openGLRenderWindow === rw) { return; } publicAPI.releaseGraphicsResources(); model._openGLRenderWindow = rw; model.context = null; if (rw) { model.context = model._openGLRenderWindow.getContext(); } }; } // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- var DEFAULT_VALUES = { forceEmulation: false, handleVAO: 0, handleProgram: 0, supported: true, buffers: null, context: null // _openGLRenderWindow: null, }; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); // Internal objects initialization model.buffers = []; // Object methods macro.obj(publicAPI, model); // Create get-only macros macro.get(publicAPI, model, ['supported']); // Create get-set macros macro.setGet(publicAPI, model, ['forceEmulation']); // For more macro methods, see "Sources/macros.js" // Object specific methods vtkOpenGLVertexArrayObject(publicAPI, model); } // ---------------------------------------------------------------------------- var newInstance = macro.newInstance(extend, 'vtkOpenGLVertexArrayObject'); // ---------------------------------------------------------------------------- var vtkVertexArrayObject = { newInstance: newInstance, extend: extend }; export { vtkVertexArrayObject as default, extend, newInstance };