In which you acquire a utility class for managing a VAO.
Recall that you draw objects by marrying their attributes to a shader program to make a VAO. The following class officiates their union:
export class VertexArray {
constructor(program, attributes) {
this.vertexArray = gl.createVertexArray();
this.attributes = attributes;
gl.bindVertexArray(this.vertexArray);
for (let attribute of attributes) {
let location = program.getAttributeLocation(attribute.name);
if (location < 0) {
console.log(`${attribute.name} is not used in the shader.`);
} else {
gl.bindBuffer(gl.ARRAY_BUFFER, attribute.buffer);
gl.vertexAttribPointer(location, attribute.ncomponents, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(location);
}
}
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, attributes.indexBuffer);
this.unbind();
}
bind() {
gl.bindVertexArray(this.vertexArray);
this.isBound = true;
}
destroy() {
gl.deleteVertexArray(this.vertexArray);
}
unbind() {
gl.bindVertexArray(null);
this.isBound = false;
}
drawSequence(mode) {
gl.drawArrays(mode, 0, this.attributes.vertexCount);
}
drawIndexed(mode) {
// gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.attributes.indexBuffer);
gl.drawElements(mode, this.attributes.indexCount, gl.UNSIGNED_INT, 0);
}
}
Create a new file named vertex-array.js
and add in this code. The ceremony is short and sweet, consisting only of a constructor call:
const vao = new VertexArray(shaderProgram, attributes);
Drawing an object requires activating both the shader program and the VAO and then telling the GPU how to extract attributes out of the VBO:
shaderProgram.bind();
vao.bind();
vao.drawSequence(gl.POINTS);
vao.unbind();
shaderProgram.unbind();
Read on to see a complete example of these utility classes in action.