three
Version:
JavaScript 3D library
230 lines (127 loc) • 4.36 kB
JavaScript
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 size = array.byteLength;
const buffer = gl.createBuffer();
gl.bindBuffer( bufferType, buffer );
gl.bufferData( bufferType, array, usage );
attribute.onUploadCallback();
let type;
if ( array instanceof Float32Array ) {
type = gl.FLOAT;
} else if ( array instanceof Uint16Array ) {
if ( attribute.isFloat16BufferAttribute ) {
if ( isWebGL2 ) {
type = gl.HALF_FLOAT;
} else {
throw new Error( '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;
} else {
throw new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array );
}
return {
buffer: buffer,
type: type,
bytesPerElement: array.BYTES_PER_ELEMENT,
version: attribute.version,
size: size
};
}
function updateBuffer( buffer, attribute, bufferType ) {
const array = attribute.array;
const updateRange = attribute._updateRange; // deprecated
const updateRanges = attribute.updateRanges;
gl.bindBuffer( bufferType, buffer );
if ( updateRange.count === - 1 && updateRanges.length === 0 ) {
// Not using update ranges
gl.bufferSubData( bufferType, 0, array );
}
if ( updateRanges.length !== 0 ) {
for ( let i = 0, l = updateRanges.length; i < l; i ++ ) {
const range = updateRanges[ i ];
if ( isWebGL2 ) {
gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
array, range.start, range.count );
} else {
gl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,
array.subarray( range.start, range.start + range.count ) );
}
}
attribute.clearUpdateRanges();
}
// deprecated
if ( updateRange.count !== - 1 ) {
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
}
attribute.onUploadCallback();
}
//
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 ) {
if ( data.size !== attribute.array.byteLength ) {
throw new Error( 'THREE.WebGLAttributes: The size of the buffer attribute\'s array buffer does not match the original size. Resizing buffer attributes is not supported.' );
}
updateBuffer( data.buffer, attribute, bufferType );
data.version = attribute.version;
}
}
return {
get: get,
remove: remove,
update: update
};
}
export { WebGLAttributes };