UNPKG

three

Version:

JavaScript 3D library

197 lines (131 loc) 4.73 kB
import { Cache } from './Cache.js'; import { Loader } from './Loader.js'; const _errorMap = new WeakMap(); /** * A loader for loading images as an [ImageBitmap]{@link https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmap}. * An `ImageBitmap` provides an asynchronous and resource efficient pathway to prepare * textures for rendering. * * Note that {@link Texture#flipY} and {@link Texture#premultiplyAlpha} are ignored with image bitmaps. * They needs these configuration on bitmap creation unlike regular images need them on uploading to GPU. * * You need to set the equivalent options via {@link ImageBitmapLoader#setOptions} instead. * * Also note that unlike {@link FileLoader}, this loader avoids multiple concurrent requests to the same URL only if `Cache` is enabled. * * ```js * const loader = new THREE.ImageBitmapLoader(); * loader.setOptions( { imageOrientation: 'flipY' } ); // set options if needed * const imageBitmap = await loader.loadAsync( 'image.png' ); * * const texture = new THREE.Texture( imageBitmap ); * texture.needsUpdate = true; * ``` * * @augments Loader */ class ImageBitmapLoader extends Loader { /** * Constructs a new image bitmap loader. * * @param {LoadingManager} [manager] - The loading manager. */ constructor( manager ) { super( manager ); /** * This flag can be used for type testing. * * @type {boolean} * @readonly * @default true */ this.isImageBitmapLoader = true; if ( typeof createImageBitmap === 'undefined' ) { console.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' ); } if ( typeof fetch === 'undefined' ) { console.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' ); } /** * Represents the loader options. * * @type {Object} * @default {premultiplyAlpha:'none'} */ this.options = { premultiplyAlpha: 'none' }; } /** * Sets the given loader options. The structure of the object must match the `options` parameter of * [createImageBitmap]{@link https://developer.mozilla.org/en-US/docs/Web/API/Window/createImageBitmap}. * * @param {Object} options - The loader options to set. * @return {ImageBitmapLoader} A reference to this image bitmap loader. */ setOptions( options ) { this.options = options; return this; } /** * Starts loading from the given URL and pass the loaded image bitmap to the `onLoad()` callback. * * @param {string} url - The path/URL of the file to be loaded. This can also be a data URI. * @param {function(ImageBitmap)} onLoad - Executed when the loading process has been finished. * @param {onProgressCallback} onProgress - Unsupported in this loader. * @param {onErrorCallback} onError - Executed when errors occur. * @return {ImageBitmap|undefined} The image bitmap. */ load( url, onLoad, onProgress, onError ) { if ( url === undefined ) url = ''; if ( this.path !== undefined ) url = this.path + url; url = this.manager.resolveURL( url ); const scope = this; const cached = Cache.get( url ); if ( cached !== undefined ) { scope.manager.itemStart( url ); // If cached is a promise, wait for it to resolve if ( cached.then ) { cached.then( imageBitmap => { // check if there is an error for the cached promise if ( _errorMap.has( cached ) === true ) { if ( onError ) onError( _errorMap.get( cached ) ); scope.manager.itemError( url ); scope.manager.itemEnd( url ); } else { if ( onLoad ) onLoad( imageBitmap ); scope.manager.itemEnd( url ); return imageBitmap; } } ); return; } // If cached is not a promise (i.e., it's already an imageBitmap) setTimeout( function () { if ( onLoad ) onLoad( cached ); scope.manager.itemEnd( url ); }, 0 ); return cached; } const fetchOptions = {}; fetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include'; fetchOptions.headers = this.requestHeader; const promise = fetch( url, fetchOptions ).then( function ( res ) { return res.blob(); } ).then( function ( blob ) { return createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) ); } ).then( function ( imageBitmap ) { Cache.add( url, imageBitmap ); if ( onLoad ) onLoad( imageBitmap ); scope.manager.itemEnd( url ); return imageBitmap; } ).catch( function ( e ) { if ( onError ) onError( e ); _errorMap.set( promise, e ); Cache.remove( url ); scope.manager.itemError( url ); scope.manager.itemEnd( url ); } ); Cache.add( url, promise ); scope.manager.itemStart( url ); } } export { ImageBitmapLoader };