playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
118 lines (115 loc) • 3.45 kB
JavaScript
import { Asset } from '../../asset/asset.js';
import { GSplatAssetLoaderBase } from '../../../scene/gsplat-unified/gsplat-asset-loader-base.js';
class GSplatAssetLoader extends GSplatAssetLoaderBase {
destroy() {
this._destroyed = true;
for (const asset of this._urlToAsset.values()){
asset.fire('unload', asset);
asset.off('load');
asset.off('error');
this._registry.remove(asset);
asset.unload();
}
this._urlToAsset.clear();
this._loadQueue.length = 0;
this._currentlyLoading.clear();
this._retryCount.clear();
}
_canLoad() {
return !!this._registry.loader?.getHandler('gsplat');
}
load(url) {
const asset = this._urlToAsset.get(url);
if (asset?.loaded || this._currentlyLoading.has(url)) {
return;
}
if (this._loadQueue.includes(url)) {
return;
}
if (this._currentlyLoading.size < this.maxConcurrentLoads) {
this._startLoading(url);
} else {
this._loadQueue.push(url);
}
}
_startLoading(url) {
this._currentlyLoading.add(url);
let asset = this._urlToAsset.get(url);
if (!asset) {
asset = new Asset(url, 'gsplat', {
url
}, {}, {
minimalMemory: true
});
this._registry.add(asset);
this._urlToAsset.set(url, asset);
}
asset.once('load', ()=>this._onAssetLoadSuccess(url, asset));
asset.once('error', (err)=>this._onAssetLoadError(url, asset, err));
if (!asset.loaded && !asset.loading) {
this._registry.load(asset);
}
}
_onAssetLoadSuccess(url, asset) {
if (this._destroyed || !this._urlToAsset.has(url)) {
return;
}
this._currentlyLoading.delete(url);
this._retryCount.delete(url);
this._processQueue();
}
_onAssetLoadError(url, asset, err) {
if (this._destroyed || !this._canLoad() || !this._urlToAsset.has(url)) {
return;
}
const retryCount = this._retryCount.get(url) || 0;
if (retryCount < this.maxRetries) {
this._retryCount.set(url, retryCount + 1);
asset.loaded = false;
asset.loading = false;
this._registry.load(asset);
} else {
this._currentlyLoading.delete(url);
this._retryCount.delete(url);
this._processQueue();
}
}
_processQueue() {
if (this._destroyed || !this._canLoad()) {
return;
}
while(this._currentlyLoading.size < this.maxConcurrentLoads && this._loadQueue.length > 0){
const url = this._loadQueue.shift();
if (url) {
this._startLoading(url);
}
}
}
unload(url) {
this._currentlyLoading.delete(url);
const queueIndex = this._loadQueue.indexOf(url);
if (queueIndex !== -1) {
this._loadQueue.splice(queueIndex, 1);
}
this._retryCount.delete(url);
const asset = this._urlToAsset.get(url);
if (asset) {
asset.fire('unload', asset);
asset.off('load');
asset.off('error');
this._registry.remove(asset);
asset.unload();
this._urlToAsset.delete(url);
}
this._processQueue();
}
getResource(url) {
const asset = this._urlToAsset.get(url);
return asset?.resource;
}
constructor(registry){
super(), this._urlToAsset = new Map(), this.maxConcurrentLoads = 2, this.maxRetries = 2, this._currentlyLoading = new Set(), this._loadQueue = [], this._retryCount = new Map(), this._destroyed = false;
this._registry = registry;
}
}
export { GSplatAssetLoader };