function WebGLAttributes(gl, capabilities) { const isWebGL2 = capabilities.isWebGL2; const buffers = new WeakMap(); function createBuffer(attribute, bufferType) { const array = attribute.array; const usage = attribute.usage; const buffer = gl.createBuffer(); gl.bindBuffer(bufferType, buffer); gl.bufferData(bufferType, array, usage); attribute.onUploadCallback(); let type = gl.FLOAT; if (array instanceof Float32Array) { type = gl.FLOAT; } else if (array instanceof Float64Array) { console.warn('THREE.WebGLAttributes: Unsupported data buffer format: Float64Array.'); } else if (array instanceof Uint16Array) { if (attribute.isFloat16BufferAttribute) { if (isWebGL2) { type = gl.HALF_FLOAT; } else { console.warn('THREE.WebGLAttributes: Usage of Float16BufferAttribute requires WebGL2.'); } } else { type = gl.UNSIGNED_SHORT; } } else if (array instanceof Int16Array) { type = gl.SHORT; } else if (array instanceof Uint32Array) { type = gl.UNSIGNED_INT; } else if (array instanceof Int32Array) { type = gl.INT; } else if (array instanceof Int8Array) { type = gl.BYTE; } else if (array instanceof Uint8Array) { type = gl.UNSIGNED_BYTE; } else if (array instanceof Uint8ClampedArray) { type = gl.UNSIGNED_BYTE; } return { buffer: buffer, type: type, bytesPerElement: array.BYTES_PER_ELEMENT, version: attribute.version, }; } function updateBuffer(buffer, attribute, bufferType) { const array = attribute.array; const updateRange = attribute.updateRange; gl.bindBuffer(bufferType, buffer); if (updateRange.count === -1) { // Not using update ranges gl.bufferSubData(bufferType, 0, array); } else { if (isWebGL2) { gl.bufferSubData(bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, array, updateRange.offset, updateRange.count); } else { gl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT, array.subarray(updateRange.offset, updateRange.offset + updateRange.count) ); } updateRange.count = -1; // reset range } } // function get(attribute) { if (attribute.isInterleavedBufferAttribute) attribute = attribute.data; return buffers.get(attribute); } function remove(attribute) { if (attribute.isInterleavedBufferAttribute) attribute = attribute.data; const data = buffers.get(attribute); if (data) { gl.deleteBuffer(data.buffer); buffers.delete(attribute); } } function update(attribute, bufferType) { if (attribute.isGLBufferAttribute) { const cached = buffers.get(attribute); if (!cached || cached.version < attribute.version) { buffers.set(attribute, { buffer: attribute.buffer, type: attribute.type, bytesPerElement: attribute.elementSize, version: attribute.version, }); } return; } if (attribute.isInterleavedBufferAttribute) attribute = attribute.data; const data = buffers.get(attribute); if (data === undefined) { buffers.set(attribute, createBuffer(attribute, bufferType)); } else if (data.version < attribute.version) { updateBuffer(data.buffer, attribute, bufferType); data.version = attribute.version; } } return { get: get, remove: remove, update: update, }; } export { WebGLAttributes };