123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364 |
- /**
- * @author Don McCurdy / https://www.donmccurdy.com
- */
- THREE.GLTFDRACOLoader = function(manager) {
- this.manager = manager || THREE.DefaultLoadingManager;
- this.decoderPath = '';
- this.decoderConfig = {};
- this.workerLimit = 4;
- this.workerPool = [];
- this.workerNextTaskID = 1;
- this.workerSourceURL = '';
- };
- THREE.GLTFDRACOLoader.prototype = {
- constructor: THREE.GLTFDRACOLoader,
- decodeDracoFile: function ( rawBuffer, callback, attributeIDs, attributeTypes ) {
- var taskID = this.workerNextTaskID++;
- var worker = this.getWorker();
- worker._callbacks[ taskID ] = callback;
- worker._taskCosts[ taskID ] = rawBuffer.byteLength;
- worker._taskLoad += worker._taskCosts[ taskID ];
- worker._taskCount++;
- var attributeTypesSerialized = {};
- for ( var name in attributeTypes ) {
- attributeTypesSerialized[ name ] = attributeTypes[ name ].name;
- }
- worker.postMessage( {
- type: 'decode',
- id: taskID,
- rawBuffer: rawBuffer,
- attributeIDs: attributeIDs,
- attributeTypes: attributeTypesSerialized
- } );
- },
- setDecoderPath: function ( path ) {
- this.decoderPath = path;
- },
- setDecoderConfig: function ( config ) {
- this.decoderConfig = config || {};
- },
- setWorkerLimit: function ( count ) {
- this.workerLimit = count;
- },
- getWorker: function () {
- if ( this.workerPool.length < this.workerLimit ) {
- if ( !this.workerSourceURL ) {
- var fn = GLTFDRACOWorker.toString();
- var body = fn.substring( fn.indexOf( '{' ) + 1, fn.lastIndexOf( '}' ) );
- this.workerSourceURL = URL.createObjectURL( new Blob( [ body ] ) );
- }
- var worker = new Worker( this.workerSourceURL );
- worker._callbacks = {};
- worker._taskCosts = {};
- worker._taskLoad = 0;
- worker._taskCount = 0;
- worker.postMessage( {
- type: 'init',
- decoderPath: new URL( this.decoderPath, window.location.href ).href, // TODO: Fails in IE11.
- decoderConfig: this.decoderConfig
- } );
- worker.onmessage = function ( e ) {
- var message = e.data;
- switch ( message.type ) {
- case 'decode':
- var geometry = new THREE.BufferGeometry();
- geometry.setIndex( new THREE.BufferAttribute( message.mesh.index.buffer, 1 ) );
- for ( var i = 0; i < message.mesh.attributes.length; i++ ) {
- var attribute = message.mesh.attributes[ i ];
- geometry.addAttribute( attribute.name, new THREE.BufferAttribute( attribute.buffer, attribute.itemSize ) );
- }
- worker._callbacks[ message.id ]( geometry );
- worker._taskLoad -= worker._taskCosts[ message.id ];
- delete worker._callbacks[ message.id ];
- delete worker._taskCosts[ message.id ];
- break;
- default:
- throw new Error( 'THREE.GLTFDRACOLoader: Unexpected message, "' + message.type + '"' );
- }
- }
- this.workerPool.push( worker );
- } else {
- this.workerPool.sort( function ( a, b ) { return a._taskLoad > b._taskLoad ? -1 : 1; } );
- }
- return this.workerPool[ this.workerPool.length - 1 ];
- },
- dispose: function () {
- for ( var i = 0; i < this.workerPool.length; i++ ) {
- this.workerPool[ i ].terminate();
- }
- this.workerPool.length = 0;
- }
- };
- function GLTFDRACOWorker () {
- var decoderPath;
- var decoderConfig;
- var decoderModulePromise;
- onmessage = function ( e ) {
- var message = e.data;
- switch ( message.type ) {
- case 'init':
- decoderPath = message.decoderPath;
- decoderConfig = message.decoderConfig;
- getDecoderModule();
- break;
- case 'decode':
- decode( message.rawBuffer, message.attributeIDs, message.attributeTypes )
- .then( function ( mesh ) {
- var buffers = [ mesh.index.buffer.buffer ];
- for ( var i = 0; i < mesh.attributes.length; i++ ) {
- buffers.push( mesh.attributes[ i ].buffer.buffer );
- }
- self.postMessage( { type: 'decode', id: message.id, mesh: mesh }, buffers );
- } );
- break;
- default:
- throw new Error( 'THREE.GLTFDRACOLoader: Unexpected message type.' );
- }
- };
- function getDecoderModule () {
- if ( decoderModulePromise ) return decoderModulePromise;
- var promise;
- if ( typeof WebAssembly !== 'object' || decoderConfig.type === 'js' ) {
- // Load with asm.js.
- self.importScripts( decoderPath + 'draco_decoder.js' );
- promise = Promise.resolve();
- } else {
- // Load with WebAssembly.
- self.importScripts( decoderPath + 'draco_wasm_wrapper.js' );
- decoderConfig.wasmBinaryFile = decoderPath + 'draco_decoder.wasm';
- promise = fetch( decoderConfig.wasmBinaryFile )
- .then( function ( wasmResponse ) { return wasmResponse.arrayBuffer(); } )
- .then( function ( wasmBinary ) { decoderConfig.wasmBinary = wasmBinary; } );
- }
- // Wait for source files, then create and return a decoder.
- promise = promise.then( function () {
- return new Promise( function ( resolve ) {
- decoderConfig.onModuleLoaded = function ( draco ) {
- // Module is Promise-like. Wrap before resolving to avoid loop.
- resolve( { draco: draco } );
- };
- DracoDecoderModule( decoderConfig );
- } );
- } );
- decoderModulePromise = promise;
- return promise;
- }
- function decode ( rawBuffer, attributeIDs, attributeTypes ) {
- return getDecoderModule().then( function ( module ) {
- var draco = module.draco;
- var decoder = new draco.Decoder();
- var buffer = new draco.DecoderBuffer();
- buffer.Init( new Int8Array( rawBuffer ), rawBuffer.byteLength );
- try {
- return this.decodeGeometry( draco, decoder, buffer, attributeIDs, attributeTypes );
- } finally {
- draco.destroy( buffer );
- draco.destroy( decoder );
- }
- } );
- }
- function decodeGeometry ( draco, decoder, buffer, attributeIDs, attributeTypes ) {
- var dracoGeometry = new draco.Mesh();
- var decodingStatus = decoder.DecodeBufferToMesh( buffer, dracoGeometry );
- if ( !decodingStatus.ok() || dracoGeometry.ptr == 0 ) {
- throw new Error( 'THREE.GLTFDRACOLoader: Decoding failed: ' + decodingStatus.error_msg() );
- }
- var geometry = { index: null, attributes: [] };
-
- var numFaces = dracoGeometry.num_faces();
- var numPoints = dracoGeometry.num_points();
- var numAttributes = dracoGeometry.num_attributes();
- // Add attributes of user specified unique id.
- for (var attributeName in attributeIDs) {
- var attributeType = self[ attributeTypes[ attributeName ] ];
- var attributeId = attributeIDs[attributeName];
- var attribute = decoder.GetAttributeByUniqueId( dracoGeometry, attributeId );
- geometry.attributes.push( this.decodeAttribute( draco, decoder, dracoGeometry, attributeName, attributeType, attribute ) );
- }
- // Generate mesh faces.
- var numIndices = numFaces * 3;
- var index = new Uint32Array(numIndices);
- var indexArray = new draco.DracoInt32Array();
- for (var i = 0; i < numFaces; ++i) {
- decoder.GetFaceFromMesh(dracoGeometry, i, indexArray);
- index[i * 3] = indexArray.GetValue(0);
- index[i * 3 + 1] = indexArray.GetValue(1);
- index[i * 3 + 2] = indexArray.GetValue(2);
- }
- geometry.index = { buffer: index, itemSize: 1 };
- draco.destroy( indexArray );
- draco.destroy( dracoGeometry );
- return geometry;
- }
- function decodeAttribute ( draco, decoder, dracoGeometry, attributeName, attributeType, attribute ) {
- var numComponents = attribute.num_components();
- var numPoints = dracoGeometry.num_points();
- var numValues = numPoints * numComponents;
- var dracoArray;
- var buffer;
- switch ( attributeType ) {
- case Float32Array:
- dracoArray = new draco.DracoFloat32Array();
- decoder.GetAttributeFloatForAllPoints( dracoGeometry, attribute, dracoArray );
- buffer = new Float32Array( numValues );
- break;
- case Int8Array:
- dracoArray = new draco.DracoInt8Array();
- decoder.GetAttributeInt8ForAllPoints( dracoGeometry, attribute, dracoArray );
- buffer = new Int8Array( numValues );
- break;
- case Int16Array:
- dracoArray = new draco.DracoInt16Array();
- decoder.GetAttributeInt16ForAllPoints( dracoGeometry, attribute, dracoArray );
- buffer = new Int16Array( numValues );
- break;
- case Int32Array:
- dracoArray = new draco.DracoInt32Array();
- decoder.GetAttributeInt32ForAllPoints( dracoGeometry, attribute, dracoArray );
- buffer = new Int32Array( numValues );
- break;
- case Uint8Array:
- dracoArray = new draco.DracoUInt8Array();
- decoder.GetAttributeUInt8ForAllPoints( dracoGeometry, attribute, dracoArray );
- buffer = new Uint8Array( numValues );
- break;
- case Uint16Array:
- dracoArray = new draco.DracoUInt16Array();
- decoder.GetAttributeUInt16ForAllPoints( dracoGeometry, attribute, dracoArray );
- buffer = new Uint16Array( numValues );
- break;
- case Uint32Array:
- dracoArray = new draco.DracoUInt32Array();
- decoder.GetAttributeUInt32ForAllPoints( dracoGeometry, attribute, dracoArray );
- buffer = new Uint32Array( numValues );
- break;
- default:
- throw new Error( 'THREE.GLTFDRACOLoader: Unexpected attribute type.' );
- }
- for ( var i = 0; i < numValues; i++ ) {
- buffer[ i ] = dracoArray.GetValue( i );
- }
- draco.destroy( dracoArray );
- return {
- name: attributeName,
- buffer: buffer,
- itemSize: numComponents
- };
-
- };
- };
|