mdx-m3-viewer
Version:
A browser WebGL model viewer. Mainly focused on models of the games Warcraft 3 and Starcraft 2.
113 lines (95 loc) • 2.94 kB
text/typescript
import { EventEmitter } from 'events';
import ModelViewer from './viewer';
/**
* The data sent to every resource as a part of the loading process.
*/
export type ResourceData = { viewer: ModelViewer, extension?: string, fetchUrl?: string };
/**
* A viewer resource.
*
* Generally speaking resources are created via viewer.load(), or viewer.loadGeneric().
*/
export abstract class Resource extends EventEmitter {
viewer: ModelViewer;
extension: string;
fetchUrl: string;
ok: boolean = false;
loaded: boolean = false;
constructor(resourceData: ResourceData) {
super();
this.viewer = resourceData.viewer;
this.extension = resourceData.extension || '';
this.fetchUrl = resourceData.fetchUrl || '';
// Ignore EventEmitter warnings.
// Mostly relevant when loading many models that reference the same texture / event object.
this.setMaxListeners(0);
}
/**
* Called when the data for this resource is ready.
*
* If a promise is returned, the resource waits for it to resolve before finalizing.
*/
abstract load(src?: any): void;
/**
* Will be called when the data for this resource is ready.
*
* If it was loaded from memory, it will be called instantly.
*
* Otherwise it will be called when the server fetch finishes, assuming it succeeded.
*/
loadData(src?: any) {
try {
this.load(src);
this.loaded = true;
this.ok = true;
this.lateLoad();
this.emit('load', this);
this.emit('loadend', this);
} catch (e) {
this.error('An exception was thrown while loading', e);
}
}
/**
* Remove this resource from its viewer's cache.
*
* Equivalent to viewer.unload(resource).
*/
detach() {
return this.viewer.unload(this);
}
/**
* This is used by models to finalize instances of them that were created before they finished loading.
*/
lateLoad() {
}
/**
* Called when an error happens while loading the resource.
*/
error(error: string, reason: any) {
this.loaded = true;
this.ok = false;
this.emit('error', this, error, reason);
this.emit('loadend', this);
}
/**
* Wait for this resource to load.
*
* Similar to attaching an event listener to the 'loadend' event, but handles the case where the resource already loaded, and code should still run.
*
* If a callback is given, it will be called, otherwise a promise is returned.
*/
whenLoaded(callback?: (resource: Resource) => void) {
let promise = new Promise((resolve: (resource: Resource) => void) => {
if (this.loaded) {
resolve(this);
} else {
this.once('loadend', () => resolve(this));
}
});
if (callback) {
promise.then(() => callback(this));
} else {
return promise;
}
}
}