three
Version:
JavaScript 3D library
186 lines (98 loc) • 3.5 kB
JavaScript
import { Uint32BufferAttribute, Uint16BufferAttribute } from 'three';
function arrayNeedsUint32( array ) {
// assumes larger values usually on last
for ( let i = array.length - 1; i >= 0; -- i ) {
if ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565
}
return false;
}
class WebGPUGeometries {
constructor( attributes, info ) {
this.attributes = attributes;
this.info = info;
this.geometries = new WeakMap();
this.wireframeGeometries = new WeakMap();
}
has( geometry ) {
return this.geometries.has( geometry );
}
update( geometry, wireframe = false ) {
const { geometries, attributes, info } = this;
if ( geometries.has( geometry ) === false ) {
const disposeCallback = onGeometryDispose.bind( this );
geometries.set( geometry, disposeCallback );
info.memory.geometries ++;
geometry.addEventListener( 'dispose', disposeCallback );
}
const geometryAttributes = geometry.attributes;
for ( const name in geometryAttributes ) {
attributes.update( geometryAttributes[ name ] );
}
const index = this.getIndex( geometry, wireframe );
if ( index !== null ) {
attributes.update( index, true );
}
}
getIndex( geometry, wireframe = false ) {
let index = geometry.index;
if ( wireframe ) {
const wireframeGeometries = this.wireframeGeometries;
let wireframeAttribute = wireframeGeometries.get( geometry );
if ( wireframeAttribute === undefined ) {
wireframeAttribute = this.getWireframeIndex( geometry );
wireframeGeometries.set( geometry, wireframeAttribute );
} else if ( wireframeAttribute.version !== this.getWireframeVersion( geometry ) ) {
this.attributes.remove( wireframeAttribute );
wireframeAttribute = this.getWireframeIndex( geometry );
wireframeGeometries.set( geometry, wireframeAttribute );
}
index = wireframeAttribute;
}
return index;
}
getWireframeIndex( geometry ) {
const indices = [];
const geometryIndex = geometry.index;
const geometryPosition = geometry.attributes.position;
if ( geometryIndex !== null ) {
const array = geometryIndex.array;
for ( let i = 0, l = array.length; i < l; i += 3 ) {
const a = array[ i + 0 ];
const b = array[ i + 1 ];
const c = array[ i + 2 ];
indices.push( a, b, b, c, c, a );
}
} else {
const array = geometryPosition.array;
for ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {
const a = i + 0;
const b = i + 1;
const c = i + 2;
indices.push( a, b, b, c, c, a );
}
}
const attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );
attribute.version = this.getWireframeVersion( geometry );
return attribute;
}
getWireframeVersion( geometry ) {
return ( geometry.index !== null ) ? geometry.index.version : geometry.attributes.position.version;
}
}
function onGeometryDispose( event ) {
const geometry = event.target;
const disposeCallback = this.geometries.get( geometry );
this.geometries.delete( geometry );
this.info.memory.geometries --;
geometry.removeEventListener( 'dispose', disposeCallback );
//
const index = geometry.index;
const geometryAttributes = geometry.attributes;
if ( index !== null ) {
this.attributes.remove( index );
}
for ( const name in geometryAttributes ) {
this.attributes.remove( geometryAttributes[ name ] );
}
}
export default WebGPUGeometries;