mirror of
https://github.com/tengge1/ShadowEditor.git
synced 2026-01-25 15:08:11 +00:00
724 lines
18 KiB
JavaScript
724 lines
18 KiB
JavaScript
/** Copyright 2016 The Draco Authors.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @param {THREE.LoadingManager} manager
|
|
*/
|
|
THREE.DRACOLoader = function ( manager ) {
|
|
|
|
this.timeLoaded = 0;
|
|
this.manager = manager || THREE.DefaultLoadingManager;
|
|
this.materials = null;
|
|
this.verbosity = 0;
|
|
this.attributeOptions = {};
|
|
this.drawMode = THREE.TrianglesDrawMode;
|
|
// Native Draco attribute type to Three.JS attribute type.
|
|
this.nativeAttributeMap = {
|
|
position: "POSITION",
|
|
normal: "NORMAL",
|
|
color: "COLOR",
|
|
uv: "TEX_COORD"
|
|
};
|
|
|
|
};
|
|
|
|
THREE.DRACOLoader.prototype = {
|
|
constructor: THREE.DRACOLoader,
|
|
|
|
load: function ( url, onLoad, onProgress, onError ) {
|
|
|
|
var scope = this;
|
|
var loader = new THREE.FileLoader( scope.manager );
|
|
loader.setPath( this.path );
|
|
loader.setResponseType( "arraybuffer" );
|
|
loader.load(
|
|
url,
|
|
function ( blob ) {
|
|
|
|
scope.decodeDracoFile( blob, onLoad );
|
|
|
|
},
|
|
onProgress,
|
|
onError
|
|
);
|
|
|
|
},
|
|
|
|
setPath: function ( value ) {
|
|
|
|
this.path = value;
|
|
return this;
|
|
|
|
},
|
|
|
|
setVerbosity: function ( level ) {
|
|
|
|
this.verbosity = level;
|
|
return this;
|
|
|
|
},
|
|
|
|
/**
|
|
* Sets desired mode for generated geometry indices.
|
|
* Can be either:
|
|
* THREE.TrianglesDrawMode
|
|
* THREE.TriangleStripDrawMode
|
|
*/
|
|
setDrawMode: function ( drawMode ) {
|
|
|
|
this.drawMode = drawMode;
|
|
return this;
|
|
|
|
},
|
|
|
|
/**
|
|
* Skips dequantization for a specific attribute.
|
|
* |attributeName| is the THREE.js name of the given attribute type.
|
|
* The only currently supported |attributeName| is 'position', more may be
|
|
* added in future.
|
|
*/
|
|
setSkipDequantization: function ( attributeName, skip ) {
|
|
|
|
var skipDequantization = true;
|
|
if ( typeof skip !== "undefined" ) skipDequantization = skip;
|
|
this.getAttributeOptions(
|
|
attributeName
|
|
).skipDequantization = skipDequantization;
|
|
return this;
|
|
|
|
},
|
|
|
|
/**
|
|
* Decompresses a Draco buffer. Names of attributes (for ID and type maps)
|
|
* must be one of the supported three.js types, including: position, color,
|
|
* normal, uv, uv2, skinIndex, skinWeight.
|
|
*
|
|
* @param {ArrayBuffer} rawBuffer
|
|
* @param {Function} callback
|
|
* @param {Object|undefined} attributeUniqueIdMap Provides a pre-defined ID
|
|
* for each attribute in the geometry to be decoded. If given,
|
|
* `attributeTypeMap` is required and `nativeAttributeMap` will be
|
|
* ignored.
|
|
* @param {Object|undefined} attributeTypeMap Provides a predefined data
|
|
* type (as a typed array constructor) for each attribute in the
|
|
* geometry to be decoded.
|
|
*/
|
|
decodeDracoFile: function (
|
|
rawBuffer,
|
|
callback,
|
|
attributeUniqueIdMap,
|
|
attributeTypeMap
|
|
) {
|
|
|
|
var scope = this;
|
|
THREE.DRACOLoader.getDecoderModule().then( function ( module ) {
|
|
|
|
scope.decodeDracoFileInternal(
|
|
rawBuffer,
|
|
module.decoder,
|
|
callback,
|
|
attributeUniqueIdMap,
|
|
attributeTypeMap
|
|
);
|
|
|
|
} );
|
|
|
|
},
|
|
|
|
decodeDracoFileInternal: function (
|
|
rawBuffer,
|
|
dracoDecoder,
|
|
callback,
|
|
attributeUniqueIdMap,
|
|
attributeTypeMap
|
|
) {
|
|
|
|
/*
|
|
* Here is how to use Draco Javascript decoder and get the geometry.
|
|
*/
|
|
var buffer = new dracoDecoder.DecoderBuffer();
|
|
buffer.Init( new Int8Array( rawBuffer ), rawBuffer.byteLength );
|
|
var decoder = new dracoDecoder.Decoder();
|
|
|
|
/*
|
|
* Determine what type is this file: mesh or point cloud.
|
|
*/
|
|
var geometryType = decoder.GetEncodedGeometryType( buffer );
|
|
if ( geometryType == dracoDecoder.TRIANGULAR_MESH ) {
|
|
|
|
if ( this.verbosity > 0 ) {
|
|
|
|
console.log( "Loaded a mesh." );
|
|
|
|
}
|
|
|
|
} else if ( geometryType == dracoDecoder.POINT_CLOUD ) {
|
|
|
|
if ( this.verbosity > 0 ) {
|
|
|
|
console.log( "Loaded a point cloud." );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
var errorMsg = "THREE.DRACOLoader: Unknown geometry type.";
|
|
console.error( errorMsg );
|
|
throw new Error( errorMsg );
|
|
|
|
}
|
|
callback(
|
|
this.convertDracoGeometryTo3JS(
|
|
dracoDecoder,
|
|
decoder,
|
|
geometryType,
|
|
buffer,
|
|
attributeUniqueIdMap,
|
|
attributeTypeMap
|
|
)
|
|
);
|
|
|
|
},
|
|
|
|
addAttributeToGeometry: function (
|
|
dracoDecoder,
|
|
decoder,
|
|
dracoGeometry,
|
|
attributeName,
|
|
attributeType,
|
|
attribute,
|
|
geometry,
|
|
geometryBuffer
|
|
) {
|
|
|
|
if ( attribute.ptr === 0 ) {
|
|
|
|
var errorMsg = "THREE.DRACOLoader: No attribute " + attributeName;
|
|
console.error( errorMsg );
|
|
throw new Error( errorMsg );
|
|
|
|
}
|
|
|
|
var numComponents = attribute.num_components();
|
|
var numPoints = dracoGeometry.num_points();
|
|
var numValues = numPoints * numComponents;
|
|
var attributeData;
|
|
var TypedBufferAttribute;
|
|
|
|
switch ( attributeType ) {
|
|
|
|
case Float32Array:
|
|
attributeData = new dracoDecoder.DracoFloat32Array();
|
|
decoder.GetAttributeFloatForAllPoints(
|
|
dracoGeometry,
|
|
attribute,
|
|
attributeData
|
|
);
|
|
geometryBuffer[ attributeName ] = new Float32Array( numValues );
|
|
TypedBufferAttribute = THREE.Float32BufferAttribute;
|
|
break;
|
|
|
|
case Int8Array:
|
|
attributeData = new dracoDecoder.DracoInt8Array();
|
|
decoder.GetAttributeInt8ForAllPoints(
|
|
dracoGeometry,
|
|
attribute,
|
|
attributeData
|
|
);
|
|
geometryBuffer[ attributeName ] = new Int8Array( numValues );
|
|
TypedBufferAttribute = THREE.Int8BufferAttribute;
|
|
break;
|
|
|
|
case Int16Array:
|
|
attributeData = new dracoDecoder.DracoInt16Array();
|
|
decoder.GetAttributeInt16ForAllPoints(
|
|
dracoGeometry,
|
|
attribute,
|
|
attributeData
|
|
);
|
|
geometryBuffer[ attributeName ] = new Int16Array( numValues );
|
|
TypedBufferAttribute = THREE.Int16BufferAttribute;
|
|
break;
|
|
|
|
case Int32Array:
|
|
attributeData = new dracoDecoder.DracoInt32Array();
|
|
decoder.GetAttributeInt32ForAllPoints(
|
|
dracoGeometry,
|
|
attribute,
|
|
attributeData
|
|
);
|
|
geometryBuffer[ attributeName ] = new Int32Array( numValues );
|
|
TypedBufferAttribute = THREE.Int32BufferAttribute;
|
|
break;
|
|
|
|
case Uint8Array:
|
|
attributeData = new dracoDecoder.DracoUInt8Array();
|
|
decoder.GetAttributeUInt8ForAllPoints(
|
|
dracoGeometry,
|
|
attribute,
|
|
attributeData
|
|
);
|
|
geometryBuffer[ attributeName ] = new Uint8Array( numValues );
|
|
TypedBufferAttribute = THREE.Uint8BufferAttribute;
|
|
break;
|
|
|
|
case Uint16Array:
|
|
attributeData = new dracoDecoder.DracoUInt16Array();
|
|
decoder.GetAttributeUInt16ForAllPoints(
|
|
dracoGeometry,
|
|
attribute,
|
|
attributeData
|
|
);
|
|
geometryBuffer[ attributeName ] = new Uint16Array( numValues );
|
|
TypedBufferAttribute = THREE.Uint16BufferAttribute;
|
|
break;
|
|
|
|
case Uint32Array:
|
|
attributeData = new dracoDecoder.DracoUInt32Array();
|
|
decoder.GetAttributeUInt32ForAllPoints(
|
|
dracoGeometry,
|
|
attribute,
|
|
attributeData
|
|
);
|
|
geometryBuffer[ attributeName ] = new Uint32Array( numValues );
|
|
TypedBufferAttribute = THREE.Uint32BufferAttribute;
|
|
break;
|
|
|
|
default:
|
|
var errorMsg = "THREE.DRACOLoader: Unexpected attribute type.";
|
|
console.error( errorMsg );
|
|
throw new Error( errorMsg );
|
|
|
|
}
|
|
|
|
// Copy data from decoder.
|
|
for ( var i = 0; i < numValues; i ++ ) {
|
|
|
|
geometryBuffer[ attributeName ][ i ] = attributeData.GetValue( i );
|
|
|
|
}
|
|
// Add attribute to THREEJS geometry for rendering.
|
|
geometry.addAttribute(
|
|
attributeName,
|
|
new TypedBufferAttribute( geometryBuffer[ attributeName ], numComponents )
|
|
);
|
|
dracoDecoder.destroy( attributeData );
|
|
|
|
},
|
|
|
|
convertDracoGeometryTo3JS: function (
|
|
dracoDecoder,
|
|
decoder,
|
|
geometryType,
|
|
buffer,
|
|
attributeUniqueIdMap,
|
|
attributeTypeMap
|
|
) {
|
|
|
|
// TODO: Should not assume native Draco attribute IDs apply.
|
|
if ( this.getAttributeOptions( "position" ).skipDequantization === true ) {
|
|
|
|
decoder.SkipAttributeTransform( dracoDecoder.POSITION );
|
|
|
|
}
|
|
var dracoGeometry;
|
|
var decodingStatus;
|
|
var start_time = performance.now();
|
|
if ( geometryType === dracoDecoder.TRIANGULAR_MESH ) {
|
|
|
|
dracoGeometry = new dracoDecoder.Mesh();
|
|
decodingStatus = decoder.DecodeBufferToMesh( buffer, dracoGeometry );
|
|
|
|
} else {
|
|
|
|
dracoGeometry = new dracoDecoder.PointCloud();
|
|
decodingStatus = decoder.DecodeBufferToPointCloud( buffer, dracoGeometry );
|
|
|
|
}
|
|
if ( ! decodingStatus.ok() || dracoGeometry.ptr == 0 ) {
|
|
|
|
var errorMsg = "THREE.DRACOLoader: Decoding failed: ";
|
|
errorMsg += decodingStatus.error_msg();
|
|
console.error( errorMsg );
|
|
dracoDecoder.destroy( decoder );
|
|
dracoDecoder.destroy( dracoGeometry );
|
|
throw new Error( errorMsg );
|
|
|
|
}
|
|
|
|
var decode_end = performance.now();
|
|
dracoDecoder.destroy( buffer );
|
|
/*
|
|
* Example on how to retrieve mesh and attributes.
|
|
*/
|
|
var numFaces;
|
|
if ( geometryType == dracoDecoder.TRIANGULAR_MESH ) {
|
|
|
|
numFaces = dracoGeometry.num_faces();
|
|
if ( this.verbosity > 0 ) {
|
|
|
|
console.log( "Number of faces loaded: " + numFaces.toString() );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
numFaces = 0;
|
|
|
|
}
|
|
|
|
var numPoints = dracoGeometry.num_points();
|
|
var numAttributes = dracoGeometry.num_attributes();
|
|
if ( this.verbosity > 0 ) {
|
|
|
|
console.log( "Number of points loaded: " + numPoints.toString() );
|
|
console.log( "Number of attributes loaded: " + numAttributes.toString() );
|
|
|
|
}
|
|
|
|
// Verify if there is position attribute.
|
|
// TODO: Should not assume native Draco attribute IDs apply.
|
|
var posAttId = decoder.GetAttributeId( dracoGeometry, dracoDecoder.POSITION );
|
|
if ( posAttId == - 1 ) {
|
|
|
|
var errorMsg = "THREE.DRACOLoader: No position attribute found.";
|
|
console.error( errorMsg );
|
|
dracoDecoder.destroy( decoder );
|
|
dracoDecoder.destroy( dracoGeometry );
|
|
throw new Error( errorMsg );
|
|
|
|
}
|
|
var posAttribute = decoder.GetAttribute( dracoGeometry, posAttId );
|
|
|
|
// Structure for converting to THREEJS geometry later.
|
|
var geometryBuffer = {};
|
|
// Import data to Three JS geometry.
|
|
var geometry = new THREE.BufferGeometry();
|
|
|
|
// Do not use both the native attribute map and a provided (e.g. glTF) map.
|
|
if ( attributeUniqueIdMap ) {
|
|
|
|
// Add attributes of user specified unique id. E.g. GLTF models.
|
|
for ( var attributeName in attributeUniqueIdMap ) {
|
|
|
|
var attributeType = attributeTypeMap[ attributeName ];
|
|
var attributeId = attributeUniqueIdMap[ attributeName ];
|
|
var attribute = decoder.GetAttributeByUniqueId(
|
|
dracoGeometry,
|
|
attributeId
|
|
);
|
|
this.addAttributeToGeometry(
|
|
dracoDecoder,
|
|
decoder,
|
|
dracoGeometry,
|
|
attributeName,
|
|
attributeType,
|
|
attribute,
|
|
geometry,
|
|
geometryBuffer
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Add native Draco attribute type to geometry.
|
|
for ( var attributeName in this.nativeAttributeMap ) {
|
|
|
|
var attId = decoder.GetAttributeId(
|
|
dracoGeometry,
|
|
dracoDecoder[ this.nativeAttributeMap[ attributeName ] ]
|
|
);
|
|
if ( attId !== - 1 ) {
|
|
|
|
if ( this.verbosity > 0 ) {
|
|
|
|
console.log( "Loaded " + attributeName + " attribute." );
|
|
|
|
}
|
|
var attribute = decoder.GetAttribute( dracoGeometry, attId );
|
|
this.addAttributeToGeometry(
|
|
dracoDecoder,
|
|
decoder,
|
|
dracoGeometry,
|
|
attributeName,
|
|
Float32Array,
|
|
attribute,
|
|
geometry,
|
|
geometryBuffer
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// For mesh, we need to generate the faces.
|
|
if ( geometryType == dracoDecoder.TRIANGULAR_MESH ) {
|
|
|
|
if ( this.drawMode === THREE.TriangleStripDrawMode ) {
|
|
|
|
var stripsArray = new dracoDecoder.DracoInt32Array();
|
|
decoder.GetTriangleStripsFromMesh(
|
|
dracoGeometry,
|
|
stripsArray
|
|
);
|
|
geometryBuffer.indices = new Uint32Array( stripsArray.size() );
|
|
for ( var i = 0; i < stripsArray.size(); ++ i ) {
|
|
|
|
geometryBuffer.indices[ i ] = stripsArray.GetValue( i );
|
|
|
|
}
|
|
dracoDecoder.destroy( stripsArray );
|
|
|
|
} else {
|
|
|
|
var numIndices = numFaces * 3;
|
|
geometryBuffer.indices = new Uint32Array( numIndices );
|
|
var ia = new dracoDecoder.DracoInt32Array();
|
|
for ( var i = 0; i < numFaces; ++ i ) {
|
|
|
|
decoder.GetFaceFromMesh( dracoGeometry, i, ia );
|
|
var index = i * 3;
|
|
geometryBuffer.indices[ index ] = ia.GetValue( 0 );
|
|
geometryBuffer.indices[ index + 1 ] = ia.GetValue( 1 );
|
|
geometryBuffer.indices[ index + 2 ] = ia.GetValue( 2 );
|
|
|
|
}
|
|
dracoDecoder.destroy( ia );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
geometry.drawMode = this.drawMode;
|
|
if ( geometryType == dracoDecoder.TRIANGULAR_MESH ) {
|
|
|
|
geometry.setIndex(
|
|
new ( geometryBuffer.indices.length > 65535
|
|
? THREE.Uint32BufferAttribute
|
|
: THREE.Uint16BufferAttribute )( geometryBuffer.indices, 1 )
|
|
);
|
|
|
|
}
|
|
|
|
// TODO: Should not assume native Draco attribute IDs apply.
|
|
// TODO: Can other attribute types be quantized?
|
|
var posTransform = new dracoDecoder.AttributeQuantizationTransform();
|
|
if ( posTransform.InitFromAttribute( posAttribute ) ) {
|
|
|
|
// Quantized attribute. Store the quantization parameters into the
|
|
// THREE.js attribute.
|
|
geometry.attributes[ "position" ].isQuantized = true;
|
|
geometry.attributes[ "position" ].maxRange = posTransform.range();
|
|
geometry.attributes[
|
|
"position"
|
|
].numQuantizationBits = posTransform.quantization_bits();
|
|
geometry.attributes[ "position" ].minValues = new Float32Array( 3 );
|
|
for ( var i = 0; i < 3; ++ i ) {
|
|
|
|
geometry.attributes[ "position" ].minValues[ i ] = posTransform.min_value(
|
|
i
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
dracoDecoder.destroy( posTransform );
|
|
dracoDecoder.destroy( decoder );
|
|
dracoDecoder.destroy( dracoGeometry );
|
|
|
|
this.decode_time = decode_end - start_time;
|
|
this.import_time = performance.now() - decode_end;
|
|
|
|
if ( this.verbosity > 0 ) {
|
|
|
|
console.log( "Decode time: " + this.decode_time );
|
|
console.log( "Import time: " + this.import_time );
|
|
|
|
}
|
|
return geometry;
|
|
|
|
},
|
|
|
|
isVersionSupported: function ( version, callback ) {
|
|
|
|
THREE.DRACOLoader.getDecoderModule().then( function ( module ) {
|
|
|
|
callback( module.decoder.isVersionSupported( version ) );
|
|
|
|
} );
|
|
|
|
},
|
|
|
|
getAttributeOptions: function ( attributeName ) {
|
|
|
|
if ( typeof this.attributeOptions[ attributeName ] === "undefined" )
|
|
this.attributeOptions[ attributeName ] = {};
|
|
return this.attributeOptions[ attributeName ];
|
|
|
|
}
|
|
};
|
|
|
|
THREE.DRACOLoader.decoderPath = "./";
|
|
THREE.DRACOLoader.decoderConfig = {};
|
|
THREE.DRACOLoader.decoderModulePromise = null;
|
|
|
|
/**
|
|
* Sets the base path for decoder source files.
|
|
* @param {string} path
|
|
*/
|
|
THREE.DRACOLoader.setDecoderPath = function ( path ) {
|
|
|
|
THREE.DRACOLoader.decoderPath = path;
|
|
|
|
};
|
|
|
|
/**
|
|
* Sets decoder configuration and releases singleton decoder module. Module
|
|
* will be recreated with the next decoding call.
|
|
* @param {Object} config
|
|
*/
|
|
THREE.DRACOLoader.setDecoderConfig = function ( config ) {
|
|
|
|
var wasmBinary = THREE.DRACOLoader.decoderConfig.wasmBinary;
|
|
THREE.DRACOLoader.decoderConfig = config || {};
|
|
THREE.DRACOLoader.releaseDecoderModule();
|
|
|
|
// Reuse WASM binary.
|
|
if ( wasmBinary ) THREE.DRACOLoader.decoderConfig.wasmBinary = wasmBinary;
|
|
|
|
};
|
|
|
|
/**
|
|
* Releases the singleton DracoDecoderModule instance. Module will be recreated
|
|
* with the next decoding call.
|
|
*/
|
|
THREE.DRACOLoader.releaseDecoderModule = function () {
|
|
|
|
THREE.DRACOLoader.decoderModulePromise = null;
|
|
|
|
};
|
|
|
|
/**
|
|
* Gets WebAssembly or asm.js singleton instance of DracoDecoderModule
|
|
* after testing for browser support. Returns Promise that resolves when
|
|
* module is available.
|
|
* @return {Promise<{decoder: DracoDecoderModule}>}
|
|
*/
|
|
THREE.DRACOLoader.getDecoderModule = function () {
|
|
|
|
var scope = this;
|
|
var path = THREE.DRACOLoader.decoderPath;
|
|
var config = THREE.DRACOLoader.decoderConfig;
|
|
var promise = THREE.DRACOLoader.decoderModulePromise;
|
|
|
|
if ( promise ) return promise;
|
|
|
|
// Load source files.
|
|
if ( typeof DracoDecoderModule !== "undefined" ) {
|
|
|
|
// Loaded externally.
|
|
promise = Promise.resolve();
|
|
|
|
} else if ( typeof WebAssembly !== "object" || config.type === "js" ) {
|
|
|
|
// Load with asm.js.
|
|
promise = THREE.DRACOLoader._loadScript( path + "draco_decoder.js" );
|
|
|
|
} else {
|
|
|
|
// Load with WebAssembly.
|
|
config.wasmBinaryFile = path + "draco_decoder.wasm";
|
|
promise = THREE.DRACOLoader._loadScript( path + "draco_wasm_wrapper.js" )
|
|
.then( function () {
|
|
|
|
return THREE.DRACOLoader._loadArrayBuffer( config.wasmBinaryFile );
|
|
|
|
} )
|
|
.then( function ( wasmBinary ) {
|
|
|
|
config.wasmBinary = wasmBinary;
|
|
|
|
} );
|
|
|
|
}
|
|
|
|
// Wait for source files, then create and return a decoder.
|
|
promise = promise.then( function () {
|
|
|
|
return new Promise( function ( resolve ) {
|
|
|
|
config.onModuleLoaded = function ( decoder ) {
|
|
|
|
scope.timeLoaded = performance.now();
|
|
// Module is Promise-like. Wrap before resolving to avoid loop.
|
|
resolve( { decoder: decoder } );
|
|
|
|
};
|
|
DracoDecoderModule( config );
|
|
|
|
} );
|
|
|
|
} );
|
|
|
|
THREE.DRACOLoader.decoderModulePromise = promise;
|
|
return promise;
|
|
|
|
};
|
|
|
|
/**
|
|
* @param {string} src
|
|
* @return {Promise}
|
|
*/
|
|
THREE.DRACOLoader._loadScript = function ( src ) {
|
|
|
|
var prevScript = document.getElementById( "decoder_script" );
|
|
if ( prevScript !== null ) {
|
|
|
|
prevScript.parentNode.removeChild( prevScript );
|
|
|
|
}
|
|
var head = document.getElementsByTagName( "head" )[ 0 ];
|
|
var script = document.createElement( "script" );
|
|
script.id = "decoder_script";
|
|
script.type = "text/javascript";
|
|
script.src = src;
|
|
return new Promise( function ( resolve ) {
|
|
|
|
script.onload = resolve;
|
|
head.appendChild( script );
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
/**
|
|
* @param {string} src
|
|
* @return {Promise}
|
|
*/
|
|
THREE.DRACOLoader._loadArrayBuffer = function ( src ) {
|
|
|
|
var loader = new THREE.FileLoader();
|
|
loader.setResponseType( "arraybuffer" );
|
|
return new Promise( function ( resolve, reject ) {
|
|
|
|
loader.load( src, resolve, undefined, reject );
|
|
|
|
} );
|
|
|
|
};
|