import { Logger } from '../..'; /** * Helper that defines and index buffer for quad geometry * * Index buffers allow you to save space in vertex buffers when you share vertices in geometry * it is almost always worth it in terms of performance to use an index buffer. */ export class QuadIndexBuffer { private _gl: WebGL2RenderingContext; private _logger: Logger = Logger.getInstance(); /** * Access to the webgl buffer handle */ public buffer: WebGLBuffer; /** * Access to the raw data of the index buffer */ public bufferData: Uint16Array | Uint32Array; /** * Depending on the browser this is either gl.UNSIGNED_SHORT or gl.UNSIGNED_INT */ public bufferGlType!: number; /** * @param gl WebGL2RenderingContext this layout will be attached to, these cannot be reused across contexts. * @param numberOfQuads Specify the max number of quads you want to draw * @param useUint16 Optionally force a uint16 buffer */ constructor(gl: WebGL2RenderingContext, numberOfQuads: number, useUint16?: boolean) { this._gl = gl; this.buffer = gl.createBuffer()!; gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.buffer); const totalVertices = numberOfQuads * 6; if (!useUint16) { this.bufferData = new Uint32Array(totalVertices); } else { // fall back to using gl.UNSIGNED_SHORT or tell the user they are out of luck const maxUint16 = 65_535; const maxUint16Index = Math.floor((maxUint16 - 1) / 4); // max quads this.bufferGlType = gl.UNSIGNED_SHORT; this.bufferData = new Uint16Array(totalVertices); // TODO Should we error if this happens?? maybe not might crash mid game if (numberOfQuads > maxUint16Index) { this._logger.warn( `Total quads exceeds hardware index buffer limit (uint16), max(${maxUint16Index}) requested quads(${numberOfQuads})` ); } } let currentQuad = 0; for (let i = 0; i < totalVertices; i += 6) { // first triangle this.bufferData[i + 0] = currentQuad + 0; this.bufferData[i + 1] = currentQuad + 1; this.bufferData[i + 2] = currentQuad + 2; // second triangle this.bufferData[i + 3] = currentQuad + 2; this.bufferData[i + 4] = currentQuad + 1; this.bufferData[i + 5] = currentQuad + 3; currentQuad += 4; } gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.bufferData, gl.STATIC_DRAW); } public get size() { return this.bufferData.length; } /** * Upload data to the GPU */ public upload() { const gl = this._gl; gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.buffer); gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, this.bufferData, gl.STATIC_DRAW); } /** * Bind this index buffer */ public bind() { const gl = this._gl; gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.buffer); } public dispose() { const gl = this._gl; gl.deleteBuffer(this.buffer); this._gl = null as any; } }