60 lines
1.9 KiB
TypeScript
60 lines
1.9 KiB
TypeScript
import type { LoadPinballOptions, PinballInstance } from './types.js';
|
|||
|
|
|
||
|
|
export type { LoadPinballOptions, PinballInstance } from './types.js';
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Instantiates the WebAssembly build of Visual Pinball against the given
|
||
|
|
* canvas.
|
||
|
|
*
|
||
|
|
* NOTE (current milestone): this wrapper boots the Emscripten module and
|
||
|
|
* exposes lifecycle control (start/stop/dispose). Runtime table loading
|
||
|
|
* (`loadTable`) mounts the given bytes into the module's virtual filesystem,
|
||
|
|
* but wiring the native engine to actually pick up a runtime-loaded table
|
||
|
|
* (as opposed to the table baked in at build time) is tracked as a follow-up
|
||
|
|
* milestone in the README's roadmap - see "Browser file-loading UX".
|
||
|
|
*/
|
||
|
|
export async function loadPinball(options: LoadPinballOptions): Promise<PinballInstance> {
|
||
|
|
const baseUrl = options.baseUrl ?? '.';
|
||
|
|
|
||
|
|
// dist/vpinball.js is built with -sMODULARIZE=1 -sEXPORT_NAME=VPinballModule,
|
||
|
|
// so importing it yields a factory function, not a module with side effects.
|
||
|
|
const factory = (await import(/* @vite-ignore */ `${baseUrl}/vpinball.js`)).default as (
|
||
|
|
moduleArgs: Record<string, unknown>
|
||
|
|
) => Promise<EmscriptenModule>;
|
||
|
|
|
||
|
|
const module = await factory({
|
||
|
|
canvas: options.canvas,
|
||
|
|
locateFile: (path: string) => `${baseUrl}/${path}`,
|
||
|
|
});
|
||
|
|
|
||
|
|
if (options.tableData) {
|
||
|
|
mountTable(module, options.tableData);
|
||
|
|
}
|
||
|
|
|
||
|
|
return {
|
||
|
|
loadTable(vpxBytes: ArrayBuffer) {
|
||
|
|
mountTable(module, vpxBytes);
|
||
|
|
},
|
||
|
|
start() {
|
||
|
|
module.ccall?.('vpinball_wasm_start', null, [], []);
|
||
|
|
},
|
||
|
|
stop() {
|
||
|
|
module.ccall?.('vpinball_wasm_stop', null, [], []);
|
||
|
|
},
|
||
|
|
dispose() {
|
||
|
|
module.ccall?.('vpinball_wasm_dispose', null, [], []);
|
||
|
|
},
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
function mountTable(module: EmscriptenModule, vpxBytes: ArrayBuffer): void {
|
||
|
|
module.FS.writeFile('/table.vpx', new Uint8Array(vpxBytes));
|
||
|
|
}
|
||
|
|
|
||
|
|
interface EmscriptenModule {
|
||
|
|
FS: {
|
||
|
|
writeFile(path: string, data: Uint8Array): void;
|
||
|
|
};
|
||
|
|
ccall?: (name: string, returnType: string | null, argTypes: string[], args: unknown[]) => unknown;
|
||
|
|
}
|