@kitware/vtk.js
Version:
Visualization Toolkit for the Web
357 lines (279 loc) • 11.3 kB
JavaScript
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 };