UNPKG

playcanvas

Version:

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

124 lines (123 loc) 3.09 kB
const cachedResult = (func) => { const uninitToken = {}; let result = uninitToken; return () => { if (result === uninitToken) { result = func(); } return result; }; }; class Impl { static modules = {}; // returns true if the running host supports wasm modules (all browsers except IE) static wasmSupported = cachedResult(() => { try { if (typeof WebAssembly === "object" && typeof WebAssembly.instantiate === "function") { const module = new WebAssembly.Module(Uint8Array.of(0, 97, 115, 109, 1, 0, 0, 0)); if (module instanceof WebAssembly.Module) { return new WebAssembly.Instance(module) instanceof WebAssembly.Instance; } } } catch (e) { } return false; }); // load a script static loadScript(url, callback) { const s = document.createElement("script"); s.setAttribute("src", url); s.onload = () => { callback(null); }; s.onerror = () => { callback(`Failed to load script='${url}'`); }; document.body.appendChild(s); } // load a wasm module static loadWasm(moduleName, config, callback) { const loadUrl = Impl.wasmSupported() && config.glueUrl && config.wasmUrl ? config.glueUrl : config.fallbackUrl; if (loadUrl) { Impl.loadScript(loadUrl, (err) => { if (err) { callback(err, null); } else { const module = window[moduleName]; window[moduleName] = void 0; module({ locateFile: () => config.wasmUrl, onAbort: () => { callback("wasm module aborted."); } }).then((instance) => { callback(null, instance); }); } }); } else { callback("No supported wasm modules found.", null); } } // get state object for the named module static getModule(name) { if (!Impl.modules.hasOwnProperty(name)) { Impl.modules[name] = { config: null, initializing: false, instance: null, callbacks: [] }; } return Impl.modules[name]; } static initialize(moduleName, module) { if (module.initializing) { return; } const config = module.config; if (config.glueUrl || config.wasmUrl || config.fallbackUrl) { module.initializing = true; Impl.loadWasm(moduleName, config, (err, instance) => { if (err) { if (config.errorHandler) { config.errorHandler(err); } else { console.error(`failed to initialize module=${moduleName} error=${err}`); } } else { module.instance = instance; module.callbacks.forEach((callback) => { callback(instance); }); } }); } } } class WasmModule { static setConfig(moduleName, config) { const module = Impl.getModule(moduleName); module.config = config; if (module.callbacks.length > 0) { Impl.initialize(moduleName, module); } } static getConfig(moduleName) { return Impl.modules?.[moduleName]?.config; } static getInstance(moduleName, callback) { const module = Impl.getModule(moduleName); if (module.instance) { callback(module.instance); } else { module.callbacks.push(callback); if (module.config) { Impl.initialize(moduleName, module); } } } } export { WasmModule };