/// namespace TSE { /** Represents the Information needed for a GLBuffer Attribute. */ export class AttributeInfo { /** The location of this Attribute */ public location: number; /** The size (number of elements) in this Attribute (i.e Vector3 = 3). */ public size: number; /** The number of Elements from the beginning of the Buffer. */ public offset: number; public constructor(location: number, size: number) { this.location = location; this.size = size; this.offset = 0; } } /** Represents a WebGLBuffer */ export class GLBuffer { private _hasAttributeLocation: boolean = false; private _elementSize: number; private _stride: number; private _buffer: WebGLBuffer; private _targetBufferType: number; private _dataType: number; private _mode: number; private _typeSize: number; private _data: number[] = []; private _attributes: AttributeInfo[] = []; /** * Creates a new GLBuffer. * @param elementSize The size of each Element in this Buffer. * @param dataType The data type of this Buffer. Default: FLOAT * @param targetBufferType The Buffer target type. ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER. Default: ARRAY_BUFFER * @param mode The drawing mode of this Buffer. TRIANGLES, LINES. Default: TRIANGLES */ public constructor(dataType: number = gl.FLOAT, targetBufferType: number = gl.ARRAY_BUFFER, mode: number = gl.TRIANGLES) { this._elementSize = 0; this._dataType = dataType; this._targetBufferType = targetBufferType; this._mode = mode; // Determine Byte size switch (this._dataType) { case gl.FLOAT: case gl.INT: case gl.UNSIGNED_INT: this._typeSize = 4; break; case gl.SHORT: case gl.UNSIGNED_SHORT: this._typeSize = 2; break; case gl.BYTE: case gl.UNSIGNED_BYTE: this._typeSize = 1; break; default: throw new Error("Unrecognized data type: " + dataType.toString()); } this._buffer = gl.createBuffer(); } /** Destroys this Buffer. */ public destroy(): void { gl.deleteBuffer(this._buffer); } /** * Binds this Buffer. * @param normalized Indecates if the BufferData should be normalized. Default: false */ public bind(normalized: boolean = false): void { gl.bindBuffer(this._targetBufferType, this._buffer); if (this._hasAttributeLocation) { for (let it of this._attributes) { gl.vertexAttribPointer(it.location, it.size, this._dataType, normalized, this._stride, it.offset * this._typeSize); gl.enableVertexAttribArray(it.location); } } } /** Unbinds this Buffer. */ public unbind(): void { if (this._hasAttributeLocation) { for (let it of this._attributes) { gl.disableVertexAttribArray(it.location); } } gl.bindBuffer(this._targetBufferType, undefined); } /** * Adds an Attribute with the provided info to this Buffer. * @param info The Attribute Information. */ public addAttributeLocation(info: AttributeInfo): void { this._hasAttributeLocation = true; info.offset = this._elementSize; this._attributes.push(info); this._elementSize += info.size; this._stride = this._elementSize * this._typeSize; } /** * Adds Data to this Buffer. * @param data The Data for this Buffer. */ public pushBackData(data: number[]): void { for (let d of data) this._data.push(d); } public clearData(): void { this._data.length = 0; } public setData(data: number[]): void { this.clearData(); this.pushBackData(data); } /** Upload the BufferData to the GPU */ public upload(): void { gl.bindBuffer(this._targetBufferType, this._buffer); let bufferData: ArrayBuffer; switch (this._dataType) { case gl.FLOAT: bufferData = new Float32Array(this._data); break; case gl.INT: bufferData = new Int32Array(this._data); break; case gl.UNSIGNED_INT: bufferData = new Uint32Array(this._data); break; case gl.SHORT: bufferData = new Int16Array(this._data); break; case gl.UNSIGNED_SHORT: bufferData = new Uint16Array(this._data); break; case gl.BYTE: bufferData = new Int8Array(this._data); break; case gl.UNSIGNED_BYTE: bufferData = new Uint8Array(this._data); break; } gl.bufferData(this._targetBufferType, bufferData, gl.STATIC_DRAW); } /** Draws this Buffer. */ public draw(): void { if (this._targetBufferType === gl.ARRAY_BUFFER) gl.drawArrays(this._mode, 0, this._data.length / this._elementSize); if (this._targetBufferType === gl.ELEMENT_ARRAY_BUFFER) gl.drawElements(this._mode, this._data.length, this._dataType, 0); } } }