UNPKG

playcanvas

Version:

PlayCanvas WebGL game engine

115 lines (112 loc) 3.62 kB
import { PIXELFORMAT_SRGBA8, PIXELFORMAT_RGBA8 } from '../../../platform/graphics/constants.js'; import { Texture } from '../../../platform/graphics/texture.js'; import { http } from '../../../platform/net/http.js'; import { ABSOLUTE_URL } from '../../asset/constants.js'; import { TextureParser } from './texture.js'; class ImgParser extends TextureParser { constructor(registry, device){ super(); this.crossOrigin = registry.prefix ? 'anonymous' : null; this.maxRetries = 0; this.device = device; } load(url, callback, asset) { const hasContents = !!asset?.file?.contents; if (hasContents) { if (this.device.supportsImageBitmap) { this._loadImageBitmapFromBlob(new Blob([ asset.file.contents ]), callback); return; } url = { load: URL.createObjectURL(new Blob([ asset.file.contents ])), original: url.original }; } const handler = (err, result)=>{ if (hasContents) { URL.revokeObjectURL(url.load); } callback(err, result); }; let crossOrigin; if (asset && asset.options && asset.options.hasOwnProperty('crossOrigin')) { crossOrigin = asset.options.crossOrigin; } else if (ABSOLUTE_URL.test(url.load)) { crossOrigin = this.crossOrigin; } if (this.device.supportsImageBitmap) { this._loadImageBitmap(url.load, url.original, crossOrigin, handler, asset); } else { this._loadImage(url.load, url.original, crossOrigin, handler, asset); } } open(url, data, device, textureOptions = {}) { const texture = new Texture(device, { name: url, width: data.width, height: data.height, format: textureOptions.srgb ? PIXELFORMAT_SRGBA8 : PIXELFORMAT_RGBA8, ...textureOptions }); texture.setSource(data); return texture; } _loadImage(url, originalUrl, crossOrigin, callback, asset) { const image = new Image(); if (crossOrigin) { image.crossOrigin = crossOrigin; } let retries = 0; const maxRetries = this.maxRetries; let retryTimeout; const dummySize = 1024 * 1024; asset?.fire('progress', 0, dummySize); image.onload = function() { asset?.fire('progress', dummySize, dummySize); callback(null, image); }; image.onerror = function() { if (retryTimeout) return; if (maxRetries > 0 && ++retries <= maxRetries) { const retryDelay = Math.pow(2, retries) * 100; console.log(`Error loading Texture from: '${originalUrl}' - Retrying in ${retryDelay}ms...`); const idx = url.indexOf('?'); const separator = idx >= 0 ? '&' : '?'; retryTimeout = setTimeout(()=>{ image.src = `${url + separator}retry=${Date.now()}`; retryTimeout = null; }, retryDelay); } else { callback(`Error loading Texture from: '${originalUrl}'`); } }; image.src = url; } _loadImageBitmap(url, originalUrl, crossOrigin, callback, asset) { const options = { cache: true, responseType: 'blob', retry: this.maxRetries > 0, maxRetries: this.maxRetries, progress: asset }; http.get(url, options, (err, blob)=>{ if (err) { callback(err); } else { this._loadImageBitmapFromBlob(blob, callback); } }); } _loadImageBitmapFromBlob(blob, callback) { createImageBitmap(blob, { premultiplyAlpha: 'none', colorSpaceConversion: 'none' }).then((imageBitmap)=>callback(null, imageBitmap)).catch((e)=>callback(e)); } } export { ImgParser };