playcanvas
Version:
PlayCanvas WebGL game engine
115 lines (112 loc) • 3.62 kB
JavaScript
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 };