UNPKG

playcanvas

Version:

Open-source WebGL/WebGPU 3D engine for the web

115 lines (114 loc) 3.35 kB
import { PIXELFORMAT_RGBA8, PIXELFORMAT_SRGBA8, TEXHINT_ASSET } 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 };