From 850fe0f07106a91bffaa2bb6b27ae9ea6a175453 Mon Sep 17 00:00:00 2001 From: Pabloader Date: Thu, 21 May 2026 14:34:39 +0000 Subject: [PATCH] Refactor wasm plugin --- .clangd | 30 +++++- .gitignore | 4 + build/assets/include/js.h | 4 + build/plugins/wasmPlugin.ts | 168 +++++++++++++++++---------------- build/plugins/wasmTypes.ts | 149 +++++++++++++++++++++++++++++ build/wasm.d.ts | 32 +++++++ compile_flags.txt | 12 +-- src/common/physics/engine.c | 30 +++--- src/games/life/life.c | 3 +- src/games/playground/awoo.cpp | 14 ++- src/games/playground/index.tsx | 3 +- src/types.d.ts | 29 ------ 12 files changed, 335 insertions(+), 143 deletions(-) create mode 100644 build/plugins/wasmTypes.ts create mode 100644 build/wasm.d.ts diff --git a/.clangd b/.clangd index 341a5c4..3b730aa 100644 --- a/.clangd +++ b/.clangd @@ -1,5 +1,31 @@ +CompileFlags: + Add: + - --target=wasm32-wasip1 + - -D_GNU_SOURCE + - -fno-exceptions + - -fno-stack-protector + - -fvisibility=hidden + - -mbulk-memory + - -mextended-const + - -mrelaxed-simd + - -msimd128 + - -mtail-call + - -msign-ext + - -mnontrapping-fptoint + - -mreference-types + - -Wall + - -Wextra + - -Wpedantic + - -Wshadow + - -Wconversion + - -Werror +--- If: PathMatch: .*\.[ch] - CompileFlags: - Add: [-std=c23] \ No newline at end of file + Add: [-std=gnu23] +--- +If: + PathMatch: .*\.(cpp|cc|cxx|hpp|hxx) +CompileFlags: + Add: [-std=gnu++26, -fno-rtti] diff --git a/.gitignore b/.gitignore index 3e6b333..19027c6 100644 --- a/.gitignore +++ b/.gitignore @@ -175,3 +175,7 @@ dist .DS_Store error.log package-lock.json + +# Generated by wasmPlugin +*.c.d.ts +*.cpp.d.ts diff --git a/build/assets/include/js.h b/build/assets/include/js.h index 078e712..ce2bb33 100644 --- a/build/assets/include/js.h +++ b/build/assets/include/js.h @@ -2,4 +2,8 @@ #define JS_IMPORT(name) __attribute__((import_module("env"), import_name(#name))) #define JS_EXPORT_AS(name) __attribute__((export_name(#name))) +#ifdef __cplusplus #define JS_EXPORT extern "C" __attribute__((visibility("default"))) +#else +#define JS_EXPORT __attribute__((visibility("default"))) +#endif diff --git a/build/plugins/wasmPlugin.ts b/build/plugins/wasmPlugin.ts index 6b45d8a..89ceb85 100644 --- a/build/plugins/wasmPlugin.ts +++ b/build/plugins/wasmPlugin.ts @@ -1,6 +1,7 @@ import { plugin, $, type BunPlugin } from "bun"; import path from 'path'; import fs from 'fs/promises'; +import { renderDts } from './wasmTypes'; interface WasmLoaderConfig { production?: boolean; @@ -10,6 +11,8 @@ interface WasmLoaderConfig { interface CompilerWithFlags { cc: string; nm: string; + wasmOpt: string | null; + reactorCrt: string | null; flags: string[]; } @@ -26,53 +29,61 @@ let compilerPromise: Promise | null = null; const getCompiler = (): Promise => { if (compilerPromise) return compilerPromise; compilerPromise = (async (): Promise => { - const wasiDir = path.resolve(import.meta.dir, '..', '..', 'dist', 'wasi'); - const cc: CompilerWithFlags = { - cc: 'clang', - nm: 'nm', - flags: [ - '--target=wasm32', - '--no-standard-libraries', - '-fno-builtin', - ], - }; + const wasiDir = path.resolve(import.meta.dir, '..', '..', 'dist', 'wasi'); + const cc: CompilerWithFlags = { + cc: 'clang', + nm: 'nm', + wasmOpt: Bun.which('wasm-opt') ?? null, + reactorCrt: null, + flags: [ + '--target=wasm32', + '--no-standard-libraries', + '-fno-builtin', + ], + }; - await fs.mkdir(wasiDir, { recursive: true }); + await fs.mkdir(wasiDir, { recursive: true }); - const installedVersion = (await Bun.file(path.resolve(wasiDir, 'VERSION')).text().catch(() => '')).slice(0, WASI_VERSION.length); + const installedVersion = (await Bun.file(path.resolve(wasiDir, 'VERSION')).text().catch(() => '')).slice(0, WASI_VERSION.length); - if (installedVersion !== WASI_VERSION) { - console.log(`WASI version mismatch. Downloading WASI SDK ${wasiArchiveURL}...`) - const response = await fetch(wasiArchiveURL); + if (installedVersion !== WASI_VERSION) { + console.log(`WASI version mismatch. Downloading WASI SDK ${wasiArchiveURL}...`) + const response = await fetch(wasiArchiveURL); - if (!response.ok) { - return cc; + if (!response.ok) { + return cc; + } + + const bytes = await response.bytes(); + + console.log(`Extracting WASI SDK...`); + await $`tar -xzv -C ${wasiDir} --strip-components=1 < ${bytes}`; + + console.log(`Downloading libclang_rt.builtins-wasm32-wasi-${WASI_VERSION}...`); + const rtResponse = await fetch(rtURL); + + if (!rtResponse.ok) { + return cc; + } + + const rtBytes = await rtResponse.bytes(); + + console.log(`Extracting libclang_rt.builtins-wasm32-wasi-${WASI_VERSION}...`); + await $`tar -xzv -C ${wasiDir} --strip-components=1 < ${rtBytes}`; } - const bytes = await response.bytes(); + cc.cc = `${path.resolve(wasiDir, 'bin', 'clang')}`; + cc.nm = `${path.resolve(wasiDir, 'bin', 'nm')}`; + cc.flags = [ + '--target=wasm32-wasip1', + `--sysroot=${path.resolve(wasiDir, 'share', 'wasi-sysroot')}`, + ]; - console.log(`Extracting WASI SDK...`); - await $`tar -xzv -C ${wasiDir} --strip-components=1 < ${bytes}`; + const wasmOptInSdk = path.resolve(wasiDir, 'bin', 'wasm-opt'); + cc.wasmOpt = await fs.access(wasmOptInSdk).then(() => wasmOptInSdk).catch(() => Bun.which('wasm-opt') ?? null); - console.log(`Downloading libclang_rt.builtins-wasm32-wasi-${WASI_VERSION}...`); - const rtResponse = await fetch(rtURL); - - if (!rtResponse.ok) { - return cc; - } - - const rtBytes = await rtResponse.bytes(); - - console.log(`Extracting libclang_rt.builtins-wasm32-wasi-${WASI_VERSION}...`); - await $`tar -xzv -C ${wasiDir} --strip-components=1 < ${rtBytes}`; - } - - cc.cc = `${path.resolve(wasiDir, 'bin', 'clang')}`; - cc.nm = `${path.resolve(wasiDir, 'bin', 'nm')}`; - cc.flags = [ - '--target=wasm32-wasip1', - `--sysroot=${path.resolve(wasiDir, 'share', 'wasi-sysroot')}`, - ]; + const reactorCrt = path.resolve(wasiDir, 'share', 'wasi-sysroot', 'lib', 'wasm32-wasip1', 'crt1-reactor.o'); + cc.reactorCrt = await fs.access(reactorCrt).then(() => reactorCrt).catch(() => null); return cc; })(); @@ -103,16 +114,13 @@ async function compileLibGroup( flags: string[], sources: string[], std: string[], - output: string, -): Promise { - if (sources.length === 0) return; + objDir: string, +): Promise { + if (sources.length === 0) return []; - // Per-file object dir derived from output name (dist/lib.c.o -> dist/lib.c/) - const objDir = output.replace(/\.o$/, ''); await fs.mkdir(objDir, { recursive: true }); const objPaths = sources.map(src => path.resolve(objDir, path.basename(src) + '.o')); - // Compile only changed files, in parallel const compilationFlags = [...flags, ...std]; await Promise.all(sources.map(async (src, i) => { if (await needsRebuild(objPaths[i], [src], compilationFlags)) { @@ -122,10 +130,7 @@ async function compileLibGroup( } })); - // Partial link if any object is newer than combined output - if (!(await needsRebuild(output, objPaths))) return; - const partialResult = await $`${cc.cc} -r -o ${output} ${objPaths}`; - if (partialResult.exitCode !== 0) throw new Error(`Partial link failed for ${output}`); + return objPaths; } async function instantiate(url: string) { @@ -134,7 +139,7 @@ async function instantiate(url: string) { i32: 0x7f, i64: 0x7e, f32: 0x7d, - f64: 0x7c + f64: 0x7c, }; type tc = keyof typeof typeCodes; @@ -211,26 +216,34 @@ async function instantiate(url: string) { lines.forEach(l => console.error(`[wasm] ${l}`)); } } - return 0; }, clock_time_get: (_id: number, _precision: bigint, timePtr: number) => { const now = Date.now(); const nanosecondNow = BigInt(now) * 1_000_000n; const data = new DataView(memory.buffer); data.setBigInt64(timePtr, nanosecondNow, true); - return 0; - } + }, }, { get(target, p) { if (p in target) { - console.debug(`[${String(p)}] exists`); - return target[p as keyof typeof target]; + return (...args: any[]) => { + const fn = target[p as keyof typeof target] as Function; + const result = fn(...args) ?? 0; + console.debug(`${String(p)}(${args.join(', ')}) = ${result}`); + + return result; + } + } + return (...args: any[]) => { + console.warn(`${String(p)}(${args.join(', ')}) is undefined`); + return 0; } - return (...args: any[]) => { console.warn(`[${String(p)}]`, args); return 0; } }, }), }); + (instance.exports._initialize as (() => void) | undefined)?.(); + return { ...Object.fromEntries( Object.entries(instance.exports) @@ -274,16 +287,14 @@ const wasmPlugin = ({ production }: WasmLoaderConfig = {}): BunPlugin => { 'sign-ext', 'nontrapping-fptoint', 'reference-types', - 'multivalue', ].map(f => `-m${f}`); const flags = [ ...cc.flags, - production ? '-O3' : '-O0', + production ? '-Os' : '-O0', '-flto', '-fno-exceptions', '-fno-stack-protector', - '-ffast-math', '-ffunction-sections', '-fdata-sections', '-Wall', @@ -297,14 +308,11 @@ const wasmPlugin = ({ production }: WasmLoaderConfig = {}): BunPlugin => { '-I', include, ]; - // Lib flags without -flto so clang -r (partial link) works on regular wasm objects - const libFlags = flags.filter(f => f !== '-flto'); - const std = args.path.endsWith('.cpp') ? STD_CPP : STD_C; const inputObjPath = path.resolve(distDir, inputBasename + '.o'); - const libCObjPath = path.resolve(distDir, 'lib.c.o'); - const libCppObjPath = path.resolve(distDir, 'lib.cpp.o'); + const libCObjDir = path.resolve(distDir, 'lib.c'); + const libCppObjDir = path.resolve(distDir, 'lib.cpp'); const libCGlob = new Bun.Glob(`${buildAssets}/lib/**/*.c`); const libCppGlob = new Bun.Glob(`${buildAssets}/lib/**/*.cpp`); @@ -313,9 +321,7 @@ const wasmPlugin = ({ production }: WasmLoaderConfig = {}): BunPlugin => { Array.fromAsync(libCppGlob.scan()), ]); - // Compile all three units in parallel - await Promise.all([ - // 1. Input file -> dist/{filename}.o + const [, libCObjs, libCppObjs] = await Promise.all([ (async () => { const compilationFlags = [...flags, ...std]; if (!await needsRebuild(inputObjPath, [args.path], compilationFlags)) return; @@ -323,19 +329,11 @@ const wasmPlugin = ({ production }: WasmLoaderConfig = {}): BunPlugin => { if (result.exitCode !== 0) throw new Error('Compile failed, check output'); await saveFlags(inputObjPath, compilationFlags); })(), - // 2. lib/**/*.c -> dist/lib.c.o - compileLibGroup(cc, libFlags, libCFiles, STD_C, libCObjPath), - // 3. lib/**/*.cpp -> dist/lib.cpp.o - compileLibGroup(cc, libFlags, libCppFiles, STD_CPP, libCppObjPath), + compileLibGroup(cc, flags, libCFiles, STD_C, libCObjDir), + compileLibGroup(cc, flags, libCppFiles, STD_CPP, libCppObjDir), ]); - // 4. Link if any input object is newer than the wasm output - const libObjs = [ - libCFiles.length > 0 ? libCObjPath : null, - libCppFiles.length > 0 ? libCppObjPath : null, - ].filter((x): x is string => x !== null); - - const allObjs = [inputObjPath, ...libObjs]; + const allObjs = [inputObjPath, ...libCObjs, ...libCppObjs]; if (await needsRebuild(wasmPath, allObjs)) { const symbolsResult = await $`${cc.nm} ${inputObjPath}`.quiet(); @@ -356,14 +354,24 @@ const wasmPlugin = ({ production }: WasmLoaderConfig = {}): BunPlugin => { '--no-entry', '--import-memory', '--export-table', - ...exports.flatMap(e => ['--export', e]), + '--growable-table', + ...exports.flatMap(e => ['--export-if-defined', e]), ].map(f => `-Wl,${f}`); - const linkResult = await $`${cc.cc} ${flags} ${linkFlags} -o ${wasmPath} -lstdc++ -nostartfiles ${allObjs}`; + const reactorInputs = cc.reactorCrt ? [cc.reactorCrt] : []; + const linkResult = await $`${cc.cc} ${flags} ${linkFlags} -o ${wasmPath} -lstdc++ -nostartfiles ${reactorInputs} ${allObjs}`; if (linkResult.exitCode !== 0) { throw new Error('Link failed, check output'); } + + if (production && cc.wasmOpt) { + const optResult = await $`${cc.wasmOpt} -Os --converge -o ${wasmPath} ${wasmPath}`; + if (optResult.exitCode !== 0) throw new Error('wasm-opt failed, check output'); + } + + const wasmBytes = new Uint8Array(await Bun.file(wasmPath).arrayBuffer()); + await Bun.write(`${args.path}.d.ts`, renderDts(wasmBytes)); } } diff --git a/build/plugins/wasmTypes.ts b/build/plugins/wasmTypes.ts new file mode 100644 index 0000000..be28163 --- /dev/null +++ b/build/plugins/wasmTypes.ts @@ -0,0 +1,149 @@ +// Parses a wasm binary's type / function / import / export sections to recover +// each function export's signature, then renders TypeScript declarations. + +type Sig = { params: number[]; results: number[] }; + +const VALUE_TYPE_TS: Record = { + 0x7f: 'number', // i32 + 0x7e: 'bigint', // i64 + 0x7d: 'number', // f32 + 0x7c: 'number', // f64 +}; + +function readULEB128(bytes: Uint8Array, offset: number): [number, number] { + let result = 0; + let shift = 0; + let i = 0; + while (true) { + const b = bytes[offset + i]; + result |= (b & 0x7f) << shift; + i++; + if ((b & 0x80) === 0) break; + shift += 7; + } + return [result, i]; +} + +function skipLimits(bytes: Uint8Array, offset: number): number { + const flags = bytes[offset]; + let o = offset + 1; + const [, l1] = readULEB128(bytes, o); o += l1; + if (flags & 1) { + const [, l2] = readULEB128(bytes, o); o += l2; + } + return o; +} + +export function parseWasmExports(bytes: Uint8Array): Map { + if (bytes[0] !== 0x00 || bytes[1] !== 0x61 || bytes[2] !== 0x73 || bytes[3] !== 0x6d) { + throw new Error('Invalid wasm magic'); + } + let offset = 8; + + const types: Sig[] = []; + const funcTypes: number[] = []; // defined function index → type index + const importedFuncTypes: number[] = []; // imported function index → type index + const exportEntries: { name: string; kind: number; index: number }[] = []; + const decoder = new TextDecoder(); + + while (offset < bytes.length) { + const sectionId = bytes[offset++]; + const [sectionSize, s1] = readULEB128(bytes, offset); + offset += s1; + const sectionEnd = offset + sectionSize; + + if (sectionId === 1) { + const [count, c1] = readULEB128(bytes, offset); offset += c1; + for (let i = 0; i < count; i++) { + if (bytes[offset++] !== 0x60) throw new Error('Expected functype 0x60'); + const [pc, p1] = readULEB128(bytes, offset); offset += p1; + const params: number[] = []; + for (let j = 0; j < pc; j++) params.push(bytes[offset++]); + const [rc, r1] = readULEB128(bytes, offset); offset += r1; + const results: number[] = []; + for (let j = 0; j < rc; j++) results.push(bytes[offset++]); + types.push({ params, results }); + } + } else if (sectionId === 2) { + const [count, c1] = readULEB128(bytes, offset); offset += c1; + for (let i = 0; i < count; i++) { + const [modLen, m1] = readULEB128(bytes, offset); offset += m1 + modLen; + const [fldLen, f1] = readULEB128(bytes, offset); offset += f1 + fldLen; + const kind = bytes[offset++]; + if (kind === 0x00) { + const [typeIdx, t1] = readULEB128(bytes, offset); offset += t1; + importedFuncTypes.push(typeIdx); + } else if (kind === 0x01) { + offset++; // elem type + offset = skipLimits(bytes, offset); + } else if (kind === 0x02) { + offset = skipLimits(bytes, offset); + } else if (kind === 0x03) { + offset += 2; // valtype + mutability + } + } + } else if (sectionId === 3) { + const [count, c1] = readULEB128(bytes, offset); offset += c1; + for (let i = 0; i < count; i++) { + const [typeIdx, t1] = readULEB128(bytes, offset); offset += t1; + funcTypes.push(typeIdx); + } + } else if (sectionId === 7) { + const [count, c1] = readULEB128(bytes, offset); offset += c1; + for (let i = 0; i < count; i++) { + const [nameLen, n1] = readULEB128(bytes, offset); offset += n1; + const name = decoder.decode(bytes.subarray(offset, offset + nameLen)); + offset += nameLen; + const kind = bytes[offset++]; + const [index, i1] = readULEB128(bytes, offset); offset += i1; + exportEntries.push({ name, kind, index }); + } + } + + offset = sectionEnd; + } + + const result = new Map(); + for (const { name, kind, index } of exportEntries) { + if (kind !== 0x00) continue; + const typeIdx = index < importedFuncTypes.length + ? importedFuncTypes[index] + : funcTypes[index - importedFuncTypes.length]; + result.set(name, types[typeIdx]); + } + return result; +} + +function tsType(valType: number): string { + return VALUE_TYPE_TS[valType] ?? 'unknown'; +} + +function tsSignature({ params, results }: Sig): string { + const paramList = params + .map((t, i) => `a${i}: ${tsType(t)}`) + .join(', '); + let ret: string; + if (results.length === 0) ret = 'void'; + else if (results.length === 1) ret = tsType(results[0]); + else ret = `[${results.map(tsType).join(', ')}]`; + return `(${paramList}) => ${ret}`; +} + +export function renderDts(wasmBytes: Uint8Array): string { + const sigs = parseWasmExports(wasmBytes); + const fns = Array.from(sigs.entries()) + .filter(([name]) => !name.startsWith('_')) + .sort(([a], [b]) => a.localeCompare(b)); + + return [ + '// Auto-generated by wasmPlugin. Do not edit.', + 'declare const _: {', + ...fns.map(([name, sig]) => ` ${name}: ${tsSignature(sig)};`), + ' memory: WebAssembly.Memory;', + ' table: WebAssembly.Table;', + ' readonly data: DataView;', + '};', + 'export default _;', + '', + ].join('\n'); +} diff --git a/build/wasm.d.ts b/build/wasm.d.ts new file mode 100644 index 0000000..2cef2c1 --- /dev/null +++ b/build/wasm.d.ts @@ -0,0 +1,32 @@ +// Fallback type for .c/.cpp imports until the wasmPlugin generates a per-file .d.ts. +// After a build, a sibling `${file}.d.ts` with concrete export names takes precedence. + +declare module '*.cpp' { + const _: { + memory: WebAssembly.Memory; + table: WebAssembly.Table; + readonly data: DataView; + [fn: string]: unknown; + }; + export default _; +} + +declare module '*.c' { + const _: { + memory: WebAssembly.Memory; + table: WebAssembly.Table; + readonly data: DataView; + [fn: string]: unknown; + }; + export default _; +} + +declare module '*.wasm' { + const _: { + memory: WebAssembly.Memory; + table?: WebAssembly.Table; + data: DataView; + [fn: string]: unknown; + }; + export default _; +} \ No newline at end of file diff --git a/compile_flags.txt b/compile_flags.txt index f1fcefe..93766aa 100644 --- a/compile_flags.txt +++ b/compile_flags.txt @@ -1,12 +1,2 @@ ---target=wasm32-wasip1 --sysroot=dist/wasi/share/wasi-sysroot --std=gnu++26 --fno-exceptions --I -build/assets/include --Wall --Wextra --Wpedantic --Wshadow --Wconversion --Werror \ No newline at end of file +-Ibuild/assets/include diff --git a/src/common/physics/engine.c b/src/common/physics/engine.c index 6c21a6a..0961d70 100644 --- a/src/common/physics/engine.c +++ b/src/common/physics/engine.c @@ -10,6 +10,8 @@ #define TYPE_CIRCLE 1 #define TYPE_PLANE 2 +#define rb_get(idx) (rigid_bodies + (idx)) + ////////// Types typedef struct rigid_body_t { @@ -50,12 +52,12 @@ static rigid_body_collision_callback_t rigid_body_collision_callback = NULL; ////////// Functions JS_EXPORT rigid_body* rigid_body_get(rigid_body_index idx) { - return (rigid_bodies + (idx)); + return rb_get(idx); } size_t rigid_body_new(float x, float y, float vx, float vy, float mass) { rigid_body_index idx = rigid_body_find_empty(); - rigid_body* rb = rigid_body_get(idx); + rigid_body* rb = rb_get(idx); rb->type = TYPE_EMPTY; rb->pos.x = x; @@ -74,7 +76,7 @@ size_t rigid_body_new(float x, float y, float vx, float vy, float mass) { JS_EXPORT rigid_body_index rigid_body_new_circle(float x, float y, float vx, float vy, float mass, float radius) { rigid_body_index idx = rigid_body_new(x, y, vx, vy, mass); - rigid_body* rb = rigid_body_get(idx); + rigid_body* rb = rb_get(idx); rb->type = TYPE_CIRCLE; rb->circle.radius = radius; @@ -84,7 +86,7 @@ JS_EXPORT rigid_body_index rigid_body_new_circle(float x, float y, float vx, flo JS_EXPORT rigid_body_index rigid_body_new_plane(float x, float y, float nx, float ny) { rigid_body_index idx = rigid_body_new(x, y, 0, 0, INFINITY); - rigid_body* rb = rigid_body_get(idx); + rigid_body* rb = rb_get(idx); rb->type = TYPE_PLANE; rb->plane.normal = vec2_normalize((vec2){nx, ny}); @@ -93,12 +95,12 @@ JS_EXPORT rigid_body_index rigid_body_new_plane(float x, float y, float nx, floa } JS_EXPORT void rigid_body_free(rigid_body_index idx) { - memset(rigid_body_get(idx), 0, sizeof(rigid_body)); + memset(rb_get(idx), 0, sizeof(rigid_body)); } JS_EXPORT void rigid_body_update(rigid_body_index idx, float dt) { rigid_body_resolve_collision(idx); - rigid_body* rb = rigid_body_get(idx); + rigid_body* rb = rb_get(idx); if (!isinf(rb->mass)) { rb->vel.x += rb->force.x * dt / rb->mass; @@ -114,7 +116,7 @@ JS_EXPORT void rigid_body_update(rigid_body_index idx, float dt) { JS_EXPORT void rigid_body_update_all(float dt) { for (rigid_body_index idx = 0; idx < rigid_bodies_cap; idx++) { - rigid_body* current = rigid_body_get(idx); + rigid_body* current = rb_get(idx); if (current->type == TYPE_EMPTY) { continue; } @@ -123,14 +125,14 @@ JS_EXPORT void rigid_body_update_all(float dt) { } JS_EXPORT void rigid_body_add_force(rigid_body_index idx, float fx, float fy) { - rigid_body* rb = rigid_body_get(idx); + rigid_body* rb = rb_get(idx); rb->force.x += fx; rb->force.y += fy; } JS_EXPORT void rigid_body_add_global_force(float fx, float fy) { for (rigid_body_index idx = 0; idx < rigid_bodies_cap; idx++) { - rigid_body* current = rigid_body_get(idx); + rigid_body* current = rb_get(idx); if (current->type == TYPE_EMPTY) { continue; } @@ -143,10 +145,10 @@ JS_EXPORT void rigid_body_set_collision_callback(rigid_body_collision_callback_t } void rigid_body_resolve_collision(rigid_body_index idx) { - rigid_body* rb = rigid_body_get(idx); + rigid_body* rb = rb_get(idx); int is_static = isinf(rb->mass); for (rigid_body_index i = idx + 1; i < rigid_bodies_cap; i++) { - rigid_body* current = rigid_body_get(i); + rigid_body* current = rb_get(i); if (!is_static || !isinf(current->mass)) { rigid_body_handle_collision(idx, i); } @@ -154,8 +156,8 @@ void rigid_body_resolve_collision(rigid_body_index idx) { } void rigid_body_handle_collision(rigid_body_index idx1, rigid_body_index idx2) { - rigid_body* rb1 = rigid_body_get(idx1); - rigid_body* rb2 = rigid_body_get(idx2); + rigid_body* rb1 = rb_get(idx1); + rigid_body* rb2 = rb_get(idx2); if (rb1->type == TYPE_CIRCLE && rb2->type == TYPE_CIRCLE) { vec2 d = vec2_sub(rb2->pos, rb1->pos); float distance = vec2_mag(d); @@ -236,7 +238,7 @@ float point_to_line_dist(vec2 p, vec2 line_point, vec2 normal) { rigid_body_index rigid_body_find_empty() { if (rigid_bodies) { for (rigid_body_index idx = 0; idx < rigid_bodies_cap; idx++) { - rigid_body* current = rigid_body_get(idx); + rigid_body* current = rb_get(idx); if (current->type == TYPE_EMPTY) { memset(current, 0, sizeof(rigid_body)); return idx; diff --git a/src/games/life/life.c b/src/games/life/life.c index f66bb6d..4acbd39 100644 --- a/src/games/life/life.c +++ b/src/games/life/life.c @@ -2,7 +2,6 @@ #include #include #include -#include #define WIDTH 512 #define HEIGHT 512 @@ -63,7 +62,7 @@ static int count_neighbours(int x, int y) { } GRAPHICS_INIT { - srand((uint32_t)time(NULL)); + srand(arc4random()); field = malloc(WIDTH * HEIGHT); next_field = malloc(WIDTH * HEIGHT); image_data = image_create(WIDTH, HEIGHT); diff --git a/src/games/playground/awoo.cpp b/src/games/playground/awoo.cpp index e5c5792..022d0cc 100644 --- a/src/games/playground/awoo.cpp +++ b/src/games/playground/awoo.cpp @@ -1,8 +1,8 @@ #include -#include #include #include #include +#include #include #include @@ -75,7 +75,13 @@ constexpr bit bit::nor(const bit& a, const bit& b) { return result; } -JS_EXPORT uint64_t awoo() { +static struct InitProbe { + InitProbe() { + std::cout << "[ctor] _initialize ran" << std::endl; + } +} init_probe; + +JS_EXPORT void awoo() { bit a{1, "a"}; bit b{1, "b"}; @@ -83,5 +89,5 @@ JS_EXPORT uint64_t awoo() { std::cout << "sum = " << sum << "\ncarry = " << carry << std::endl; - return sum; -} \ No newline at end of file + std::cout << "rand = " << rand() << "\narc4 = " << arc4random() << std::endl; +} diff --git a/src/games/playground/index.tsx b/src/games/playground/index.tsx index f4cc306..4ae5147 100644 --- a/src/games/playground/index.tsx +++ b/src/games/playground/index.tsx @@ -1,5 +1,6 @@ import awoo from './awoo.cpp'; export default function main() { - console.log(awoo); + console.log(awoo) + awoo.awoo(); } \ No newline at end of file diff --git a/src/types.d.ts b/src/types.d.ts index c4cbb2d..2e21c9d 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -38,35 +38,6 @@ declare module "*.ogg" { const audio: HTMLAudioElement; export default audio; } -declare module "*.wasm" { - const instance: { - memory: WebAssembly.Memory; - data: DataView; - - [x: string]: (...args: any) => any; - }; - export default instance; -} -declare module "*.c" { - const instance: { - memory: WebAssembly.Memory; - table: WebAssembly.Table; - data: DataView; - - [x: string]: (...args: any) => any; - }; - export default instance; -} -declare module "*.cpp" { - const instance: { - memory: WebAssembly.Memory; - table: WebAssembly.Table; - data: DataView; - - [x: string]: (...args: any) => any; - }; - export default instance; -} declare module "*.glsl" { const content: string; export default content;